问题
I have a JTable
:
after I swap columns unfortunately the flags are not rendered anymore:
I assume it is the fault of my getColumnClass
method where I have fixed class for every column, but I don't know how to fix this issue.
package zad1;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Arrays;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;
public class CountryTable extends JTable {
public CountryTable(String countriesFileName) {
Vector<String> columnNames = new Vector<String>();
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
try {
BufferedReader br = new BufferedReader(new FileReader(countriesFileName));
columnNames.addAll(Arrays.asList(br.readLine().split("\t")));
System.out.println(columnNames);
String line;
while ((line = br.readLine()) != null) {
String[] attributes = line.split("\t");
Vector<Object> rowData = new Vector<Object>();
rowData.add(attributes[0]);
rowData.add(attributes[1]);
rowData.add(Long.valueOf(attributes[2]));
BufferedImage icon = ImageIO.read(new File("./data/" + attributes[3]));
double ratio = (double) icon.getWidth() / icon.getHeight();
rowData.add(new ImageIcon(icon.getScaledInstance(30, 20, Image.SCALE_FAST)));
data.add(rowData);
}
br.close();
} catch (Exception e) {
e.printStackTrace();
}
setModel(new MyTableModel(data, columnNames));
setRowHeight(30);
getColumnModel().getColumn(2).setCellRenderer(new PopulationCellRenderer());
for (int i = 0; i < getColumnCount(); i++) {
getColumnModel().getColumn(i).setWidth(400);
}
}
@Override
public Class getColumnClass(int column) {
switch (column) {
case 0:
return String.class;// Panstwo
case 1:
return String.class;// stolica
case 2:
return Long.class;// ludnosc
case 3:
return Icon.class; // flaga jakiej klasy jest dana komorka w danej kolumnie aby tabela ja poprawnie wyswietlila
default:
return String.class;
}
}
class MyTableModel extends DefaultTableModel {
public MyTableModel(Vector<Vector<Object>> data, Vector<String> columnNames) {
super(data, columnNames);//wywolanie konstruktora z nadklasy
System.out.println(columnNames);
}
@Override
public boolean isCellEditable(int row, int column) {
return column == 3;
}
}
class PopulationCellRenderer extends JLabel implements TableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Long population = (Long) value;
setHorizontalAlignment(JLabel.RIGHT);
if (population > 20000000) {
setForeground(Color.red);
} else {
setForeground(Color.BLACK);
}
setText(population + "");
return this;
}
}
}
回答1:
There's no need to extend JTable
for this. Your example overrides getColumnClass()
in the view, when it should do so in the model. The default renderer for Icon.class
will be applied wherever the column is moved.
private final TableModel model = new DefaultTableModel(data, columnNames) {
@Override
public Class<?> getColumnClass(int column) {
switch (column) {
…
}
}
};
This will also make it possible to apply the PopulationCellRenderer
on a per-type basis:
table.setDefaultRenderer(Long.class, new PopulationRenderer());
Also consider extending DefaultTableCellRenderer
, as shown here, using a NumberFormat
, as shown below. Based on an example by @mKorbel, the self-contained code below shows a corrected TableModel
and updated TableCellRenderer
.
import java.awt.*;
import java.text.NumberFormat;
import javax.swing.*;
import javax.swing.table.*;
public class TableExample {
private static final long CUSP = 20000000;
private JFrame frame = new JFrame("Table Demo");
private Icon errorIcon = (Icon) UIManager.getIcon("OptionPane.errorIcon");
private Icon infoIcon = (Icon) UIManager.getIcon("OptionPane.informationIcon");
private Icon warnIcon = (Icon) UIManager.getIcon("OptionPane.warningIcon");
private String[] columnNames = {"String", "Long", "Float", "Double", "Boolean", "Icon"};
private Object[][] data = {
{"aaa", CUSP - 1, 12.15F, 100.05, true, (errorIcon)},
{"bbb", CUSP, 7.154F, 6.1555, false, (infoIcon)},
{"ccc", CUSP + 1, 0.1135F, 3.1455, true, (warnIcon)},
{"ddd", 42L, 31.15F, 10.05, true, (errorIcon)},
{"eee", 12345L, 5.154F, 16.1555, false, (infoIcon)},
{"fff", 54321L, 4.1135F, 31.1455, true, (warnIcon)}};
private final TableModel model = new DefaultTableModel(data, columnNames) {
@Override
public Class<?> getColumnClass(int column) {
switch (column) {
case 0:
return String.class;
case 1:
return Long.class;
case 2:
return Float.class;
case 3:
return Double.class;
case 4:
return Boolean.class;
case 5:
return Icon.class;
default:
return String.class;
}
}
};
private final JTable table = new JTable(model);
private static class PopulationRenderer extends DefaultTableCellRenderer {
NumberFormat f = NumberFormat.getInstance();
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int col) {
JLabel r = (JLabel) super.getTableCellRendererComponent(
table, value, isSelected, hasFocus, row, col);
if (col == 1) {
r.setHorizontalAlignment(JLabel.RIGHT);
Long population = (Long) value;
if (population > CUSP) {
r.setForeground(Color.red);
} else {
r.setForeground(Color.BLACK);
}
r.setText(f.format(population));
}
return r;
}
}
public TableExample() {
int h = infoIcon.getIconHeight();
table.setRowHeight(h);
table.setPreferredScrollableViewportSize(
new Dimension(table.getPreferredSize().width, 4 * h));
table.setAutoCreateRowSorter(true);
table.setDefaultRenderer(Long.class, new PopulationRenderer());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JScrollPane(table));
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
TableExample tableExample = new TableExample();
});
}
}
来源:https://stackoverflow.com/questions/32919867/how-to-make-jlabel-still-appear-after-jtable-column-swap-in-the-runtime