JTable with selection restricted to only 2 rows

168 views Asked by At

I want to restrict the row selection in JTable to only 2 rows. If the user tries to select a third row (Ctrl + click), the oldest selection in the table should be programmatically deselected. To achieve this, I have added a ListSelectionListener to the table. In the following sample, the "clearSelection()" doesn't seem to work.

Please advice if there is a simpler or elegant way to achieve the same.

package test;

import java.util.Arrays;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

public class JTableDemo {
    public static void main(String[] argv) {
        Vector rowData = new Vector();
        for (int i = 0; i < 10; i++) {
            Vector colData = new Vector(Arrays.asList("row" + (i + 1)));
            rowData.add(colData);
        }

        String[] columnNames = { "header" };

        Vector columnNamesV = new Vector(Arrays.asList(columnNames));

        JTable table = new JTable(rowData, columnNamesV);
        table.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        table.setColumnSelectionAllowed(false);
        SelectionListener listener = new SelectionListener(table);
        table.getSelectionModel().addListSelectionListener(listener);

        JFrame f = new JFrame();
        f.setSize(300, 300);
        f.add(new JScrollPane(table));
        f.setVisible(true);
    }

    private static class SelectionListener implements ListSelectionListener {
        JTable table;
        int prevSelectedRow;
        int oldSelectedRow = -1;

        SelectionListener(JTable table) {
            this.table = table;
        }

        public void valueChanged(ListSelectionEvent e) {

            if (e.getValueIsAdjusting()) {
                return;
            }
            if (e.getSource() == table.getSelectionModel() && table.getRowSelectionAllowed()) {

                int[] selectedRows = table.getSelectedRows();

                if (selectedRows.length == 1) {
                    prevSelectedRow = selectedRows[0];
                    return;
                }

                if (selectedRows.length > 1) {
                    int currentSelectedRow = -1;
                    System.out.println("The first and last indexes are : " + e.getFirstIndex() + ", " + e.getLastIndex());

                    if (oldSelectedRow == -1) {
                        for (int i = 0; i < selectedRows.length; i++) {
                            if (prevSelectedRow != selectedRows[i]) {
                                currentSelectedRow = selectedRows[i];
                                break;
                            }
                        }
                        table.getSelectionModel().removeListSelectionListener(this);
                        table.clearSelection();
                        table.setRowSelectionInterval(prevSelectedRow, prevSelectedRow);
                        oldSelectedRow = prevSelectedRow;
                        prevSelectedRow = currentSelectedRow;
                        table.addRowSelectionInterval(currentSelectedRow, currentSelectedRow);
                        table.getSelectionModel().addListSelectionListener(this);
                    } else {
                        for (int i = 0; i < selectedRows.length; i++) {
                            if (prevSelectedRow != selectedRows[i] && oldSelectedRow != selectedRows[i]) {
                                currentSelectedRow = selectedRows[i];
                                break;
                            }
                        }

                        table.getSelectionModel().removeListSelectionListener(this);
                        table.clearSelection();
                        table.setRowSelectionInterval(prevSelectedRow, prevSelectedRow);
                        oldSelectedRow = prevSelectedRow;
                        prevSelectedRow = currentSelectedRow;
                        table.addRowSelectionInterval(currentSelectedRow, currentSelectedRow);
                        table.getSelectionModel().addListSelectionListener(this);
                    }

                }

            }

        }
    }
}
2

There are 2 answers

0
camickr On

Please advice if there is a simpler or elegant way to achieve the same.

You can extend the DefaultListSelectionModel and override the addSelectionInterval(...) method. Then you add you custom selection model to the table.

0
VijayV On

Thanks for the replies. I have tried to override "addSelectionInterval(...)" method but couldn't resolve my problem.

Instead of "clearSelection()", I have used "removeRowSelectionInterval(...)" and that seems to work as expected.

...
if (selectedRows.length > 1) {
    int currentSelectedRow = -1;
    System.out.println("The first and last indexes are : " + e.getFirstIndex() + ", " + e.getLastIndex());

    if (oldSelectedRow == -1) {
        for (int i = 0; i < selectedRows.length; i++) {
            if (prevSelectedRow != selectedRows[i]) {
                currentSelectedRow = selectedRows[i];
                break;
            }
        }
        table.getSelectionModel().removeListSelectionListener(this);
        //table.clearSelection();
        table.setRowSelectionInterval(prevSelectedRow, prevSelectedRow);
        oldSelectedRow = prevSelectedRow;
        prevSelectedRow = currentSelectedRow;
        table.addRowSelectionInterval(currentSelectedRow, currentSelectedRow);
        table.getSelectionModel().addListSelectionListener(this);
    } else {
        for (int i = 0; i < selectedRows.length; i++) {
            if (prevSelectedRow != selectedRows[i] && oldSelectedRow != selectedRows[i]) {
                currentSelectedRow = selectedRows[i];
                break;
            }
        }

        table.getSelectionModel().removeListSelectionListener(this);
        //table.clearSelection();
        table.removeRowSelectionInterval(oldSelectedRow, oldSelectedRow);
        table.setRowSelectionInterval(prevSelectedRow, prevSelectedRow);
        oldSelectedRow = prevSelectedRow;
        prevSelectedRow = currentSelectedRow;
        table.addRowSelectionInterval(currentSelectedRow, currentSelectedRow);
        table.getSelectionModel().addListSelectionListener(this);
    }
}
...