有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java在TableCellRenderer中使用自定义Swing 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中返回的东西。GetTableCellRenderComponent(),则仅当我单击相关单元格时,它才会重新绘制。有什么好处?我一定漏掉了一些非常简单的东西


共 (3) 个答案

  1. # 1 楼答案

    你们两人(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;
        }
    }
    
  2. # 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中的整数,它将触发条的重新绘制(您可能需要TableModel.fireTableCellUpdated,具体取决于您使用的TableModel实现)

  3. # 3 楼答案

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

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

    如果数据发生了变化,但表没有立即重新呈现,那么我会说您的表模型工作不正常

    基础数据更改->;表格模型更改->;fires TableModelEvent->;JTable重新渲染

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

    确保你做的每件事都是正确的