By Amarnath


2012-12-17 13:26:40 8 Comments

I have a JTable using AbstractTableModel where I have a JCheckBox in the first column for selecting rows. Now, I need to get the selected rows from the table which are checked. Right now, I am sequentially traversing from first row to the last row and getting all the rows that are selected like the following,

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, I need to traverse all the rows when ever I need to get the selected rows. Right now I am having 10 to 20 rows. But in future I will get around 5000 rows. My question is, if there are 5000 rows and if the user selects only 5000nd (last record) row then I need to traverse all the 5000 rows to get the selected row. Which I think is not a good approach.

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

Are there any better approaches ?

2 comments

@trashgod 2012-12-17 18:27:07

In the example below, the TableModel updates a Set<Integer> checked in the implementation of setValueAt(). The model of an adjacent JList listens to the table's model and displays the currently selected row numbers. The example assumes that the number of selected rows is small compared to the number of rows. Note the use of TreeSet, whose iterator retains the natural order of the 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;
        }
    }
}

@Amarnath 2012-12-18 02:35:31

+1 .. is it a good practice to write logic (getting the selected rows) in the model itself. B'coz all these days I am separating the TableModel from my logics.

@trashgod 2012-12-18 10:06:30

It's a trade-off, certainly worth profiling for large models. Also consider AbstractListModel for the JList or a shared model.

@Amarnath 2012-12-18 11:08:41

But I have an issue with this appraoach. When ever I delete some selected rows then those row numbrers have to be removed from the Set. But all the rows numbers in the Set that are having the previous row numbers will be inconsistent right? I have fuctionalities like delete, do_action, etc..

@Amarnath 2012-12-18 14:22:01

ok one solution which I can think is .. when ever I delete a row I will recreate the Set again and at one shot. So again it will come back to consistent state with all the selected rows.

@trashgod 2012-12-18 17:38:38

Yes that's the trade-off: once you have determined that it's too expensive to recreate the Set each time, then you have to keep the Set up to date for all insert, update or delete operations. Your AbstractTableModel is the place to do it. Set<Integer> was just for demonstration; you may want to look at Set<Row> or some other data structure that supports your intended operations.

@Amarnath 2012-12-19 03:43:12

Thanks for the time. I will try to figure out what Data Structure it best fits and post here if that appraoch is better than this.

@Rob Philipp 2012-12-17 14:03:57

I agree with kleopatra. When you create a subclass of the AbstractTableModel, you'll override the setValue( Object value, int rowIndex, int colIndex ). In your overridden method, you just check if the column is the one with your check box, and if so, update the internal data structure appropriately. You can also add a method getCheckedRows() that returns a List< Integer > with the rows in which the check boxes have been selected.

Related Questions

Sponsored Content

47 Answered Questions

[SOLVED] Does a finally block always get executed in Java?

1 Answered Questions

[SOLVED] Programmatically deselecting a row in JTable

4 Answered Questions

[SOLVED] Multiple row selection in JTable

2 Answered Questions

[SOLVED] Inserted Row Selection jTable

3 Answered Questions

[SOLVED] Listeneing for changes in JCheckBox in a JTable

1 Answered Questions

[SOLVED] Checkbox in Jtable with Dialog

3 Answered Questions

[SOLVED] Make a JCheckBox in a JTable editable

1 Answered Questions

[SOLVED] Listener for CheckBox in JTable

2 Answered Questions

[SOLVED] Multiple row selection with checkbox in JTable

  • 2012-05-21 04:10:05
  • rcnpl
  • 12333 View
  • 5 Score
  • 2 Answer
  • Tags:   java swing jtable

Sponsored Content