在 TableCellRenderer 中使用自定义 Swing JComponent
-
21-08-2019 - |
题
好的,我知道如何制作一个简单的自定义 JComponent。我知道如何重写 TableCellRenderer。我似乎无法将两者结合起来。
这是一个示例 JComponent
我创建:
public static class BarRenderer extends JComponent
{
final private double xmin;
final private double xmax;
private double xval;
public BarRenderer(double xmin, double xmax)
{
this.xmin=xmin;
this.xmax=xmax;
}
@Override protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Rectangle r = g.getClipBounds();
g.drawRect(r.x, r.y,
(int)(r.width * ((xval-xmin)/(xmax-xmin))), r.height);
}
public void setXval(double x) {
this.xval = x;
repaint();
}
public double getXval() { return xval; }
}
它作为独立的 JComponent 工作得很好。我打电话 setXval(something)
而且更新得很好。(编辑:我有一个 Swing 计时器,可以定期更新数据)
但是,如果这个组件是我在 TableCellRenderer.getTableCellRendererComponent() 中返回的组件,那么它只会在我单击相关单元格时重新绘制。是什么赋予了?我一定遗漏了一些非常简单的东西。
解决方案
有关性能原因JTable中重用渲染器组件绘制多个单元格 - 因此,当你在JTable看到组件它实际上不是有在容器,其存在的位置处的组件的传统意义上的。这意味着,渲染器组件上调用重绘()什么都不做。
最有效的办法是酒吧的整数值存储在您的TableModel。那么你的TableCellRenderer会是这个样子:
public class BarTableCellRenderer implements TableCellRenderer {
private final BarRenderer rendererComponent = new BarRenderer(0, 10);
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
rendererComponent.setXval((Integer)value);
return rendererComponent;
}
}
然后你可以改变整你的TableModel,它会触发条的重绘(你可能需要一个TableModel.fireTableCellUpdated取决于你使用的是TableModel的实现)。
其他提示
你们俩(拉斯·海沃德和安德鲁)都提供了帮助,关键是要做到以下几点:
- 存储要在 TableModel 本身中可见的状态,而不是在渲染器中
- 确保当 TableModel 的状态发生变化时,
fireTableCellUpdated()
叫做 - 只有 一 TableCellRenderer 对象和 一 我的自定义列的 JComponent(不是每个单元格一个)
- 之内
TableCellRenderer.getTableCellRendererComponent()
存储单元格的状态以便稍后渲染(长期存储在 TableModel 中) - 将该状态提供给 JComponent
- 返回 JComponent
- 覆盖
JComponent.PaintComponent()
- 之内
- 一种方便的可能性是自定义渲染器扩展 JComponent 并实现 TableCellRenderer,然后在
TableCellRenderer.getTableCellRendererComponent()
你存储细胞的状态并且return this;
这是我现在可以使用的代码的相关摘录:
class TraceControlTableModel extends AbstractTableModel {
/* handle table state here */
// convenience method for setting bar value (table model's column 2)
public void setBarValue(int row, double x)
{
setValueAt(x, row, 2);
}
}
// one instance of BarRenderer will be set as the
// TableCellRenderer for table column 2
public static class BarRenderer extends JComponent
implements TableCellRenderer
{
final private double xmin;
final private double xmax;
private double xval;
public BarRenderer(double xmin, double xmax)
{
super();
this.xmin=xmin;
this.xmax=xmax;
}
@Override protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Rectangle r = g.getClipBounds();
g.drawRect(r.x, r.y,
(int)(r.width * ((xval-xmin)/(xmax-xmin))), r.height);
}
@Override
public Component getTableCellRendererComponent(JTable arg0,
Object value,
boolean isSelected, boolean hasFocus,
int row, int col)
{
// save state here prior to returning this object as a component
// to be painted
this.xval = (Double)value;
return this;
}
}
如果你犯了一个表,说3排,每一个具有不同XVAL,然后它开始渲染器正确,这意味着每个单元都有不同的期待吧?
当你说它不重画,除非你点击它,有一些发生在本应引起数据的可视化显示(渲染栏),以改变你的基础数据?
如果数据发生变化,但不能将表immediatley重新渲染,那么我会说,你的TableModel的工作不正常。
底层数据的改变 - >的TableModel变化 - >触发TableModelEvent - >的JTable重新呈现
看为TableModel tuturial: HTTP:/ /java.sun.com/docs/books/tutorial/uiswing/components/table.html#data
,以确保你正在做的一切是正确的。