1

我正在创建我的第一个 JTable,它需要我创建一个自定义AbstractTableModelTableCellEditorDefaultTableCellRenderer. 鉴于我以前不需要创建这些,我在让我的表按预期运行方面取得了一些重大进展。

但是,我对我要覆盖的所有不同方法感到不知所措,并且正在转动我的轮子试图弄清楚如何修改特定单元格的 ImageIcon。 该单元格必须包含一个 JLabel,因为它既需要一个文本字符串,也需要 ImageIcon 一个文本字符串。我已经可以设置初始值ImageIcon(尽管我可能做错了),但我无法设置更新的ImageIcon. 没有失败,但没有改变。

一般来说,假设所有这些模型、编辑器和渲染器都已实例化,那么获取图标并将其设置为 a 的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
4

3 回答 3

3

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

但是根据渲染器中的代码,您希望这些单元格中有一个 String 值:

setText((String)value); 

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

获取图标并将其设置为 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;
    }
}
于 2011-01-19T21:22:15.437 回答
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 的单元格。班级。渲染器是从 JTable 中自动调用的,你也不需要扩展 JTable,你只需要实现 Renderer 和 Model。setIconAt 应该只调用 setValueAt 并将您的 URL 放在列中,渲染器负责其余的工作。

于 2011-01-19T20:16:27.217 回答
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. 感谢大家的洞察和帮助。这让我发疯!

于 2011-01-19T22:06:29.670 回答