I have been bitten. ListSelectionListener.valueChanged is called more than once when a selection in a List/Tree/Table is changed. After some googling, I found out that I'm not alone.

The fix is quick enough, but I was curious about why was happening, so I hacked up the following test program:

package org.soronthar.spikes;

import javax.swing.*;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.ListSelectionEvent;

public class ListSelectionSpike extends JFrame {

public static void main(String[] args) {
ListSelectionSpike spike = new ListSelectionSpike();
spike.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JList jList = new JList(new String[]{"One", "Two", "Three"});
jList.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting()) {
System.out.print("Adjusting ");
}
System.out.println("f:" + e.getFirstIndex() + " l:" + e.getLastIndex());
}
});
spike.getContentPane().add(jList);
spike.pack();
spike.setVisible(true);
}
}
After some toying, I found out that valueChanged is called once each time the mouse is pressed and the selection changes without releasing the mouse, and once more when the mouse is released. That means that if you press the mouse, move over all the elements of a list and then release the mouse, valueChanged will be called once for each element plus once at the end (n+1 calls).

If you change the selection using the keyboard, then it gets called once.

I checked the javadocs for ListSelectionListener and the Swing tutorial, and it seems that this behavior is not documented.

After some more digging, I found out that it was even reported as a bug long time ago, and it was closed as "not a bug".
The workaround? Implement your valueChanged method as follows:
           public void valueChanged(ListSelectionEvent e) {
if (!e.getValueIsAdjusting()) {
//do my stuff
}
}
The key is that while the mouse is pressed, all the ListSelectionEvents will return true for the e.getValueIsAdjusting() call, and will only return false when the mouse is released. For keyboard operations, it always returns false.

Hope this helps someone. Happy coding!

No TrackBacks

TrackBack URL: http://tech.soronthar.com/mt/mt-tb.cgi/40

10 Comments

| Leave a comment

Thank you, it did help : )

It helped me too.

Thank You Very Much!
Just as an Inspiration: You Do a Lot of Help to Newbies! God Bless You for That:)

user-pic

When we press "Enter" key, the selection is changing to the next row, due to ListSelectionListener()

Could you please let me know the reason.

user-pic

yes! u help me! ty so much =D

Thanks, it really help me solved my problem.

JAjaja thx, u help me!

Thanks! It helped me too!

user-pic

Thanks a lot. It helped me!!! :)

Leave a comment