2011-01-19 48 views
1

我正在创建我的第一个JTable,它需要我创建自定义AbstractTableModel,TableCellEditorDefaultTableCellRenderer。鉴于我之前不需要创建这些工具,我已经取得了一些重大进展,使我的表能够按照预期行事。更新JTable单元格的ImageIcon

但是,我不知所措地使用了所有不同的方法,而且我正在旋转我的轮子,试图弄清楚如何修改特定单元格的ImageIcon。 单元格必须包含JLabel,因为它需要ImageIcon以及文本字符串。我已经可以设置初始ImageIcon(虽然我可能做得不正确),但我无法设置更新的ImageIcon。没有任何失败,但没有改变。

从一般意义上说,假设所有这些模型,编辑器和渲染器都已经实例化,获取和设置图标到JTableJLabel单元格的最佳方法是什么?

我的模型已被定义为返回JLabel.class这些单元格,如果您想知道,并且我也会在做出更改后执行fireTableCellUpdated(row, col)。如果我在更新前后执行System.out.println(getIcon()),我甚至可以看到源已更改。

下面是一些代码(与地方URL/ImageIcon的修复更新)的

class MonitorTable extends JTable { 
    MonitorTableModel model = new MonitorTableModel(rows, columnNames); 
    setModel(model); 
    ... 
    public void setIconAt(ImageIcon icon, int row, int col) { 
     model.setIconAt(icon, row, col); 
    } // End setIconAt(ImageIcon, int, int) 
    ... 

    class MonitorTableModel extends AbstractTableModel { 
     ... 
     public void setIconAt(ImageIcon icon, int row, int col) { 
     StatusTableCellRenderer cell = 
      (StatusTableCellRenderer)getColumnModel().getColumn(col).getCellRenderer(). 
      getTableCellRendererComponent(myTableObject, null, false, false, row, col); 

     System.out.println(cell.getIcon()); // Shows initial icon source 
     cell.setIcon(icon); 
     fireTableCellUpdated(row, col);  // Should update the table 
     System.out.println(cell.getIcon()); // Shows new icon source 
     System.out.println("Cell updated"); 
     } // End setIconAt(ImageIcon, int, int) 
    } // End class MonitorTableModel 

    public class StatusTableCellRenderer extends DefaultTableCellRenderer { 
     public Component getTableCellRendererComponent(JTable table, Object value, 
     boolean isSelected, boolean hasFocus, int row, int col) { 

     setIcon(imgGray); 
     setText((String)value); 
     return this; 
     } // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int) 
    } // End class StatusTableCellRenderer 
} // End class MonitorTable 

回答

0

我改变setIcon(imgGray)固定这if (getIcon() == null) setIcon(imgGray);

问题是我的getTableCellRendererComponent方法是每次将图标设置为imgGray。很明显,我的setIconAt方法(即调用getTableCellRendererComponent)被覆盖,即使“新”图标值是在“旧”值被重新设置后处理的。

我最终删除了所有我的setIcon方法,并将相关逻辑转移到我的StatusTableCellRenderer类中。这样我传递单元格的值,并让渲染器根据该值执行图标设置。这样做更有意义,而且工作得很漂亮。我已确认初始设置和所有后续更新均按预期执行。

设置图标的逻辑非常简单 - 根据某些预定义的阈值设置预定义的图标。

double val; 
if (getIcon() == null) setIcon(imgGray);  // Initialize 
if ((value == null) || (value == "")) { 
    val = 0; 
} else { 
    val = Double.parseDouble(value.toString()); 
} // End if 

if (val <= THRESHOLD1) { 
    setIcon(icon1); 
} else if (val <= THRESHOLD2) { 
    setIcon(icon2); 
... 
} // End if 
setText(value.toString()); 

我很担心建议,让品牌新的对象来使用,当默认JLabel正是我所需要的东西。这对JTable来说既没有必要也没有潜在的性能影响。谢谢大家的意见和协助。这让我bat!不安!

0

调用fireTableDataChanged从你的模型。

尝试从JLabel调用repaint方法。

更好的方法是实现一个CellRenderer,并返回一个JPanel并在paintComponent中绘制draw方法。您可以加载BufferedImage而不是ImageIcon,并使用它来绘制JPanel。

尝试改变你渲染器:

public class StatusTableCellRenderer extends DefaultTableCellRenderer { 
    public Component getTableCellRendererComponent(JTable table, Object value, 
     boolean isSelected, boolean hasFocus, int row, int col) { 
     JLabel comp = new JLabel(new ImageIcon(imgGray)); 
     comp.setText((String)value); 
     return comp; 
    } // End getTableCellRendererComponent(JTable, Object, boolean, boolean, int, int) 
    } 

你正在做一些乱七八糟的,这是不是与TableModel来工作的正确途径,应返回的URL在getValueAt图像(INT行, int col),在它之后,注册CellRenderer以对应于带有URL.class的单​​元格。渲染器是从JTable自动调用的,您无需扩展JTable,只需实现渲染器和模型。 setIconAt应只调用setValueAt并将您的URL放在列中,渲染器负责其余部分。

+0

我已经触发`fireTableCellUpdated(row,col)`。我会更多地更新我的问题。 – 2011-01-19 20:17:44

+0

尝试重绘JLabel – 2011-01-19 20:20:35

+0

我试过了,没有改变。无论如何``fireTableCellUpdated(row,col)`应该照顾。难怪我以前从来没有搞错过JTables!哎呀! – 2011-01-19 20:23:10

3

我的模型已经被定义为返回JLabel.class这些细胞,

但是根据你的渲染,你在这些细胞中期待一个字符串值代码:

setText((String)value); 

我不喜欢你的setIcon()方法。我不会传入网址。我会通过图标。也许你有一个问题,即在渲染单元格时图标还没有被读入内存。

什么是获得和图标设置为一个JTable的一个JLabel细胞的最佳途径,

你不应该存储在TableModel一个JLable。将Swing组件存储在模型中很昂贵,这就是Swing组件使用渲染器的原因。而是存储一个自定义对象,如“LabelInfo”,其中包含两个属性,即文本和图标。然后,您的自定义渲染器将扩展默认渲染器并调用super.getTableCellRendererComponent()。然后,您可以访问您的对象并放置渲染器的文本/图标属性。你不应该在渲染器中创建对象。

现在,当你想改变模型的东西,你可以这样做:

LabelInfo info = (LabelInfo)table.getValueAt(row, column); 
info.setIcon(...); 
table.setValueAt(info, row, column); 

这就是你所需要的。没有自定义代码来重新绘制单元格或任何东西,因为它已经构建到setValueAt(...)方法中。你的表模型。

编辑:在TableModel中使用自定义对象的简单示例。

1)对象添加到模型中你这样做:

LabelInfo info = new LabelInfo("some Text", yourIcon); 
table.setValueAt(info, row, column); 

2)为您的自定义渲染器的代码如下:

class LabelInfoRenderer extends DefaultTableCellRenderer 
{ 
    @Override 
    public Component getTableCellRendererComponent(
     JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) 
    { 
     super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); 

     LableInfo info = (LabelInfo)value; 
     setIcon(info.getIcon()); 

     return this; 
    } 
}