Question

Dans l'exemple ci-dessous, j'ai un JTable, un JList et deux JButtons (ajouter et supprimer). Dans la liste se trouvent 6 éléments (chaînes) lorsque l'on clique sur le bouton d'ajout, une valeur sélectionnée est ajoutée au tableau.
Les chaînes du tableau sont affichées à l'aide d'un moteur de rendu personnalisé (un code générique avec un bouton et une étiquette). Le texte du bouton et le texte de l'étiquette prennent la valeur de la chaîne.
Tout se passe bien jusqu'à ce que l'éditeur fasse son entrée. L'éditeur permet de cliquer sur le bouton donc c'est nécessaire.
Quand on ajoute une chaîne à la table pour la première fois qu'elle s'affiche correctement, la hauteur de la ligne est ajustée à la hauteur préférée du panneau et le texte est défini pour le bouton et l'étiquette.
Quand on supprime l'entrée du tableau en cliquant sur la ligne, puis en cliquant sur le bouton Supprimer, tout se passe comme prévu.
Voici maintenant le problème: si on ajoute une chaîne (différente) à la table, la hauteur de la ligne est et le texte de l'étiquette et du bouton ne sont pas définis (car le moteur de rendu et l'éditeur ne sont pas appelés, j'ai vérifié en utilisant des points d'arrêt).
Bien sûr, je souhaite que la nouvelle ligne soit affichée à l'aide du moteur de rendu personnalisé, mais comment faire?

package test;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.EventObject;
import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;

public class MainForm
        extends javax.swing.JFrame
{
    private JTable table;
    private JScrollPane tableScrollPane;
    private JList list;
    private JScrollPane listScrollPane;
    private JButton add;
    private JButton remove;

    public MainForm()
    {
        tableScrollPane = new JScrollPane();
        table = new JTable();
        listScrollPane = new JScrollPane();
        list = new JList();
        add = new JButton(new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                add();
            }
        });
        add.setText("add");
        remove = new JButton(new AbstractAction()
        {
            public void actionPerformed(ActionEvent e)
            {
                remove();
            }
        });
        remove.setText("remove");

        setLayout(new javax.swing.BoxLayout(getContentPane(), javax.swing.BoxLayout.LINE_AXIS));

        tableScrollPane.setViewportView(table);
        listScrollPane.setViewportView(list);

        add(tableScrollPane);

        DefaultTableModel model = new DefaultTableModel();
        model.addColumn("test");
        table.setModel(model);

        TableColumn col = table.getColumn("test");
        col.setCellRenderer(new CustomTableCellRenderer());
        col.setCellEditor(new CustomTableCellEditor());

        DefaultListModel listModel = new DefaultListModel();
        listModel.addElement("test1");
        listModel.addElement("test2");
        listModel.addElement("test3");
        listModel.addElement("test4");
        listModel.addElement("test5");
        listModel.addElement("test6");
        list.setModel(listModel);

        add(listScrollPane);
        add(add);
        add(remove);
    }

    private void add()
    {
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        model.addRow(new Object[]
                {
                    list.getSelectedValue()
                });
    }

    private void remove()
    {
        int selectedRow = table.getSelectedRow();
        DefaultTableModel model = (DefaultTableModel) table.getModel();
        model.removeRow(selectedRow);
    }

    public static void main(String[] args)
    {
        new MainForm().setVisible(true);
    }

    public class CustomTableCellRenderer
            extends customPanel
            implements TableCellRenderer
    {
        public Component getTableCellRendererComponent(JTable table,
                                                       Object value,
                                                       boolean isSelected,
                                                       boolean hasFocus, int row,
                                                       int column)
        {
            setText((String) value);
            if (isSelected || hasFocus)
            {
                setBackground(UIManager.getColor("List.selectionBackground"));
                setForeground(UIManager.getColor("List.selectionForeground"));
            }
            else
            {
                setBackground(UIManager.getColor("Panel.background"));
                setForeground(UIManager.getColor("Panel.foreground"));
            }
            table.setRowHeight(row, (int)getPreferredSize().height);
            return this;
        }
    }

    public class CustomTableCellEditor
            extends customPanel
            implements TableCellEditor
    {
        Object value;

        public Component getTableCellEditorComponent(JTable table, Object value,
                                                     boolean isSelected, int row,
                                                     int column)
        {
            this.value = value;
            setText((String) value);
            setBackground(UIManager.getColor("List.selectionBackground"));
            setForeground(UIManager.getColor("List.selectionForeground"));
            table.setRowHeight(row, (int)getPreferredSize().height);
            return this;
        }

        public Object getCellEditorValue()
        {
            return value;
        }

        public boolean isCellEditable(EventObject anEvent)
        {
            return true;
        }

        public boolean shouldSelectCell(EventObject anEvent)
        {
            return true;
        }

        public boolean stopCellEditing()
        {
            setBackground(UIManager.getColor("Panel.background"));
            setForeground(UIManager.getColor("Panel.foreground"));
            return true;
        }

        public void cancelCellEditing()
        {
        }

        public void addCellEditorListener(CellEditorListener l)
        {
        }

        public void removeCellEditorListener(CellEditorListener l)
        {
        }
    }

    public class customPanel
            extends JPanel
    {
        private JLabel label;
        private JButton button;

        public customPanel()
        {
            label = new JLabel();
            button = new JButton();
            add(label);
            add(button);
        }

        public void setText(String text)
        {
            label.setText(text);
            button.setText(text);
        }
    }
}
Était-ce utile?

La solution

Vous ne devriez jamais utiliser:

table.setRowHeight(row, (int)getPreferredSize().height);

dans un moteur de rendu. Cela provoquera une boucle infinie puisque chaque fois que vous changez la hauteur de ligne, le tableau repeint () la ligne et lorsque le moteur de rendu est appelé, vous modifiez à nouveau la hauteur de ligne ....

Débarrassez-vous de cette ligne de code. Au lieu de cela, vous pouvez calculer la hauteur de la ligne lorsque vous ajoutez la ligne au tableau. Ajoutez ce code au bas de votre méthode add ():

int row = table.getRowCount() - 1;
Component comp = table.prepareRenderer(table.getCellRenderer(row, 0), row, 0);
int rowHeight = comp.getPreferredSize().height;
table.setRowHeight(row, rowHeight);

Mise à jour:

Le code fonctionne correctement sans l'éditeur personnalisé. Le problème est donc l'éditeur. Regardez le code source de AbstractCellEditor pour voir ce qui se passe lorsque l'édition est arrêtée. Il déclenche un événement pour notifier la table afin que l'éditeur puisse être supprimé. Vous n'avez pas ce code. Je vous suggère donc d'étendre AbstractCellEditor au lieu d'étendre customPanel afin que vous puissiez facilement déclencher l'événement approprié.

De plus, je crois que cliquer sur une ligne appellera l'éditeur, vous devez donc supprimer l'éditeur avant de supprimer la ligne du modèle. Voir Table Stop Editing pour plusieurs façons de procéder. .

Autres conseils

L'implémentation des méthodes addCellEditorListener (), removeCellEditorListener (), stopCellEditing () et cancelCellEditing () fonctionne comme un charme.Un éditeur doit être "déconnecté" avant de supprimer l'objet sélectionné.
Dans l'une de mes tables, j'ai un menu contextuel pour modifier les entrées de table et avant la suppression, je dois appeler cancelCellEditing () ou stopCellEditing () sinon la table ne libère pas l'entrée ou elle réapparaît comme avant.

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