java - JTable 中鼠标单击引起的多个焦点事件

标签 java swing jtable focus mouselistener

当我单击一个表格单元格,然后单击第二个表格单元格时,会发生许多我不明白的鼠标和焦点事件。例如,单击单元格 (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;
    }

}

关于java - JTable 中鼠标单击引起的多个焦点事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59228151/

相关文章:

Java Sprite 应该与 Data Structure 合并

java - 使用调度程序的多个按键

java - 使用 ArrayList 创建 jTable

java - 按键和按钮兼容性 Java

java - getServletContext().getAttribute() 返回 null?

java - 将 boolean 值传递给上一个 Activity 并在 Android Java 中验证 boolean 值

java - 选择日期后将 jdatepicker impl 设置为空白

java - 如何使 JTable 单元格中的 JButton 可点击?

java - 无法使用 mysql "like"语句填充 jtable

java - 如何在javascript中使用action返回值(oncomplete)?