Domanda

Nell'esempio seguente ho a JTable UN JList e due JButtons (aggiungi e rimuovi).Nell'elenco ci sono 6 elementi (Stringhe) quando si fa clic sul pulsante Aggiungi, un valore selezionato viene aggiunto alla tabella.
Le stringhe nella tabella vengono visualizzate utilizzando un renderer personalizzato (a JPanel con un pulsante e un'etichetta).Il testo del pulsante e il testo dell'etichetta vengono modificati nel valore di String.
Tutto va bene finché l'editore non fa il suo ingresso.L'editor consente di fare clic sul pulsante quindi è necessario.
Quando si aggiunge una stringa alla tabella per la prima volta, questa viene visualizzata correttamente, l'altezza della riga viene regolata all'altezza preferita del pannello e il testo viene impostato per il pulsante e l'etichetta.
Quando si rimuove la voce dalla tabella facendo clic sulla riga e quindi facendo clic sul pulsante Rimuovi, tutto va come previsto.
Ora ecco il problema:Se si aggiunge una stringa (diversa) alla tabella, l'altezza della riga è e il testo dell'etichetta e del pulsante non sono impostati (poiché sia ​​il renderer che l'editor non vengono chiamati, ho controllato utilizzando i punti di interruzione).
Ovviamente voglio che la nuova riga venga visualizzata utilizzando il renderer personalizzato, ma come posso farlo?

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);
        }
    }
}
È stato utile?

Soluzione

Non dovresti mai usare:

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

in un renderer.Ciò causerà un ciclo infinito poiché ogni volta che si modifica l'altezza della riga la tabella ridipingerà() la riga e quando viene richiamato il renderer si modificherà nuovamente l'altezza della riga....

Sbarazzati di quella riga di codice.Puoi invece calcolare l'altezza della riga quando aggiungi la riga alla tabella.Aggiungi questo codice alla fine del tuo metodo 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);

Aggiornamento:

Il codice funziona correttamente senza l'editor personalizzato.Quindi il problema è l'editore.Guarda il codice sorgente di AbstractCellEditor per vedere cosa succede quando la modifica viene interrotta.Genera un evento per notificare la tabella in modo che l'editor possa essere rimosso.Non hai questo codice.Quindi ti suggerisco di estendere AbstractCellEditor invece di estendere customPanel in modo da poter attivare facilmente l'evento appropriato.

Inoltre, credo che facendo clic su una riga verrà richiamato l'editor, quindi è necessario rimuovere l'editor prima di rimuovere la riga dal modello.Vedere Tabella Interrompi modifica per un paio di modi per farlo.

Altri suggerimenti

L'implementazione dei metodi addCellEditorListener(),removeCellEditorListener(), stopCellEditing() e cancelCellEditing() funziona a meraviglia.Un editor deve essere "disconnesso" prima di rimuovere l'oggetto selezionato.
In una delle mie tabelle ho un menu contestuale per modificare le voci della tabella e prima della rimozione devo chiamare cancelCellEditing() o stopCellEditing() altrimenti la tabella non rilascia la voce o riappare come prima.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top