Selección de múltiples filas en JTable

Tengo una JTable, que tiene una columna que es texto que no se puede editar y la segunda columna es una checkbox que muestra valores booleanos … Ahora lo que quiero es que el usuario seleccione múltiples filas y desmarque cualquiera de las casillas de verificación seleccionadas, luego todas las casillas de verificación debajo de la selección deben desmarcarse y viceversa.

Usando el ejemplo de @Hovercraft y el consejo de @camickr, el ejemplo a continuación muestra una interfaz de usuario adecuada. Aunque utiliza botones, SelectionAction también sería adecuado para un menú o ventana emergente.

Compruebe un manojo

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

El problema es que cuando hace clic en una checkbox para cambiar el valor de la checkbox, se perderá la selección de todas las filas. Por lo tanto, puede necesitar hacer clic con el botón derecho del mouse para mostrar un menú emergente que contiene valores de selección / anulación de selección.

Luego puede usar table.getSelectedRows (), para obtener los índices de todas las filas seleccionadas que necesita actualizar.

Puede obtener el intervalo de selección con un código similar al siguiente:

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

Luego, cuando se ItemEvent una checkbox (escuchar ItemEvent ) debe iterar desde el minSelectedRow al maxSelectedRow y cambiar el recuadro marcado. Eso es.

Estoy de acuerdo con Roman en que su idea funcionaría si usa un campo de clase para mantener la selección mínima y máxima. Por ejemplo:

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