Пользовательский TableCellEditor, показывающий предыдущую запись при добавлении - PullRequest
1 голос
/ 05 декабря 2011

В приведенном ниже примере у меня есть JTable a JList и два JButton s (добавить и удалить).В списке находятся 6 элементов (строк), когда одним нажатием кнопки добавления выбранное значение добавляется в таблицу.Строки в таблице отображаются с помощью пользовательского средства визуализации (JPanel с кнопкой и меткой).Текст кнопки и текст метки изменяются на значение String.Все идет хорошо, пока редактор не сделает свою запись.Редактор позволяет нажать кнопку, чтобы она была необходима.Когда в первый раз добавляется строка в таблицу, она отображается правильно, высота строки настраивается в соответствии с предпочтительной высотой панели, а для кнопки и надписи устанавливается текст.Когда кто-то удаляет запись из таблицы, щелкая строку и затем нажимая кнопку удаления, все идет как положено.Теперь возникает проблема: если добавить к таблице (другую) строку (String), высота строки будет равна, а текст метки и кнопки не будет установлен (поскольку не вызывается ни средство визуализации, ни редактор, я проверилиспользуя точки останова).Конечно, я хочу, чтобы новая строка отображалась с помощью пользовательского средства визуализации, но как мне это сделать?

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

Ответы [ 2 ]

2 голосов
/ 06 декабря 2011

Вы никогда не должны использовать:

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

в рендере.Это приведет к бесконечному циклу, так как всякий раз, когда вы изменяете высоту строки, таблица перерисовывает () строку, и когда вызывается рендерер, вы снова изменяете высоту строки ....

Избавьтесь от этой строкикод.Вместо этого вы можете вычислить высоту строки при добавлении строки в таблицу.Добавьте этот код в конец метода 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);

Обновление:

Код работает без специального редактора.Так что проблема в редакторе.Посмотрите на исходный код AbstractCellEditor, чтобы увидеть, что происходит, когда редактирование прекращается.Это вызывает событие, чтобы уведомить таблицу, чтобы редактор мог быть удален.У вас нет этого кода.Поэтому я предлагаю вам расширить AbstractCellEditor вместо расширения customPanel, чтобы вы могли легко запустить соответствующее событие.

Кроме того, я считаю, что нажатие на строку вызовет редактор, поэтому вам нужно удалить редактор перед тем, какВы удаляете строку из модели.См. Table Stop Editing для нескольких способов сделать это.

0 голосов
/ 06 декабря 2011

Реализация методов addCellEditorListener (), removeCellEditorListener (), stopCellEditing () и cancelCellEditing () работает как шарм. Редактор должен быть отключен перед удалением выбранного объекта.
В одной из моих таблиц у меня есть контекстное меню для изменения записей в таблице, и перед удалением мне нужно вызвать cancelCellEditing () или stopCellEditing (), иначе таблица не освобождает запись или она снова появляется, как раньше.

...