在TableCellRenderer中使用自定义Swing JComponent

时间:2009-05-14 17:39:25

标签: java swing jcomponent tablecellrenderer

好的,我知道如何制作一个简单的自定义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 Timer)

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

3 个答案:

答案 0 :(得分:2)

出于性能原因,JTable重用渲染器组件来绘制多个单元格 - 因此当您在JTable中看到组件时,实际上并不存在传统意义上的某个位置存在的Container中的Component。这意味着在渲染器组件上调用repaint()不会执行任何操作。

最有效的选择是在TableModel中存储条形的Integer值。你的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实现)。

答案 1 :(得分:2)

你们两个人(拉斯·海沃德和安德鲁)帮忙,关键主要是要做到以下几点:

  • 将状态存储在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;
    }
}

答案 2 :(得分:1)

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

当你说它没有重新绘制除非你点击它,你的底层数据发生了什么事情应该导致数据的可视化显示(渲染条)改变?

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

基础数据更改 - > TableModel更改 - >触发TableModelEvent - > JTable重新渲染

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

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