我有一个 JTable,用于在不同行中显示多种不同的数据类型。只有两列,其中左列是变量名称,右列是与该变量关联的变量(因此使用 ColumnModel 不适合我的解决方案)。到目前为止,这对于基元来说非常有效,并且 JComboBox 和 JCheckBox 的 DefaultRenderer 也非常有效。
我现在正在尝试将 java.awt.Color 集成到表中,但我希望它能够渲染,以便单元格实际上填充有颜色,并且根本没有文本(我不认为这会很困难)当我到达那个点时)。到目前为止,我已经完成了单元的功能;单击单元格会弹出一个 JColorChooser 并返回颜色,然后将其应用于与该单元格关联的对象。我使用的代码是:
JTable table = new JTable(new CustomModel(columnNames, values))
{
//Other functions inside here are excluded to keep it concise
public void changeSelection(int row, int col, boolean toggle, boolean extend)
{
/*Row is a custom object I am using for each row in the table. Its purpose is to
hold more information about the rows than I would normally be able to. Suffice
to say for this example, it will be returning something with a Color in it*/
Row obj = ((CustomModel)(table.getModel())).getRow(row);
/*ObjectProperties is essentially a modified version of a hashmap that also
stores the objects type among other things*/
if(obj.getType() == ObjectProperties.TYPE.COLOR)
{
Color newColor = JColorChooser.showDialog(null, "Pick color", Color.RED);
if(newColor != null)
{
table.getModel().setValueAt(newColor, row, col);
}
}
super.changeSelection(row, col, toggle, extend);
}
}
所以这似乎工作得很好,但现在是渲染。我想如果我尝试设置一个 DefaultRenderer,它会起作用,所以我使用了这一行:
table.setDefaultRenderer(Color.class, new ColorRenderer());
我的ColorRenderer类如下:
public class ColorRenderer extends JLabel implements TableCellRenderer
{
public ColorRenderer()
{
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int col)
{
Color newColor = (Color)value;
setBackground(newColor);
return this;
}
}
但是,当我确实使用它时,我没有运气显示实际的颜色,而是得到了颜色的字符串表示形式(我认为这意味着我的渲染器根本无法工作)。因此,我仍然没有真正使其以正确的方式呈现,更不用说能够更改用户选择新内容时显示的颜色了。
我长期以来一直在努力让 CustomRenderer 正常工作,查看了我能得到的所有资源。我认为Oracle 的 JTable 部分 的教程相当有用,但最终并没有像我希望的那样工作。该论坛上的其他问题与我的情况很接近,但往往缺乏适用于特定对象类型(而不仅仅是特定单元格)的关键要素。如果我的表中存储了许多 Color 对象,我理想情况下希望它们都具有相同的行为方式。
如果我的实现中有明显错误或遗漏的地方,如果有人指出这一点那就太好了。仔细查看代码(在多次发布之前我已经重新阅读了此代码,以确保我已包含所有内容),我相信问题可能出在我的 Row 类中。它包含一个名为 getValue() 的方法,该方法将返回该对象,因此从技术上讲,我可以调用类似以下内容的方法:
if(rowObject.getValue() instanceof Color)
//Apply renderer
但是我如何使用为特定类设置默认渲染器的代码来做到这一点?
不知道这是否是最好的方法,但覆盖
getCellRenderer(int row, int col)
可能会帮助你:
public TableCellRenderer getCellRenderer(int row, int col) {
// Only care about the first column
if (col == 1) {
Row obj = ((CustomModel)(table.getModel())).getRow(row);
// Check to see if this is a color
if (obj.getType() == ObjectProperties.TYPE.COLOUR) {
return super.getDefaultRenderer(Color.class);
}
}
// Either this wasn't a color or it wasn't the first column, either way its super.getCellRenderer's problem now
return super.getCellRenderer(row, col);
}
getCellRenderer(int row, int col)
似乎只适用于列上的单元格渲染器,因此如果您只想以不同的方式渲染单个单元格,那就不太好了。
我见过的另一种选择是定义一个单元格渲染器,将其应用到列,并在单元格渲染器的
getTableCellRendererComponent(...)
函数中确定这是哪种数据类型以及是否渲染它或将其传递到另一个渲染器。
我个人更喜欢第一个选项,但如果您有大量不同的自定义单元类型要渲染,并且希望将所有渲染代码保留在一个类中,那么我可以看到第二个选项的吸引力。
您必须重写表模型中的方法
getColumnClass(int c)
(最好使用DefaultTableModel...)
class MyTableModel extends AbstractTableModel {
private String[] columnNames = ...//same as before...
private Object[][] data = ...//same as before...
//taken from http://docs.oracle.com/javase/tutorial/uiswing/components/table.html
public Object getValueAt(int row, int col) {
return data[row][col];
}
public Class getColumnClass(int c) {
//here - check that the proper class is returned!
return getValueAt(0, c).getClass();
}
}