Java 在Jtable单元格中单击JComboBox时调用ActionPerformed

Java 在Jtable单元格中单击JComboBox时调用ActionPerformed,java,swing,jframe,jtable,Java,Swing,Jframe,Jtable,我正在Jtable单元格中使用JComboBox。当我点击JComboBox并从中选择一个值时,它调用ActionPerformed函数。在此之前,它工作正常,但只要我再次单击JComboBox,它就会调用ActionPerformed函数,而它不应该调用该函数。我想要的是,当在JComboBox中选择项目时,调用ActionPerformed函数。换句话说,当从JComboBox中选择项目,然后调用ActionPerformed函数时,它应该像第一次那样工作。我不明白为什么会发生这个问题。这里

我正在
Jtable
单元格中使用
JComboBox
。当我点击
JComboBox
并从中选择一个值时,它调用
ActionPerformed
函数。在此之前,它工作正常,但只要我再次单击
JComboBox
,它就会调用
ActionPerformed
函数,而它不应该调用该函数。我想要的是,当在
JComboBox
中选择项目时,调用
ActionPerformed
函数。换句话说,当从
JComboBox
中选择项目,然后调用
ActionPerformed
函数时,它应该像第一次那样工作。我不明白为什么会发生这个问题。这里是我已经查看过的链接,我也做了一些其他搜索,但仍然找不到上述问题的任何相关答案

  • 这是代码,你可以复制粘贴并检查

    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import javax.swing.DefaultCellEditor;
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.table.TableColumn;
    
    public class TableExample implements ActionListener{
    
        JFrame frame;
        JComboBox skuNameComboBoxTable;
    
        TableExample() {
            frame = new JFrame();
            String data[][] = {{"101", "Amit", "Choose"},
            {"102", "Jai", "Choose"},
            {"101", "Sachin", "Choose"}};
            String column[] = {"ID", "Name", "Degree"};
            JTable table = new JTable(data, column);
            table.setBounds(30, 40, 200, 300);
            JScrollPane scrollPane = new JScrollPane(table);
            frame.add(scrollPane);
            frame.setSize(300, 400);
            frame.setVisible(true);
    
            String[] array = {"BS(SE)", "BS(CS)", "BS(IT)"};
            skuNameComboBoxTable = new JComboBox(array);
            skuNameComboBoxTable.addActionListener(this);
    
            TableColumn col = table.getColumnModel().getColumn(2);
            col.setCellEditor(new DefaultCellEditor(skuNameComboBoxTable));
        }
    
        public static void main(String[] args) {
            new TableExample();
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            JOptionPane.showMessageDialog(null, "actionPerformed called");
        }
    }
    

    请告诉我发生此问题的原因以及我应该如何解决它。

    您可以尝试使用ItemListener并根据ItemEvent筛选您的操作

    import java.awt.event.ItemEvent;
    import java.awt.event.ItemListener;
    
    import javax.swing.JComboBox;
    import javax.swing.JFrame;
    
    
    public class JComboBoxTest {
        public static void main(String[] args) {
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
            String[] items = {"One", "Two", "Three"};
            JComboBox cb = new JComboBox(items);
            cb.addItemListener(new ItemListener() {
                @Override
                public void itemStateChanged(ItemEvent e) {
                    if (e.getStateChange() == ItemEvent.SELECTED) {
                        System.out.println("Selected " + e.getItem());
                    } else {
                        System.out.println("Deselected " + e.getItem());
                    }
                }
            });
    
            frame.add(cb);
    
            frame.pack();
            frame.setVisible(true);
        }
    }
    

    不幸的是,当使用DefaultCellEditor时,您不能做太多事情-这就是它的行为方式。在代码中,可以添加一个检查,以确保在处理事件之前值发生了更改。如下所示:

    public void actionPerformed(ActionEvent e) {
        if (skuNameSelected == null || skuNameComboBoxTable.getSelectedItem() != skuNameSelected)
            JOptionPane.showMessageDialog(null, "actionPerformed called: ");
        skuNameSelected = (String) skuNameComboBoxTable.getSelectedItem();
    }
    
    TableColumn col = table.getColumnModel().getColumn(2);
    DefaultCellEditor cellEditor = new DefaultCellEditor(skuNameComboBoxTable);
    col.setCellEditor(cellEditor);
    
    cellEditor.addCellEditorListener(new CellEditorListener() {
    
                @Override
                public void editingStopped(ChangeEvent e) {
                    System.out.println("Value of combo box defined!");
                }
    
                @Override
                public void editingCanceled(ChangeEvent e) {
                    System.out.println("Edition canceled, set the old value");
                }
    });
    

    之所以发生这种情况,是因为您正在使用与列2的DefaultCellEditor相同的JComboBox

    无论何时单击第2列中的单元格,组合框都将更改为当前单元格上的值,并触发取消选择(来自旧值)和选择(用于新值)只有当旧值和新值不相同时,才会发生这种情况。

    避免这种情况的一种方法是在您正在使用的DefaultCellEditor上添加CellEditorListener,如下所示:

    public void actionPerformed(ActionEvent e) {
        if (skuNameSelected == null || skuNameComboBoxTable.getSelectedItem() != skuNameSelected)
            JOptionPane.showMessageDialog(null, "actionPerformed called: ");
        skuNameSelected = (String) skuNameComboBoxTable.getSelectedItem();
    }
    
    TableColumn col = table.getColumnModel().getColumn(2);
    DefaultCellEditor cellEditor = new DefaultCellEditor(skuNameComboBoxTable);
    col.setCellEditor(cellEditor);
    
    cellEditor.addCellEditorListener(new CellEditorListener() {
    
                @Override
                public void editingStopped(ChangeEvent e) {
                    System.out.println("Value of combo box defined!");
                }
    
                @Override
                public void editingCanceled(ChangeEvent e) {
                    System.out.println("Edition canceled, set the old value");
                }
    });
    
    这样,您将只能在ComboBox定义值时执行操作


    我希望这有帮助。

    您不应该为此使用ActionListener。组合框使用自己的ActionListener在选择项时更新TableModel

    因此,您应该监听TableModel中的更改,以便执行自定义代码。因此,您应该使用
    TableModelListener
    来侦听数据中的更改。但是,
    TableModelListener
    可以触发事件,即使只是开始和停止编辑单元格,这可能会给您带来问题

    在这种情况下,您可以使用。它将仅在TableModel中的值发生更改时生成事件