1

I have a JTable where the user should be able to select only a single row, but whenever a row is selected by the user, some other rows (that are related according to some logic) should also be selected programmatically. The problem is that if I set the selection mode of the table to ListSelectionModel.SINGLE_SELECTION, addRowSelectionInterval will also select only one row. Any ideas?

EDIT: I think all ideas (custom selection model, clearing all but last user selections, custom renderer for highlighting) were good, but the best is to use SwingX, because it doesn't require much infrastructure-code, only a clever usage of the library. (and it's easy to be clever when a SwingX-guru is helping :)

lbalazscs
  • 17,474
  • 7
  • 42
  • 50
  • You'll probably want to look at replacing the selection manager – MadProgrammer Aug 17 '12 at 10:34
  • you'll confuse your users - how would they differentiate those selected by themselves and the magically selected others? – kleopatra Aug 17 '12 at 10:41
  • Sorry selection model :P long day – MadProgrammer Aug 17 '12 at 10:42
  • kleopatra: the users know that the rows are related. And after the selection is made, something will happen with all related rows. – lbalazscs Aug 17 '12 at 10:54
  • hmm ... would it okay to visually select (aka: highlight) to related rows, without actually selecting them? You'll need the "related" logic separately from the "selection", anyway. – kleopatra Aug 17 '12 at 11:43
  • yes, if they look selected, it is just as good as when they "are" selected :) mKorbel is also suggesting a highlight-only. This project does not use swingx, but if this is much easier with a JXTable, I would consider adding another dependency... – lbalazscs Aug 17 '12 at 12:00

3 Answers3

3

Biased me would say: certainly much easier in SwingX :-)

All you need is

  • a custom HighlightPredicate which decides about what is related
  • a ColorHighlighter configured with the selectionColors
  • set the custom predicate on receiving change notification from the selection model

Some code:

// the custom predicate
public static class RelatedHighlightPredicate implements HighlightPredicate {
    List<Integer> related;

    public RelatedHighlightPredicate(Integer... related) {
        this.related = Arrays.asList(related);

    }
    @Override
    public boolean isHighlighted(Component renderer,
            ComponentAdapter adapter) {
        int modelIndex = adapter.convertRowIndexToModel(adapter.row);
        return related.contains(modelIndex);
    }

}

// its usage
JXTable table = new JXTable(someModel);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
final ColorHighlighter hl = new ColorHighlighter(HighlightPredicate.NEVER, 
        table.getSelectionBackground(), table.getSelectionForeground());
table.addHighlighter(hl);
ListSelectionListener l = new ListSelectionListener() {

    @Override
    public void valueChanged(ListSelectionEvent e) {
        if (e.getValueIsAdjusting()) return;
        invokeUpdate((ListSelectionModel) e.getSource());
    }

    private void invokeUpdate(final ListSelectionModel source) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                int singleSelection = source.getMinSelectionIndex();
                if (singleSelection >= 0) {
                    int first = Math.max(0, singleSelection - 2);
                    int last = singleSelection + 2;
                    hl.setHighlightPredicate(new RelatedHighlightPredicate(first, last));
                } else {
                    hl.setHighlightPredicate(HighlightPredicate.NEVER);
                }
            }
        });

    }

};
table.getSelectionModel().addListSelectionListener(l);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
2

You might set multiselection possible for the table, but with each selection change - take only 1 (last selected) row, clear other selections and add your own computed selection.

Mikle Garin
  • 10,083
  • 37
  • 59
  • The other point I'd mention: You'll need a flag within your ListSelectionListener to state whether you are programmatically changing the selection and if so, do not react to selection events. Otherwise you'll end up in an infinite loop. – Adamski Aug 17 '12 at 10:42
  • @Adamski that is true aswell. Or just remove all the selection listeners while you perform the computed selected and store them back after. That might be better in case you have other selection listeners on that table. – Mikle Garin Aug 17 '12 at 10:56
2
  1. The problem is that if I set the selection mode of the table

    use ListSelectionModel.SINGLE_SELECTION for events came from mouse and keyborad

  2. some other rows (that are related according to some logic) should also be selected programmatically

    have look at Renderer for JTable, then required row(s), columns or whatever could be highlighted until programmatic rules stay unchanged

  3. ... maybe will help you

Community
  • 1
  • 1
mKorbel
  • 109,525
  • 20
  • 134
  • 319