Question

OK, je sais comment faire un JComponent personnalisé simple. Je sais comment passer outre un TableCellRenderer. Je ne peux pas sembler combiner les deux.

Voici un exemple que j'ai créé 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; }
}

Il fonctionne très bien comme JComponent autonome. Je l'appelle et il met à jour setXval(something) très bien. (Edit: j'ai une minuterie Swing qui met à jour les données périodiquement)

Mais, il ne redessine si ce composant est quelque chose que je retourne dans TableCellRenderer.getTableCellRendererComponent () lorsque je clique sur la cellule en question. Ce qui donne? Je dois quitter quelque chose très simple.

Était-ce utile?

La solution

Pour des raisons de performance un JTable réutilise composants pour peindre plusieurs renderer cellules - donc quand vous voyez le composant dans le JTable il n'y est pas réellement dans le sens traditionnel d'un composant dans un conteneur qui est présent à un endroit. Cela signifie que l'appel repeindre () sur le composant renderer ne fait rien.

L'option la plus efficace serait de stocker la valeur entière de la barre dans votre TableModel. Votre TableCellRenderer alors ressembler à quelque chose comme ceci:

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

Ensuite, vous pouvez changer le nombre entier dans votre TableModel et déclencherait une repeindre de la barre (vous devrez peut-être une personne à charge TableModel.fireTableCellUpdated sur la mise en œuvre de TableModel que vous utilisez).

Autres conseils

Les deux vous (Russ Hayward et Andrew) ont aidé, la clé était essentiellement de faire ce qui suit:

  • stocker l'état à être visible dans le TableModel lui-même, et non pas dans le moteur de rendu
  • Assurez-vous que lorsque les changements d'état du TableModel, est appelé fireTableCellUpdated()
  • ont seulement un objet TableCellRenderer et un JComponent pour ma colonne personnalisée (pas un par cellule)
    • au sein de l'état magasin TableCellRenderer.getTableCellRendererComponent() de la cellule à des fins d'être rendu peu après (stockage à long terme est dans le TableModel)
    • fournir cet état à la JComponent
    • retourner le JComponent
    • override JComponent.PaintComponent()
  • une possibilité pratique est un moteur de rendu personnalisé pour étendre JComponent et mettre en œuvre TableCellRenderer, puis en vous stockez l'return this; état de la cellule et <=>

Voici l'extrait pertinent de mon code qui fonctionne maintenant:

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

Si vous faites une table avec 3 rangées dire, chacun ayant un autre xVal, puis-t-elle renderer d'abord correctement, ce qui signifie chaque cellule a un autre bar à la recherche?

Quand vous dites ne pas repeindre à moins que vous cliquez dessus, a quelque chose qui est arrivé à vos données sous-jacentes qui aurait causé l'affichage visuel des données (la barre rendu) pour changer?

Si les données ont été modifiées, mais la table ne pas immediatley réengendrer, je dirais que votre TableModel ne fonctionne pas correctement.

sous-tendant les modifications de données -> TableModel changements -> incendies TableModelEvent -> JTable nouveau rendu

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

pour vous assurer que vous faites tout correct.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top