更新JTable单元的ImageIcon

时间:2011-01-19 20:12:59

标签: java swing icons jtable abstracttablemodel

我正在创建我的第一个JTable,要求我创建自定义AbstractTableModelTableCellEditorDefaultTableCellRenderer。鉴于我以前不需要创建这些,我已经取得了一些重要进展,使我的表能够按照需要运行。

但是,我对我所覆盖的所有不同方法感到不知所措,并且正在试图弄清楚如何修改特定单元格的ImageIcon。 单元格必须包含JLabel,因为它需要 ImageIcon 以及文本字符串。我已经可以设置初始ImageIcon(虽然我可能做错了),但我无法设置更新的ImageIcon。什么都没有失败,但没有改变。

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

我的模型已被定义为返回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

3 个答案:

答案 0 :(得分:3)

  

我的模型已被定义为返回这些单元格的JLabel.class,

但根据渲染器中的代码,您希望在这些单元格中使用String值:

setText((String)value); 

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

  

获取和设置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;
    }
}

答案 1 :(得分: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的正确方法,你应该在getValueAt(int row,int col)中返回图像的URL,之后,注册CellRenderer以对应于单元格使用URL.class。从JTable自动调用渲染器,您也不需要扩展JTable,只需实现渲染器和模型。 setIconAt应该只调用setValueAt并将你的URL放在列中,渲染器会处理其余的事情。

答案 2 :(得分:0)

我通过将setIcon(imgGray)更改为if (getIcon() == null) setIcon(imgGray);来解决此问题。

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

我最终删除了所有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来说既不必要又有潜在的性能影响。谢谢大家的见解和帮助。这让我感到沮丧!