Ранее выбранная ячейка JTable запускает редактор при нажатии клавиш, даже если явно не выбрана

Следующийtrashgod»отличный примерВотЯ собрал небольшую демонстрацию, которая решает простую задачу, вероятно, запутанно. Графический интерфейс, показанный ниже, отображает столбец значков, представляющих значения true / false. Если вы щелкнете по значку, он изменит значение на противоположное значению. Почти как флажок, но с другим внешним видом и более расширяемым (например, я мог бы изменить его в будущем, чтобы циклически проходить через дюжину символов, а не только два логических символа).

Я сделал это с помощью специального редактора, который является фиктивным расширением JComponent. Вы никогда даже не увидите этот фиктивный компонент, потому что, как только он поднимаетMousePressed событие, вызывает редакторfireEditingStopped(), Он прекрасно работает, за исключением одной странной ошибки, которую я нашел. Если вы щелкнете по символу, чтобы изменить его, а затем переместите указатель мыши в другое место на экране и нажмите клавишу клавиатуры, он вызовет фиктивный редактор в последней нажатой ячейке (который фактически закрывает ячейку) и останется там до тех пор, пока вы не либо переместите указатель мыши в ячейку, либо щелкните другую ячейку.

В качестве хакерского исправления я добавил строку в рендере, которая всегда отменяет выбор всей таблицы после ее рендеринга. Это прекрасно работает, и я убедился, что вся таблица действительно отменена. Однако, несмотря на это, если вы нажмете клавишу клавиатуры, онеще выполняет редактор для последней отредактированной ячейки. Как я могу предотвратить это поведение? В моем приложении есть другие слушатели клавиатуры, и если ячейка не выбрана, я не думаю, что какой-либо из их редакторов должен быть выполнен.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.imageio.ImageIO;
import javax.swing.AbstractCellEditor;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

public class JTableBooleanIcons {

    private JFrame frame;
    private DefaultTableModel tableModel;
    private JTable table;

    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    JTableBooleanIcons window = new JTableBooleanIcons();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public JTableBooleanIcons() {
        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        tableModel = new DefaultTableModel(new Object[]{"Words", "Pictures"},0);
        table = new JTable(tableModel);
        table.setRowHeight(40);
        tableModel.addRow(new Object[]{"click icon to change", false});
        tableModel.addRow(new Object[]{"click icon to change", true});
        tableModel.addRow(new Object[]{"click icon to change", false});
        tableModel.addRow(new Object[]{"click icon to change", true});
        tableModel.addRow(new Object[]{"click icon to change", false});
        tableModel.addRow(new Object[]{"click icon to change", true});
        tableModel.addRow(new Object[]{"click icon to change", false});
        tableModel.addRow(new Object[]{"click icon to change", true});

        frame.getContentPane().add(table, BorderLayout.CENTER);

        table.getColumn("Pictures").setCellRenderer(new BooleanIconRenderer());
        table.getColumn("Pictures").setCellEditor(new BooleanIconEditor());

    }

    @SuppressWarnings("serial")
    private class BooleanIconRenderer extends DefaultTableCellRenderer implements TableCellRenderer {

        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                                        boolean hasFocus, int row, int col) {
            String iconFilename = null;
            if ((boolean) value) {
                iconFilename = "yes.png";
                value = true;
            } else {
                iconFilename = "no.png";
                value = false;
            }
            try {
                setIcon(new ImageIcon(ImageIO.read(BooleanIconRenderer.class.getResourceAsStream(iconFilename))));
            } catch (Exception e) {
                System.err.println("Failed to load the icon.");
            }
            if (isSelected) {
                this.setBackground(Color.white);
            } else {
                this.setBackground(Color.white);
            }
            table.getSelectionModel().clearSelection();
            return this;
        }
    }

    @SuppressWarnings("serial")
    private class BooleanIconEditor extends AbstractCellEditor implements TableCellEditor, MouseListener {

        private BooleanComponent boolComp;

        public BooleanIconEditor() {
            boolComp = new BooleanComponent(false);
            boolComp.addMouseListener(this);
        }

        @Override
        public Object getCellEditorValue() {
            return boolComp.getValue();
        }

        @Override
        public Component getTableCellEditorComponent(JTable table,
                Object value, boolean isSelected, int row, int column) {
            boolComp.setValue(! (boolean) value);
            return boolComp;
        }

        @Override
        public void mouseClicked(MouseEvent e) {
            this.fireEditingStopped();
        }

        @Override
        public void mousePressed(MouseEvent e) {
            this.fireEditingStopped();

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            this.fireEditingStopped();
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            this.fireEditingStopped();
        }

        @Override
        public void mouseExited(MouseEvent e) {
            this.fireEditingStopped();
        }

    }

    @SuppressWarnings("serial")
    private class BooleanComponent extends JComponent {
        private boolean value;

        public BooleanComponent(boolean value) {
            this.value = value;
        }

        public boolean getValue() {
            return value;
        }

        public void setValue(boolean value) {
            this.value = value;
        }
    }
}

Ответы на вопрос(2)

Ваш ответ на вопрос