0

OK、単純なカスタム JComponent の作成方法を知っています。TableCellRenderer をオーバーライドする方法を知っています。2つを組み合わせることができないようです。

これが私が作成したサンプル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; }
}

It works fine as a standalone JComponent. I call setXval(something) and it updates just fine. (edit: I have a Swing Timer that updates the data periodically)

But if this component is something I return in TableCellRenderer.getTableCellRendererComponent(), then it only repaints when I click on the cell in question. What gives? I must be leaving out something really simple.

4

3 に答える 3

2

両方(Russ HaywardとAndrew)が助けてくれました。重要なのは、基本的に次のことを行うことでした。

  • レンダラーではなく、TableModel自体に表示される状態を保存します
  • TableModelの状態が変化したときに、fireTableCellUpdated()が呼び出されることを確認してください
  • カスタム列用に TableCellRendererオブジェクトとJComponentが1だけあります(セルごとに1つではありません)
    • 直後にレンダリングするためにセルの状態をTableCellRenderer.getTableCellRendererComponent()保存します(長期保存はTableModelにあります)
    • その状態をJComponentに提供します
    • JComponentを返します
    • オーバーライドJComponent.PaintComponent()
  • 便利な可能性の1つは、カスタムレンダラーが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 に答える
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 実装によっては、TableModel.fireTableCellUpdated が必要になる場合があります)。

于 2009-05-15T10:37:26.207 に答える