Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

seletion behavior on insert of rows in a JTable?

4 views
Skip to first unread message

Gabriel Belingueres

unread,
Jul 23, 2001, 4:45:32 PM7/23/01
to
Hi,

When I add a new row to my JTable, the previous selected rows are
deselected or they keep selected?

I ask this because I have a problem with that. I've added a
ListSelectionListener subclass listenening on the ListSelectionModel
(which is an instance of DefaultListSelectionModel by default).

When I add, remove or change the order of the table (using the
TableMap and TableSorter classes that I found in an example), the
selected rows are deselected. What can it be?

Also, I need some explanation about the getValueIsAdjusting() method.
When it returns true and when returns false?

Thanks in advance
Gabriel

Christian Kaufhold

unread,
Jul 23, 2001, 6:01:33 PM7/23/01
to
Gabriel Belingueres <ga...@ieee.org> wrote:

> When I add a new row to my JTable, the previous selected rows are
> deselected or they keep selected?

They are kept (there was an off-by-one bug that shifted indices
subsequent to the selection by one).


> I ask this because I have a problem with that. I've added a
> ListSelectionListener subclass listenening on the ListSelectionModel
> (which is an instance of DefaultListSelectionModel by default).

> When I add, remove or change the order of the table (using the
> TableMap and TableSorter classes that I found in an example), the
> selected rows are deselected. What can it be?

TableSorter is dumb and fires non-specific events. The JTable must
assume that the contents of all rows have been changed and that it
doesn't make purpose to retain the selection.

Doing it with more fine-grained events is a little tricky.


> Also, I need some explanation about the getValueIsAdjusting() method.
> When it returns true and when returns false?

It returns true when the ListSelectionModel has been set to be in that
state.

Basically, all changes of indices are sent twice if it is enabled, once
with it being true, once false. For false-events, events are collapsed
so that you may only be informed later of a change. Only process events
with getValueIsAdjusting() false when immediate reactions are not im-
portant, but efficiency is..

Christian
--
Homer: I saw this in a movie about a bus that had to speed around the city,
keeping its speed over fifty. And if its speed dropped, the bus
would explode! I think it was called... "The bus that couldn't slow
down." 3G01, "The Springfield Files"

Gabriel Belingueres

unread,
Jul 24, 2001, 8:29:27 AM7/24/01
to
use...@chka.de (Christian Kaufhold) wrote in message news:<0t3b5c9d...@simia.chka.de>...

> Gabriel Belingueres <ga...@ieee.org> wrote:
>
> > When I add a new row to my JTable, the previous selected rows are
> > deselected or they keep selected?
>
> They are kept (there was an off-by-one bug that shifted indices
> subsequent to the selection by one).

In which JDK version was the bug? I'm working with JDK 1.3.0 SE.

> > I ask this because I have a problem with that. I've added a
> > ListSelectionListener subclass listenening on the ListSelectionModel
> > (which is an instance of DefaultListSelectionModel by default).
>
> > When I add, remove or change the order of the table (using the
> > TableMap and TableSorter classes that I found in an example), the
> > selected rows are deselected. What can it be?
>
> TableSorter is dumb and fires non-specific events. The JTable must
> assume that the contents of all rows have been changed and that it
> doesn't make purpose to retain the selection.
>
> Doing it with more fine-grained events is a little tricky.

TableMap fires TableChanged(TableModelEvent e), but this event is
setted by the TableModel and can specify a couple of parameters that
had changed, not only if the table model changed or not in some way.

Shouldn't be this sufficient?

Christian Kaufhold

unread,
Jul 24, 2001, 2:35:38 PM7/24/01
to
Gabriel Belingueres <ga...@ieee.org> wrote:
> use...@chka.de (Christian Kaufhold) wrote in message news:<0t3b5c9d...@simia.chka.de>...
>> Gabriel Belingueres <ga...@ieee.org> wrote:
>>
>> > When I add a new row to my JTable, the previous selected rows are
>> > deselected or they keep selected?
>>
>> They are kept (there was an off-by-one bug that shifted indices
>> subsequent to the selection by one).

> In which JDK version was the bug? I'm working with JDK 1.3.0 SE.

I was wrong, it was in JList and not in JTable. Sorry.


[...]

> TableMap fires TableChanged(TableModelEvent e), but this event is
> setted by the TableModel and can specify a couple of parameters that
> had changed, not only if the table model changed or not in some way.

Yes, it really does, but that is wrong (I assumed at least that would
be something they got right). Whenever TableSorter receives
an event, it destroys the sorted order and goes back to original order,
so that in general, *all indices* have been changed, but that isn't
contained in the event (which also has a wrong source).

The only way to do it properly would be to convert the event somehow
on the way, but TableSorter doesn't even do that.

But the selection should be retained if the original model fires spe-
cific events, only that the actual data in the indices has changed
(and that is not announced by TableSorter).

Where exactly do you have problems with selection getting lost?


Christian

Gabriel Belingueres

unread,
Jul 25, 2001, 8:54:26 AM7/25/01
to
use...@chka.de (Christian Kaufhold) wrote in message news:<1t3b5dbe...@simia.chka.de>...

The source of the problem (I think) is that when in the TableSorter a
row is added, removed or updated, it fires an fireTableChanged() event
and this event makes the JTable updates all and, since all rows and
columns could be changed, the ListSelectionModel erases all the
selections.

I modified my code and now the selections remain, only that a new
problem appears:
When a row is updated, added or removed, the TableSorter sorts its
rows, and the rows can change in the order that are viewed by the
JTable, but the selected rows (in the JTable) are in the same indexes,
when it should change the order according to the changes in the model.
I don't know how to fix that, without having an extra vector of
booleans with the selected indexes and then iterate over all the
vector to re-select the rows.

Any ideas?

Gabriel

Christian Kaufhold

unread,
Jul 25, 2001, 11:53:06 AM7/25/01
to
Gabriel Belingueres <ga...@ieee.org> wrote:
> use...@chka.de (Christian Kaufhold) wrote in message news:<1t3b5dbe...@simia.chka.de>...

[...]

>> Where exactly do you have problems with selection getting lost?

> The source of the problem (I think) is that when in the TableSorter a
> row is added, removed or updated, it fires an fireTableChanged() event
> and this event makes the JTable updates all and, since all rows and
> columns could be changed, the ListSelectionModel erases all the
> selections.

It does then when it has just sorted the data, not when the original
data changed. Then it forwards the original event, which is typically
completely wrong. Things aren't that easy:

- for row additions, add the rows somewhere (at the end in the most
simple way), fix the "indexes" array, convert the event to reflect
the rows where the insertion was
- for row removals, remove the corresponding rows. Typically they are
not consecutive, so one must fire a change for the complete data
(running into a JTable bug with different row heights)
- for row/cell changes, figure out where the rows really are and
fire event(s) for those rows.
- for complete data changes: if the size changed, the "indexes" don't
make sense anymore. Go back to original order, and forward the event
if the size didn't change, the permutation could be retained
(but it doesn't really make sense).
- for structural changes: as for complete data changes.

> I modified my code and now the selections remain, only that a new
> problem appears:
> When a row is updated, added or removed, the TableSorter sorts its
> rows, and the rows can change in the order that are viewed by the
> JTable, but the selected rows (in the JTable) are in the same indexes,
> when it should change the order according to the changes in the model.
> I don't know how to fix that, without having an extra vector of
> booleans with the selected indexes and then iterate over all the
> vector to re-select the rows.


When sorting, keep track of the permutation that is applied to the data,
sent that along with the event, then let a subclass of JTable permute
the selection (and the row heights) according to the permutation.


Christian
--
Tarzan un er kannte sämtliche Tricks
durch dausend Heffjer nur Siejer - sons nix.
BAP, Fortsetzung folgt

Gabriel Belingueres

unread,
Jul 26, 2001, 8:34:02 AM7/26/01
to
use...@chka.de (Christian Kaufhold) wrote in message news:<3t3b5ee9...@simia.chka.de>...

What I did was to keep a hashtable of the selected rows (I capture the
selected rows adding a ListSelectionListener to the JTable). Also is
TableSorter I added an int inverseIndex[] vector that keeps track of
the inverse relation between the model and the ordering in the
TableSorter.
So, when a change in the selectionss ocurrs, I iterate the hashtable
selecting one by one the rows.

Not I nice solution, I know. But creating a new event every time a new
permutation happens when sorting the table seems not too much lighter
than what I did.

I read on the net somewhere that the ideal solution would be to set
the selectionModel to one with the methods insertIndexInterval and
removeIndexInterval, and delegating to the original selection model
the rest of the methods. The only problem is that I don't know how
those methods work :(
Do you?

Gabriel

Christian Kaufhold

unread,
Jul 26, 2001, 12:20:53 PM7/26/01
to
Gabriel Belingueres <ga...@ieee.org> wrote:
> use...@chka.de (Christian Kaufhold) wrote in message news:<3t3b5ee9...@simia.chka.de>...

[...]

>> When sorting, keep track of the permutation that is applied to the data,
>> sent that along with the event, then let a subclass of JTable permute
>> the selection (and the row heights) according to the permutation.

> What I did was to keep a hashtable of the selected rows (I capture the
> selected rows adding a ListSelectionListener to the JTable). Also is
> TableSorter I added an int inverseIndex[] vector that keeps track of
> the inverse relation between the model and the ordering in the
> TableSorter.
> So, when a change in the selectionss ocurrs, I iterate the hashtable
> selecting one by one the rows.

> Not I nice solution, I know. But creating a new event every time a new
> permutation happens when sorting the table seems not too much lighter
> than what I did.

You would have to create a new event anyway, since you need to fire
a change for all rows (since most of them obviously have changed, and
figuring out which have not would a) cause multiple events, b) be more
complicated).

You only need a permutation (roughly the size of an int array with
row count length) which could even be reused for all events.


A major advantage is that the TableModel sorting code need not have
knowledge of any ListSelectionModel(s), JTable(s) other components
and models etc. that may use it, and *any* listener that knows about
the extended event may know that the data has not really changed, but
only permuted. It can used with any ListSelectionModel, and only
requires some lines (run-down, shortened form of the real code).


class PermutationTableModelEvent
extends TableModelEvent
{
private int[] permutation;

public PermutationTableModelEvent(TableModel source, int[] p)
{
super(source, 0, source.getRowCount());

permutation = p;
}

public int[] permutation()
{
return permutation;
}
}

(This is unsafe, the array may be changed. I use a Permutation class
instead of an array that is readonly)


class XTable
extends JTable
{
// some constructors

private boolean hasRowModel;


public void setRowHeight(int row, int height)
{
super.setRowHeight(row, height);

hasRowModel = true;
}

public void setRowHeight(int height)
{
super.setRowHeight(height);

hasRowModel = false;
}


public void tableChanged(TableModelEvent e)
{
if (e instanceof PermutationTableModelEvent)
{
int[] permutation
= ((PermutationTableModelEvent)e).permutation();

int size = permutation.length;


ListSelectionModel selection = getSelectionModel();

boolean old = selection.getValueIsAdjusting();
selection.setValueIsAdjusting(true);

int[] array = getSelectedRows();

int lead = selection.getLeadSelectionIndex(),
anchor = selection.getAnchorSelectionIndex();


selection.clearSelection();

for (int i = 0; i < array.length; i++)
selection.addSelectionInterval(permutation[i], permutation[i]);

if (lead != -1)
// Skip this line with DefaultListSelectionModel, which
// produces chaos then.
selection.setLeadSelectionIndex(permutation[lead]);
if (anchor != -1)
selection.setAnchorSelectionIndex(permutation[anchor]);

selection.setValueIsAdjusting(old);


if (hasRowModel)
{
int[] heights = new int[size];

for (int i = 0; i < size; i++)
heights[i] = getRowHeight(i);

for (int i = 0; i < size; i++)
setRowHeight(permutation[i], heights[i]);
}

repaint();
}
else
super.tableChanged(e);
}
}


> I read on the net somewhere that the ideal solution would be to set
> the selectionModel to one with the methods insertIndexInterval and
> removeIndexInterval, and delegating to the original selection model
> the rest of the methods. The only problem is that I don't know how
> those methods work :(
> Do you?

Yes. Been there, done that. It really gets messy. Basically the List-
SelectionModel does the mapping row indices -> original indices. Then
insert/removeIndexInterval don't do anything (since that is implicitly
done by the change of the TableModel), all the others map the index
arguments/return values on the way. It makes the ListSelectionModel
behave in non-obvious ways sometimes, even if one uses careful logic,
and ties many things more together than needed.

Christian
--
Your mornings will be brighter
Break the line
Tear up rules
Make the most of a million times no Bauhaus, Hope

0 new messages