Selecting multiple rows using checkbox in JTable

I have a JTable with a checkbox as one of the columns. I also have a checkbox in the title to check / unmark all. AFAIK default behavior JTable by default deselects all selected rows if you select a new row. But can we reach CTRL click like behavior with a checkbox? This saves the previously selected row. The main problem I am facing is to enable multiple selection of JTable strings with a checkbox.

Expected Result

The 1st row is checked, then the first row is selected, and if the third row is checked, then the third row is selected along with the first row (which has already been checked and selected)

Actual output

When the first row is checked and selected, and if you select the third row, it deselects all previously selected rows and only the third is selected.

I have an example code that simulates a script that I want to achieve in the same way as the Add Another One button, but with a checkbox selected.

import javax.swing.*; import javax.swing.event.ListSelectionEvent; import javax.swing.table.AbstractTableModel; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.event.ListSelectionListener; import javax.swing.table.TableColumn; import javax.swing.event.CellEditorListener; public class JTableRowSelectProgramatically extends JPanel { final JTable table = new JTable(new MyTableModel()); public JTableRowSelectProgramatically() { initializePanel(); } private void initializePanel() { setLayout(new BorderLayout()); setPreferredSize(new Dimension(475, 150)); table.setFillsViewportHeight(true); JScrollPane pane = new JScrollPane(table); JLabel label2 = new JLabel("Row: "); final JTextField field2 = new JTextField(3); JButton add = new JButton("Select"); table.setRowSelectionAllowed(true); table.setColumnSelectionAllowed(false); table.getSelectionModel().addListSelectionListener(new ListSelectionListenerImpl()); TableColumn tc = table.getColumnModel().getColumn(3); tc.setCellEditor(table.getDefaultEditor(Boolean.class)); tc.setCellRenderer(table.getDefaultRenderer(Boolean.class)); ((JComponent) table.getDefaultRenderer(Boolean.class)).setOpaque(true); tc.getCellEditor().addCellEditorListener(new CellEditorListenerImpl()); add.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent event) { int index2 = 0; try { index2 = Integer.valueOf(field2.getText()); } catch (NumberFormatException e) { e.printStackTrace(); } table.addRowSelectionInterval(index2, index2); field2.setText(String.valueOf(index2)); } }); JPanel command = new JPanel(new FlowLayout()); command.add(label2); command.add(field2); command.add(add); add(pane, BorderLayout.CENTER); add(command, BorderLayout.SOUTH); } public static void showFrame() { JPanel panel = new JTableRowSelectProgramatically(); panel.setOpaque(true); JFrame frame = new JFrame("JTable Row Selection"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setContentPane(panel); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { JTableRowSelectProgramatically.showFrame(); } }); } public class MyTableModel extends AbstractTableModel { private String[] columns = {"ID", "NAME", "AGE", "A STUDENT?"}; private Object[][] data = { {1, "Alice", 20, new Boolean(false)}, {2, "Bob", 10, new Boolean(false)}, {3, "Carol", 15, new Boolean(false)}, {4, "Mallory", 25, new Boolean(false)} }; public int getRowCount() { return data.length; } public int getColumnCount() { return columns.length; } public Object getValueAt(int rowIndex, int columnIndex) { return data[rowIndex][columnIndex]; } @Override public String getColumnName(int column) { return columns[column]; } @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == 3; } // // This method is used by the JTable to define the default // renderer or editor for each cell. For example if you have // a boolean data it will be rendered as a check box. A // number value is right aligned. // @Override public Class<?> getColumnClass(int columnIndex) { return data[0][columnIndex].getClass(); } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex == 3) { data[rowIndex][columnIndex] = aValue; fireTableCellUpdated(rowIndex, columnIndex); } } } class ListSelectionListenerImpl implements ListSelectionListener { public void valueChanged(ListSelectionEvent lse) { ListSelectionModel lsm = (ListSelectionModel) lse.getSource(); int row = table.getRowCount(); if (lsm.isSelectionEmpty()) { } else { // If any column is clicked other than checkbox then do normal selection // ie select the click row and deselects the previous selection if (table.getSelectedColumn() != 3) { for (int i = 0; i < row; i++) { if (lsm.isSelectedIndex(i)) { table.setValueAt(true, i, 3); } else { table.setValueAt(false, i, 3); } } } } } } public class CellEditorListenerImpl implements CellEditorListener{ public void editingStopped(ChangeEvent e) { for(int i=0; i<table.getRowCount();i++){ if((Boolean)table.getValueAt(i, 3)){ table.addRowSelectionInterval(i, i); } else{ table.removeRowSelectionInterval(i, i); } } } public void editingCanceled(ChangeEvent e) { System.out.println("do nothing"); } } } 

+4
source share
2 answers

Once you implement these TableModel methods, you can use setValueAt() in your button listeners so that the model conditions match the need to maintain the state of the flag and the selection model synchronously. Here is an example here .

 @Override public boolean isCellEditable(int rowIndex, int columnIndex) { return columnIndex == 3; } @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if (columnIndex == 3) { data[rowIndex][columnIndex] = aValue; fireTableCellUpdated(rowIndex, columnIndex); } } 

Appendix: As a specific example, your clear listener can call a method in TableModel , for example clearChecks() :

 MyTableModel model = (MyTableModel) table.getModel(); model.clearChecks(); ... private void clearChecks() { for (int i = 0; i < data.length; i++) { data[i][3] = false; } fireTableRowsUpdated(0, data.length); } 
+3
source

At a high level, I would call a key listener and check if VK_CTRL is checked when inside your select listener. This sounds like a logic block problem or a listener conflict.

Prevents the JList field from being multiple-selectable.

0
source

Source: https://habr.com/ru/post/1413466/


All Articles