Get selected rows in JTable using AbstractTableModel

I have a JTable using AbstractTableModel , where I have a JCheckBox in the first column to select rows. Now I need to get the selected rows from the table that have been checked. Right now, I sequentially traverse from the first row to the last row and get all the rows that are selected as follows:

 List<Integer> selectedRows = new ArrayList<Integer>(); for(int i = 0; i < table.getRowCount(); i++) { if((Boolean) table.getValuAt(i, 0)) { selectedRows.add(i); } } 

The problem here is that I need to go through all the lines when I need to get the selected lines. Now I have 10 to 20 lines. But in the future I will get about 5,000 rows. My question is: if there are 5000 rows, and if the user selects only the 5000th (last record), then I need to go through all 5000 rows to get the selected row. I think this is not a very good approach.

One approach that I want to implement is to add a listener to the JCheckBox column JCheckBox that a change (SELECTED/DESELECTED) , then I need to update my array of selected rows in the listener class. In this listener class, when the user selects the JCheckBox , I need to call table.getSelectedRow(..) , and I need to save if this JCheckBox selected.

Are there any better approaches?

+4
source share
2 answers

In the example below, TableModel updates a Set<Integer> checked in the implementation of setValueAt() . The adjacent JList model listens on the table model and displays the currently selected row numbers. The example assumes that the number of rows selected is small compared to the number of rows. Pay attention to the use of TreeSet , the iterator of which preserves the natural order of elements.

image

 import java.awt.Dimension; import java.awt.EventQueue; import java.awt.GridLayout; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; /** @see http://stackoverflow.com/a/13919878/230513 */ public class CheckTable { private static final CheckModel model = new CheckModel(5000); private static final JTable table = new JTable(model) { @Override public Dimension getPreferredScrollableViewportSize() { return new Dimension(150, 300); } }; public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { JFrame f = new JFrame("CheckTable"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setLayout(new GridLayout(1, 0)); f.add(new JScrollPane(table)); f.add(new DisplayPanel(model)); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } }); } private static class DisplayPanel extends JPanel { private DefaultListModel dlm = new DefaultListModel(); private JList list = new JList(dlm); public DisplayPanel(final CheckModel model) { super(new GridLayout()); this.setBorder(BorderFactory.createTitledBorder("Checked")); this.add(new JScrollPane(list)); model.addTableModelListener(new TableModelListener() { @Override public void tableChanged(TableModelEvent e) { dlm.removeAllElements(); for (Integer integer : model.checked) { dlm.addElement(integer); } } }); } } private static class CheckModel extends AbstractTableModel { private final int rows; private List<Boolean> rowList; private Set<Integer> checked = new TreeSet<Integer>(); public CheckModel(int rows) { this.rows = rows; rowList = new ArrayList<Boolean>(rows); for (int i = 0; i < rows; i++) { rowList.add(Boolean.FALSE); } } @Override public int getRowCount() { return rows; } @Override public int getColumnCount() { return 2; } @Override public String getColumnName(int col) { return "Column " + col; } @Override public Object getValueAt(int row, int col) { if (col == 0) { return row; } else { return rowList.get(row); } } @Override public void setValueAt(Object aValue, int row, int col) { boolean b = (Boolean) aValue; rowList.set(row, b); if (b) { checked.add(row); } else { checked.remove(row); } fireTableRowsUpdated(row, row); } @Override public Class<?> getColumnClass(int col) { return getValueAt(0, col).getClass(); } @Override public boolean isCellEditable(int row, int col) { return col == 1; } } } 
+8
source

I agree with klepatra. When you subclass AbstractTableModel, you override setValue (value Object, int rowIndex, int colIndex). In your overridden method, you simply check to see if the column matches your checkbox, and if so, update the internal data structure accordingly. You can also add the getCheckedRows () method, which returns a List <Integer> with the rows in which the checkboxes were checked.

+3
source

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


All Articles