我正在创建我的第一个JTable,要求我创建自定义AbstractTableModel
,TableCellEditor
和DefaultTableCellRenderer
。鉴于我以前不需要创建这些,我已经取得了一些重要进展,使我的表能够按照需要运行。
但是,我对我所覆盖的所有不同方法感到不知所措,并且正在试图弄清楚如何修改特定单元格的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
答案 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
来说既不必要又有潜在的性能影响。谢谢大家的见解和帮助。这让我感到沮丧!