Pregunta

En el ejemplo a continuación tengo un JTable a JList y dos JButtonS (agregar y eliminar). En la lista hay 6 elementos (cadenas) cuando uno hace clic en el botón Agregar un valor seleccionado se agrega a la tabla.
Las cadenas en la tabla se muestran utilizando un renderizador personalizado (un JPanel con un botón y una etiqueta). El texto del botón y el texto de la etiqueta se cambian al valor de la cadena.
Todo va bien hasta que el editor haga su entrada. El editor permite hacer clic en el botón para que sea necesario.
Cuando uno agrega una cadena a la tabla por primera vez que se muestra correctamente, la altura de la fila se ajusta a la altura preferida del panel y el texto está configurado para el botón y la etiqueta.
Cuando se elimina la entrada de la tabla haciendo clic en la fila y luego haciendo clic en el botón Retirar todo se esperaba.
Ahora aquí viene el problema: si uno agrega una cadena (diferente) a la tabla, la altura de la fila es y el texto de la etiqueta y el botón no se establece (porque el renderizador y el editor no se llaman, he verificado, he verificado usando puntos de interrupción).
Por supuesto, quiero que se muestre la nueva fila utilizando el renderizador personalizado, pero ¿cómo hago esto?

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);
        }
    }
}
¿Fue útil?

Solución

Nunca debes usar:

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

en un renderizador. Esto causará un bucle infinito ya que cada vez que cambie la altura de la fila, la tabla repintará () la fila y cuando se invoca el renderizador, volverá a cambiar la altura de la fila ...

Deshágase de esa línea de código. En su lugar, puede calcular la altura de la fila cuando agrega la fila a la tabla. Agregue este código al final de su método 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);

Actualizar:

El código funciona bien sin el editor personalizado. Entonces el problema es el editor. Mire el código fuente del Abstract CellEditor para ver qué sucede cuando se detiene la edición. Dispara un evento para notificar a la tabla para que se pueda eliminar el editor. No tienes este código. Así que le sugiero que extienda el StraceCelEditor en lugar de extender customPanel Para que pueda disparar el evento apropiado.

Además, creo que hacer clic en una fila invocará el editor, por lo que debe eliminar el editor antes de eliminar la fila del modelo. Ver Tabla deja de editar por un par de formas de hacer esto.

Otros consejos

Implementación de addCellEditorListener (), eliminarCellEditorListener (), stopCellediting () y CancelCellediting () Los métodos funcionan como un encanto. Un editor debe ser 'desconectado' antes de eliminar el objeto seleccionado.
En una de mis tablas tengo un menú contextual para modificar las entradas de la tabla y antes de eliminar tengo que llamar a CancelCellediting () o StopCellediting () de lo contrario, la tabla no libera la entrada o vuelve a aparecer como antes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top