更新 JTable 单元格的 ImageIcon

发布于 2024-10-13 04:54:24 字数 2155 浏览 7 评论 0原文

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

然而,我对我要重写的所有不同方法感到不知所措,并且正在旋转我的轮子试图找出如何修改特定单元格的 ImageIcon。 单元格必须包含 JLabel,因为它需要 ImageIcon 以及文本字符串。我已经可以设置初始 ImageIcon (尽管我可能做得不正确),但我无法设置更新的 ImageIcon。没有失败,但也没有做出任何改变。

一般来说,假设所有这些模型、编辑器和渲染器已经被实例化了吗?

如果您想知道的话,我的模型已经定义为返回这些单元格的 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

I am creating my first JTable that requires me to create a custom AbstractTableModel, TableCellEditor, and DefaultTableCellRenderer. Given that I have not needed to create these before, I've made some significant progress in getting my table to behave as desired.

However, I am getting overwhelmed with all the different methods I am overriding, and am spinning my wheels trying to figure out how to modify the ImageIcon of a particular cell. The cell must contain a JLabel, as it needs both an ImageIcon as well as a text string. I can already set the initial ImageIcon (although I am probably doing it incorrectly), but I can't set an updated ImageIcon. Nothing fails, but no change is made.

In a general sense, what is the best way to get and set an icon to a JLabel cell of a JTable, assuming all of these models, editors, and renderers have already been instantiated?

My model has already been defined to return JLabel.class for these cells, if you're wondering, and I also do a fireTableCellUpdated(row, col) once the change has supposedly been made. If I do a System.out.println(getIcon()) before and after the update, I can even see the source has changed.

Here is some of the code (updated with URL/ImageIcon fix in place):

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

紧拥背影 2024-10-20 04:54:24

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

但根据渲染器中的代码,您期望这些单元格中包含 String 值:

setText((String)value); 

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

获取 JTable 的 JLabel 单元格并将其设置图标的最佳方法是什么,

您不应将 JLable 存储在 TableModel 中。在模型中存储 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;
    }
}

My model has already been defined to return JLabel.class for these cells,

But according to the code in your renderer you expect a String value in these cells:

setText((String)value); 

I don't like your setIcon() method. I would not pass in the URL. I would pass in the Icon. Maybe you have a problem that the icon has not been read into memory at the time the cell is rendered.

what is the best way to get and set an icon to a JLabel cell of a JTable,

You should not store a JLable in the TableModel. It is expensive to store Swing components in the model, that is why Swing components use renderers. Instead you store a custom Object like "LabelInfo" which contains two properties, the text and the Icon. Then your custom renderer will extend the default renderer and invoke super.getTableCellRendererComponent(). You can then access your object and rest the text/icon properties of the renderer. You should not be creating objects in the renderer.

Now when you want to change something in the model you can do:

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

Thats all you need. There is not custom code to repaint the cell or anything because that is already built intothe setValueAt(...) method. of your table model.

Edit: a simple example for using a custom Object in the TableModel.

1) to add the object to the model you do something like:

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

2) the code for your custom renderer would be:

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;
    }
}
掀纱窥君容 2024-10-20 04:54:24

从模型中调用 fireTableDataChanged。

也尝试从 JLabel 调用 repaint 方法。

更好的方法是实现一个 CellRenderer,返回一个 JPanel 并在 PaintComponent 中创建绘制方法。您可以加载 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 放在该列中,渲染器会处理其余的事情。

Call the fireTableDataChanged from your model.

Try call the repaint method from JLabel too.

The better way to do it, is implement a CellRenderer, with returns a JPanel and make the draw method in the paintComponent. You can load a BufferedImage instead of a ImageIcon and use it to draw in the JPanel.

Try change you Renderer to:

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)
  }

You are doing some mess, this is not the right way to work with the TableModel, you should return the URL for the image in the getValueAt(int row, int col), after it, register the CellRenderer to correspond to cells with URL.class. The renderer is automatically called from the JTable, you don't need to extends JTable either, you have only to implement the Renderer and the Model.
The setIconAt should only call the setValueAt and put your URL at the column, the renderer take care of the rest.

ˇ宁静的妩媚 2024-10-20 04:54:24

我通过将 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 造成潜在的性能影响。感谢大家的见解和帮助。这让我抓狂!

I fixed this by changing setIcon(imgGray) to if (getIcon() == null) setIcon(imgGray);.

The issue is my getTableCellRendererComponent method was setting the icon to imgGray every time. Apparently my setIconAt method, which calls getTableCellRendererComponent, was being overridden, even though the "new" icon value was processed after the "old" value was (re)set.

I ended up removing all my setIcon methods and moved the relevant logic into my StatusTableCellRenderer class. That way I pass the value of the cell and let the renderer do the icon setting based on that value. It makes more sense this way, and works beautifully. I have confirmed that initial setting and all subsequent updates are performing as expected.

The logic of setting the icon is pretty simple -- set the predefined icon based on certain predefined threshold values.

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());

I was very concerned about suggestions to make brand new objects to use, when the default JLabel was exactly what I needed. It was both unnecessary and a potential performance hit to the JTable. Thank you all for your insight and assistance. This was driving me batty!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文