【问题标题】:Multiple focus events from mouse click in JTableJTable中鼠标单击的多个焦点事件
【发布时间】:2019-12-07 16:42:40
【问题描述】:

当我单击一个表格单元格,然后单击第二个表格单元格时,会发生一些我无法理解的鼠标和焦点事件。例如,单击单元格 (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();
            }
        });
    }

}

【问题讨论】:

    标签: java swing jtable focus mouselistener


    【解决方案1】:

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

    【讨论】:

    • 这清除了多个事件,但是当我单击第二个单元格时,它的焦点在获得之前就丢失了,并且单击第一个单元格时焦点永远不会丢失。不知道如何显示修改后的编辑器代码
    • “这清除了多个事件” 这似乎涵盖了“JTable 中鼠标单击的多个焦点事件”。请accept the answer,因为它有助于解决问题。 “但是..” 没有但是。如果还有更多问题,请提出新问题。请在下一个问题中添加swing 标签。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-12
    • 1970-01-01
    • 1970-01-01
    • 2020-04-11
    • 2012-11-28
    • 2012-11-28
    相关资源
    最近更新 更多