Pergunta

OK, eu sei como fazer um simples costume JComponent. Eu sei como substituir um TableCellRenderer. Eu não consigo combinar os dois.

Aqui está uma JComponent amostra Criei:

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; }
}

Ele funciona muito bem como um autônomo JComponent. Eu chamo setXval(something) e atualiza apenas multa. (Edit: Eu tenho um temporizador do balanço que atualiza os dados periodicamente)

Mas se este componente é algo que eu retorno em TableCellRenderer.getTableCellRendererComponent (), então ele só redesenha quando eu clicar sobre a célula em questão. O que da? Eu devo estar deixando de fora algo realmente simples.

Foi útil?

Solução

Por motivos de desempenho uma JTable reutiliza componentes renderizador para pintar várias células - assim quando você vê o componente na JTable não está realmente lá, no sentido tradicional de um componente em um recipiente que está presente em um local. Isto significa que chamar repaint () no componente renderizador não faz nada.

A opção mais eficaz seria para armazenar o valor inteiro do bar em sua TableModel. Seu TableCellRenderer, então, algo parecido com isto:

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;
    }
}

Em seguida, você poderia mudar o Integer em sua TableModel e provocaria uma repaint do bar (você pode precisar de um TableModel.fireTableCellUpdated dependente da implementação TableModel você está usando).

Outras dicas

Tanto de você (Russ Hayward e Andrew) ajudou, a chave era essencialmente para fazer o seguinte:

  • armazenar o estado de ser tornada visível no próprio TableModel, não no renderizador
  • Certifique-se de que, quando as mudanças de estado da tabela simples, fireTableCellUpdated() é chamado
  • têm apenas um objeto TableCellRenderer e um JComponent para minha coluna personalizada (não um por célula)
    • dentro de loja TableCellRenderer.getTableCellRendererComponent() estado da célula para fins de estar tornando logo depois (armazenamento a longo prazo está no TableModel)
    • fornecer esse estado ao JComponent
    • devolver o JComponent
    • override JComponent.PaintComponent()
  • uma possibilidade conveniente é para um processador personalizado para estender JComponent e implementar TableCellRenderer, em seguida, em TableCellRenderer.getTableCellRendererComponent() você armazenar o estado da célula e return this;

Aqui está o trecho relevante do meu código que agora funciona:

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;
    }
}

Se você fizer uma tabela com digamos 3 linhas, cada uma com uma ValX diferente, então ele inicialmente renderizador corretamente, o que significa que cada célula tem um bar olhando diferente?

Quando você diz que não redesenhar a menos que você clicar nele, tem algo aconteceu com seus dados subjacentes que deve ter causado a apresentação visual dos dados (a barra prestados) a mudança?

Se os dados alterados, mas a tabela não immediatley re-render, então eu diria que seu TableModel não está funcionando corretamente.

subjacente alterações de dados -> TableModel muda -> dispara TableModelEvent -> JTable re-torna

Olhe para o TableModel tuturial: http: / /java.sun.com/docs/books/tutorial/uiswing/components/table.html#data

para se certificar de que você está fazendo tudo correto.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top