更新 JTable 单元格的 ImageIcon
我正在创建第一个 JTable,它要求我创建自定义 AbstractTableModel
、TableCellEditor
和 DefaultTableCellRenderer
。鉴于我以前不需要创建这些,我在让我的表按预期运行方面取得了一些重大进展。
然而,我对我要重写的所有不同方法感到不知所措,并且正在旋转我的轮子试图找出如何修改特定单元格的 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
但根据渲染器中的代码,您期望这些单元格中包含 String 值:
我不喜欢您的 setIcon() 方法。我不会传递 URL。我会传递图标。也许您遇到一个问题,即在渲染单元格时图标尚未读入内存。
您不应将 JLable 存储在 TableModel 中。在模型中存储 Swing 组件的成本很高,这就是 Swing 组件使用渲染器的原因。相反,您存储一个自定义对象,例如“LabelInfo”,它包含两个属性:文本和图标。然后,您的自定义渲染器将扩展默认渲染器并调用 super.getTableCellRendererComponent()。然后,您可以访问您的对象并保留渲染器的文本/图标属性。您不应该在渲染器中创建对象。
现在,当您想要更改模型中的某些内容时,您可以执行以下操作:
这就是您所需要的。没有自定义代码来重新绘制单元格或任何内容,因为它已经内置到 setValueAt(...) 方法中。您的表模型。
编辑:在 TableModel 中使用自定义对象的简单示例。
1) 要将对象添加到模型中,您可以执行以下操作:
2) 自定义渲染器的代码为:
But according to the code in your renderer you expect a String value in these cells:
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.
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:
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:
2) the code for your custom renderer would be:
从模型中调用 fireTableDataChanged。
也尝试从 JLabel 调用 repaint 方法。
更好的方法是实现一个 CellRenderer,返回一个 JPanel 并在 PaintComponent 中创建绘制方法。您可以加载 BufferedImage 而不是 ImageIcon,并使用它在 JPanel 中进行绘制。
尝试将渲染器更改为:
您正在做一些混乱,这不是使用 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:
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.
我通过将
setIcon(imgGray)
更改为if (getIcon() == null) setIcon(imgGray);
修复了此问题。问题是我的 getTableCellRendererComponent 方法每次都将图标设置为 imgGray。显然,我的
setIconAt
方法(调用 getTableCellRendererComponent)被覆盖,即使在(重新)设置“旧”值之后处理了“新”图标值。我最终删除了所有
setIcon
方法,并将相关逻辑移至我的StatusTableCellRenderer
类中。这样我就传递了单元格的值,并让渲染器根据该值进行图标设置。这种方式更有意义,而且效果也很好。我已确认初始设置和所有后续更新均按预期执行。设置图标的逻辑非常简单——根据某些预定义的阈值设置预定义的图标。
当默认的 JLabel 正是我所需要的时,我非常关心创建要使用的全新对象的建议。这不仅是不必要的,而且还会对
JTable
造成潜在的性能影响。感谢大家的见解和帮助。这让我抓狂!I fixed this by changing
setIcon(imgGray)
toif (getIcon() == null) setIcon(imgGray);
.The issue is my
getTableCellRendererComponent
method was setting the icon to imgGray every time. Apparently mysetIconAt
method, which callsgetTableCellRendererComponent
, 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 myStatusTableCellRenderer
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.
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 theJTable
. Thank you all for your insight and assistance. This was driving me batty!