JTable 单元格中的 JComboBox。选择更改会影响其他行中的 JComboBox

JComboBox in JTable cell. Selection change affects JComboBox in other rows

我在这里潜伏了几年左右,以前从来不需要问问题,因为我总是在别人的问题中找到我的答案。谢谢!

我想潜伏已经结束了。我在这里看到过类似的问题,但不完全是这种情况: 我有一个 2 列的 JTable,第一列中有一个 JComboBox,第二列中有一个整数。 JComboBox 设置了 ItemListener,因此当 JComboBox 中的 selection 发生更改时,Integer 列中的值将设置为 comboBox selected 索引。右键单击 table 使用 addRow() 作为 MouseEvent 呈现 JPopupMenu。

只要我在设置 DefaultTableModel 时添加我想要的所有行,它就可以正常工作。但是,如果我只用一行启动模型并使用 MouseEvent(或任何其他添加行的方法,而不是将它们添加到 DefaultTableModel 的参数中)来添加行,当我们开始更改组合中的 selections 时boxes 它将更改其他行中的整数值。

例如:如果我 运行 程序并立即通过 MouseEvent 添加两行,然后我 select 第 0 行中的组合为零,第 1 行中的组合为一,第二为第 2 行的组合。到目前为止一切正常...... 然后我回到第 0 行,一旦我激活组合框(我还没有 selected 一个项目......)它就会将第 2 行中的整数更改为 0。 谁能告诉我如何阻止整数以这种方式改变? 这是试用代码:

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ItemEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

public class JComboBoxInJTable {

    public static void main(String[] args) {
        new JComboBoxInJTable();
    }

    public JComboBoxInJTable() {
        EventQueue.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                ex.printStackTrace();
            }

            DefaultTableModel model = new DefaultTableModel(new Object[]{"ComboBox", "Index"}, 1);
            JTable table = new JTable(model);

            //popup menu to add row
            JPopupMenu popup = new JPopupMenu();
            JMenuItem newRow;
            newRow = new JMenuItem("New Row");
            newRow.setToolTipText("Add new row.");
            newRow.addActionListener((ActionEvent nr) -> {
                model.addRow(new Object[]{"", ""});
            });
            popup.add(newRow);

            //set up right-click to open popup menu
            table.addMouseListener(new MouseAdapter() {
                @Override
                public void mousePressed(MouseEvent rc) {
                    if (SwingUtilities.isRightMouseButton(rc)) {
                        if (table.getSelectedRow() >= 0) {
                            popup.show(table, rc.getX(), rc.getY());
                        }
                    }
                }
            });

            JComboBox combo = new JComboBox(new Object[]{"Zero", "One", "Two", "Three"});
            combo.addItemListener((ItemEvent e) -> {
                if (e.getStateChange() == ItemEvent.SELECTED) {
                    //sets value of cell to left of combobox to comboboxe's selected index
                    table.setValueAt(combo.getSelectedIndex(), table.getSelectedRow(), 1);
                } else {
                    //do nothing...
                }
            });

            DefaultCellEditor comboEditor = new DefaultCellEditor(combo);

            TableColumnModel tcm = table.getColumnModel();
            tcm.getColumn(0).setCellEditor(comboEditor);

            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new JScrollPane(table));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}

像往常一样,我确信这是我所缺少的简单内容。再次感谢过去和未来的帮助!

  • 不要使用MouseListener来显示弹出菜单,不同的操作系统对弹出菜单有不同的触发,并不是所有的都由mousePressed触发。而是使用 JComponent#setComponentPopupMenu 并让 API 处理它
  • 不要从编辑器修改模型的状态。这会使模型进入无效状态并导致其他副作用,就像您现在遇到的那样。有一次似乎是在选择新行时,编辑器会更新行单元格值,但行选择尚未设置,因此 table 仍然认为前一行仍处于选中状态。相反,使用模型 setValueAt 方法来决定第一列值更改后要做什么。

例如...

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.swing.DefaultCellEditor;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;

public class JComboBoxInJTable {

    public static void main(String[] args) {
        new JComboBoxInJTable();
    }

    private List<String> comboData;

    public JComboBoxInJTable() {
        EventQueue.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                ex.printStackTrace();
            }

            DefaultTableModel model = new DefaultTableModel(new Object[]{"ComboBox", "Index"}, 1) {

                @Override
                public void setValueAt(Object aValue, int row, int column) {
                    super.setValueAt(aValue, row, column);
                    if (column == 0) {
                        String value = aValue == null ? null : aValue.toString();
                        if (aValue == null) {
                            super.setValueAt(null, row, 1);
                        } else {
                            super.setValueAt(comboData.indexOf(aValue), row, 1);
                        }
                    }
                }

            };
            JTable table = new JTable(model);
            table.setFillsViewportHeight(true);
            table.setGridColor(Color.GRAY);

            //popup menu to add row
            JPopupMenu popup = new JPopupMenu();
            JMenuItem newRow;
            newRow = new JMenuItem("New Row");
            newRow.setToolTipText("Add new row.");
            newRow.addActionListener((ActionEvent nr) -> {
                model.addRow(new Object[]{"", ""});
            });
            popup.add(newRow);

            table.setComponentPopupMenu(popup);

            comboData = new ArrayList<>(Arrays.asList(new String[]{"Zero", "One", "Two", "Three"}));

            JComboBox combo = new JComboBox(comboData.toArray(new String[comboData.size()]));
//          combo.addItemListener((ItemEvent e) -> {
//              if (e.getStateChange() == ItemEvent.SELECTED) {
//                  //sets value of cell to left of combobox to comboboxe's selected index
//                  System.out.println("Selected row = " + table.getSelectedRow());
//                  table.setValueAt(combo.getSelectedIndex(), table.getSelectedRow(), 1);
//              } else {
//                  //do nothing...
//              }
//          });

            DefaultCellEditor comboEditor = new DefaultCellEditor(combo);

            TableColumnModel tcm = table.getColumnModel();
            tcm.getColumn(0).setCellEditor(comboEditor);

            JFrame frame = new JFrame("Testing");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.add(new JScrollPane(table));
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        });
    }
}