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);
});
}
}
我在这里潜伏了几年左右,以前从来不需要问问题,因为我总是在别人的问题中找到我的答案。谢谢!
我想潜伏已经结束了。我在这里看到过类似的问题,但不完全是这种情况: 我有一个 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);
});
}
}