当我单击一个表格单元格,然后单击第二个表格单元格时,发生许多我不理解的鼠标和焦点事件。例如,单击单元格(1、0),然后单击单元格(2、1),然后单击“完成”按钮以显示事件序列,将导致以下事件:

1)鼠标压在单元格上(1,0)
2)聚焦于单元格(1,0)
3)鼠标压在单元格(1,0)上-为什么(?)
4)鼠标压在单元格(2,1)上
5)专注于单元格(1,0)-为什么(?)
6)专注于单元格(2,1)
7)焦点集中在单元格(1,0)上-为什么(?)
8)聚焦于单元格(2,1)-为什么(?)
9)专注于单元格(1,0)-为什么(?)
10)焦点丢失在单元格(2,1)上-为什么(?)

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.*;
import static javax.swing.SwingConstants.CENTER;
import static javax.swing.SwingConstants.LEFT;
import javax.swing.SwingUtilities;
import javax.swing.table.*;

public class TestFocus {

    public ArrayList<String> mylog;
    public int number = 0;

    public TestFocus() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel panel = createPanel();
        frame.add(panel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public JPanel createPanel() {
        mylog = new ArrayList<>();
        JPanel panel = new JPanel();
        TestTableModel tm = new TestTableModel();
        JLabel title = new JLabel("Test Table");
        JTable table = new JTable(tm);
        TableColumnModel tcm = table.getColumnModel();
        TestTableCellEditor editor = new TestTableCellEditor();
        TestTableCellRenderer renderer = new TestTableCellRenderer();
        for (int i = 0; i < tm.getColumnCount(); i++) {
            TableColumn column = tcm.getColumn(i);
            column.setCellEditor(editor);
            column.setCellRenderer(renderer);
        }

        JScrollPane jsp = new JScrollPane(table);

        JButton btn = new JButton("Done");
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                for (String s : mylog) {
                    System.out.println(s);
                }
            }
        });

        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
        panel.add(jsp);
        panel.add(btn);
        return panel;
    }

    class TestTableModel extends AbstractTableModel {
        private String[] columnNames = { "Firstname", "Lastname", "Age" };
        private Object[][] data = {
            { "John", "Smith", 29},
            { "Mary", "Thomas", 63},
            { "Peter", "Jones", 48} };

        public int getColumnCount() {
            return columnNames.length;
        }

        public int getRowCount() {
            return data.length;
        }

        public String getColumnName(int col) {
            return columnNames[col];
        }

        public Object getValueAt(int row, int col) {
            return data[row][col];
        }

        public Class getColumnClass(int col) {
            return getValueAt(0, col).getClass();
        }

        public String getColumnClassName(int col) {
            if (col == 2) {
                return "Integer";
            } else {
                return "String";
            }
        }

        public boolean isCellEditable(int row, int col) {
            return true;
        }

        public void setValueAt(Object value, int row, int col) {
            data[row][col] = value;
            fireTableCellUpdated(row, col);
        }
    }

    public class TestTableCellEditor extends AbstractCellEditor
            implements TableCellEditor {
        JComponent component = new JTextField();

        @Override
        public Component getTableCellEditorComponent(JTable table, Object value,
                boolean isSelected, int row, int column) {

            ((JTextField)component).addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent me) {
                    mylog.add(++number + ") Mouse pressed: " +
                        value.toString() + ": r/c ("+row+"/"+column+")");
                }
            });

            ((JTextField)component).addFocusListener(new FocusListener() {
                @Override
                public void focusGained(FocusEvent fe) {
                    mylog.add(++number + ") Focus gained: " +
                        value.toString() + ": r/c ("+row+"/"+column+")");
                }

                @Override
                public void focusLost(FocusEvent fe) {
                    mylog.add(++number + ") FocusLost: " +
                        value.toString() + ": r/c ("+row+"/"+column+")");
                }
            });

            if (value != null) {
                ((JTextField)component).setText(value.toString());
            } else {
                ((JTextField)component).setText("");
            }

            return (JTextField)component;
        }

        @Override
        public Object getCellEditorValue() {
            return ((JTextField)component).getText();
        }

    }

    public class TestTableCellRenderer extends JLabel implements
                TableCellRenderer {

        public TestTableCellRenderer() {
            this.setOpaque(true);
        }

        public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, final int row, int column) {

            DefaultTableCellRenderer renderer = new DefaultTableCellRenderer();
            Component c = renderer.getTableCellRendererComponent(table, value,
                    isSelected, hasFocus, row, column);
            if (hasFocus) {
                c.setBackground(Color.yellow);
            }
            TestTableModel tm = (TestTableModel)table.getModel();
            int col = table.convertColumnIndexToModel(column);
            String colname = tm.getColumnName(col);
            String type = tm.getColumnClassName(col);

            if (type.equals("Integer") || type.equals("Int")) {
                ((JLabel)c).setHorizontalAlignment(CENTER);
            } else {    // add padding
                ((JLabel)c).setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
                ((JLabel)c).setHorizontalAlignment(LEFT);
            }

            if (type.equals("String")) {
                String text = ((JLabel)c).getText();
                    ((JLabel)c).setToolTipText(text);
            }
           return c;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new TestFocus();
            }
        });
    }

}

最佳答案

getTableCellEditorComponent方法将在JTable呈现时被调用-很多次。在其中textfield.addMouseListener()。这意味着侦听器将被添加很多次。这就是为什么您收到许多事件而不是一个事件的原因(所有这些侦听器都会得到通知)。为了解决它,只添加一次监听器。您可以在此类的构造函数中添加侦听器。

例如:

public class TestTableCellEditor extends AbstractCellEditor implements TableCellEditor {
    private JTextField component;

    public TestTableCellEditor() {
        component = new JTextField();
        component.addMouseListener(mouseListener);
        component.addFocusListener(focusListener)
    }

    @Override
    public Object getCellEditorValue() {
        return component.getText();
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) {
        component.setText(value == null ? "" : String.valueOf(value));
        return component;
    }

}

09-10 10:02
查看更多