0

好的,我知道如何制作一个简单的自定义 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),它更新就好了。(编辑:我有一个摆动计时器,它会定期更新数据)

但是如果这个组件是我在 TableCellRenderer.getTableCellRendererComponent() 中返回的东西,那么它只会在我单击相关单元格时重新绘制。是什么赋予了?我一定遗漏了一些非常简单的东西。

4

3 回答 3

2

出于性能原因,JTable 重用渲染器组件来绘制多个单元格 - 因此,当您在 JTable 中看到组件时,它实际上并不存在于传统意义上的容器中的组件存在于某个位置。这意味着在渲染器组件上调用 repaint() 什么都不做。

最有效的选择是将条形的整数值存储在 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 中的 Integer ,它会触发条的重绘(您可能需要一个 TableModel.fireTableCellUpdated 取决于您正在使用的 TableModel 实现)。

于 2009-05-15T10:37:26.207 回答
2

你们两个(Russ Hayward 和 Andrew)都提供了帮助,关键是要做到以下几点:

  • 将要显示的状态存储在 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;
    }
}
于 2009-05-19T14:20:42.850 回答
1

如果您制作一个包含 3 行的表格,每行都有不同的 Xval,那么它最初是否正确渲染,这意味着每个单元格都有不同的外观栏?

当您说除非您单击它才重新绘制它,那么您的基础数据是否发生了本应导致数据的视觉显示(渲染栏)发生变化的情况?

如果数据发生了变化,但表格没有立即重新渲染,那么我会说您的 TableModel 工作不正常。

底层数据更改 -> TableModel 更改 -> 触发 TableModelEvent -> JTable 重新渲染

查看 TableModel 教程:http: //java.sun.com/docs/books/tutorial/uiswing/components/table.html#data

确保你做的一切都是正确的。

于 2009-05-14T23:06:11.407 回答