JTable中的多行select

我有一个JTable,有一列是不可编辑的文本,第二列是一个checkbox显示布尔值….现在我想要的是,当用户select多行并取消选中任何一个选中的checkbox,则选中的所有checkbox应该取消选中,反之亦然。

使用@ Hovercraft的例子和@ camickr的build议,下面的例子显示了一个合适的用户界面。 虽然它使用button,但SelectionAction也适用于菜单或popup窗口。

检查一堆

 import java.awt.*; import java.awt.event.ActionEvent; import javax.swing.*; import javax.swing.DefaultListSelectionModel; import javax.swing.table.DefaultTableModel; /** @see http://stackoverflow.com/questions/4526779 */ public class CheckABunch extends JPanel { private static final int CHECK_COL = 1; private static final Object[][] DATA = { {"One", Boolean.TRUE}, {"Two", Boolean.FALSE}, {"Three", Boolean.TRUE}, {"Four", Boolean.FALSE}, {"Five", Boolean.TRUE}, {"Six", Boolean.FALSE}, {"Seven", Boolean.TRUE}, {"Eight", Boolean.FALSE}, {"Nine", Boolean.TRUE}, {"Ten", Boolean.FALSE}}; private static final String[] COLUMNS = {"Number", "CheckBox"}; private DataModel dataModel = new DataModel(DATA, COLUMNS); private JTable table = new JTable(dataModel); private DefaultListSelectionModel selectionModel; public CheckABunch() { super(new BorderLayout()); this.add(new JScrollPane(table)); this.add(new ControlPanel(), BorderLayout.SOUTH); table.setPreferredScrollableViewportSize(new Dimension(250, 175)); selectionModel = (DefaultListSelectionModel) table.getSelectionModel(); } private class DataModel extends DefaultTableModel { public DataModel(Object[][] data, Object[] columnNames) { super(data, columnNames); } @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == CHECK_COL) { return getValueAt(0, CHECK_COL).getClass(); } return super.getColumnClass(columnIndex); } @Override public boolean isCellEditable(int row, int column) { return column == CHECK_COL; } } private class ControlPanel extends JPanel { public ControlPanel() { this.add(new JLabel("Selection:")); this.add(new JButton(new SelectionAction("Clear", false))); this.add(new JButton(new SelectionAction("Check", true))); } } private class SelectionAction extends AbstractAction { boolean value; public SelectionAction(String name, boolean value) { super(name); this.value = value; } @Override public void actionPerformed(ActionEvent e) { for (int i = 0; i < dataModel.getRowCount(); i++) { if (selectionModel.isSelectedIndex(i)) { dataModel.setValueAt(value, i, CHECK_COL); } } } } private static void createAndShowUI() { JFrame frame = new JFrame("CheckABunch"); frame.add(new CheckABunch()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowUI(); } }); } } 

问题是,当您单击一个checkbox来更改checkbox的值时,所有行的select将会丢失。 因此,您可能需要使用鼠标右键单击以显示包含select/取消select值的popup式菜单。

然后你可以使用table.getSelectedRows()来获取你需要更新的所有选定行的索引。

您可以使用类似于此的代码来获得select间隔:

 table.getSelectionModel().addListSelectionListener(new ListSelectionListener(){ public void valueChanged(ListSelectionEvent e) { minSelectedRow = ((DefaultListSelectionModel)e.getSource()).getMinSelectionIndex(); maxSelectedRow = ((DefaultListSelectionModel)e.getSource()).getMaxSelectionIndex(); } }); 

然后, minSelectedRow一个checkbox(监听ItemEvent )时,应该从minSelectedRow迭代到maxSelectedRow并更改checkbox的状态。 而已。

我同意Roman的观点,如果你使用class字段来保存最小和最大select,他的想法就会起作用。 例如:

 import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.DefaultTableModel; public class CheckABunch extends JPanel { private static final Object[][] DATA = {{"One", Boolean.TRUE}, {"Two", Boolean.FALSE}, {"Three", Boolean.TRUE}, {"Four", Boolean.FALSE}, {"Five", Boolean.TRUE}, {"Six", Boolean.FALSE}, {"Seven", Boolean.TRUE}, {"Eight", Boolean.FALSE}}; private static final String[] COLUMNS = {"Number", "CheckBox"}; private DefaultTableModel model = new DefaultTableModel(DATA, COLUMNS) { @Override public Class<?> getColumnClass(int columnIndex) { if (columnIndex == 1) { return getValueAt(0, 1).getClass(); } return super.getColumnClass(columnIndex); } }; private JTable table = new JTable(model); private int minSelectedRow = -1; private int maxSelectedRow = -1; boolean tableModelListenerIsChanging = false; public CheckABunch() { add(new JScrollPane(table)); table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) { return; } minSelectedRow = ((DefaultListSelectionModel) e.getSource()).getMinSelectionIndex(); maxSelectedRow = ((DefaultListSelectionModel) e.getSource()).getMaxSelectionIndex(); } }); model.addTableModelListener(new TableModelListener() { public void tableChanged(TableModelEvent e) { if (tableModelListenerIsChanging) { return; } int firstRow = e.getFirstRow(); int column = e.getColumn(); if (column != 1 || maxSelectedRow == -1 || minSelectedRow == -1) { return; } tableModelListenerIsChanging = true; boolean value = ((Boolean)model.getValueAt(firstRow, column)).booleanValue(); for (int i = minSelectedRow; i <= maxSelectedRow; i++) { model.setValueAt(Boolean.valueOf(value), i, column); } // *** edit: added two lines minSelectedRow = -1; maxSelectedRow = -1; tableModelListenerIsChanging = false; } }); } private static void createAndShowUI() { JFrame frame = new JFrame("CheckABunch"); frame.getContentPane().add(new CheckABunch()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { public void run() { createAndShowUI(); } }); } }