Jslider fire two events (not one) with getValueIsAdjusting andsetSnapToTicks(true)

E

etantonio

Good Evening,
I've a problem with jslider and its method getValueIsAdjusting, I also
use slider.setSnapToTicks(true)
in a way that the slider can only choose 3 different values, one in
the middle and the other at the extremity of the slider, the problem
is that when I bring the slider to one of these 3 values I've not just
an event fired but two.
Can you help me to solve this problem ?
Thanks,

Antonio
www.etantonio.it/en

Here's the code not working:

public class CommandPanel extends JPanel implements ChangeListener{

public CommandPanel() {
BorderLayout borderLayout = new BorderLayout();
this.setLayout(borderLayout);
JLabel sliderLabel = new JLabel("Direzione Rotazione",
JLabel.CENTER);
sliderLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
//Create the slider.
JSlider slider = new JSlider(JSlider.HORIZONTAL, 0, 359, 180);
slider.setMajorTickSpacing(180);
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setSnapToTicks(true);
slider.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
slider.setFont(new Font("Serif", Font.ITALIC, 15));
slider.setBackground(Constants.BACKGROUND_CONTROL_PANEL);
Hashtable<Integer, JLabel> labelTable = new Hashtable<Integer,
JLabel>();
labelTable.put( new Integer( 0 ), new JLabel("Rotazione verso
Sinistra") );
labelTable.put( new Integer( 180 ), new JLabel("Fermo") );
labelTable.put( new Integer( 359 ), new JLabel("Rotazione verso
Destra") );
slider.setLabelTable( labelTable );
slider.addChangeListener(this);
add(sliderLabel, BorderLayout.NORTH);
add(slider, BorderLayout.CENTER);

setBorder(BorderFactory.createTitledBorder(null, " Pannello Comandi
", TitledBorder.LEFT, TitledBorder.TOP, new java.awt.Font("Verdana",
3,14)));
setBackground(Constants.BACKGROUND_CONTROL_PANEL);
}

/** Listen to the slider. */
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int iValue = (int)source.getValue();
BigDecimal bdValue = new BigDecimal(iValue);
int i2bit = bdValue.divide(BigDecimal.valueOf(5.625) ,
BigDecimal.ROUND_DOWN).intValue();
CommandFrame.getInstance().setSelectedPosition(i2bit);
System.out.println("ACS Comando Posizione valore dello
slider = " + bdValue + " valore codificato = " + i2bit);
}
}


}
 
J

John B. Matthews

[...]
I've a problem with jslider and its method getValueIsAdjusting, I
also use slider.setSnapToTicks(true) in a way that the slider can
only choose 3 different values, one in the middle and the other at
the extremity of the slider, the problem is that when I bring the
slider to one of these 3 values I've not just an event fired but two.
Can you help me to solve this problem?

I am unable to reproduce this effect using the mouse, although I do see
two identical change events for some keyboard actions, e.g. the left-
and right-arrow keys. The first event is the attempt to change to a new
value; the second is the snap back. In either case, it should be trivial
to ignore duplicates, as the values are fixed.

Alternatively, you might eschew setSnapToTicks() completely and use just
three integral values with custom labels. Your event handler would
translate 0..2 into the preferred angular measure:

<http://java.sun.com/docs/books/tutorial/uiswing/components/slider.html>

[...]
 
E

etantonio

[...]
I've a problem with jslider and its method getValueIsAdjusting, I
also use slider.setSnapToTicks(true) in a way that the slider can
only choose 3 different values, one in the middle and the other at
the extremity of the slider, the problem is that when I bring the
slider to one of these 3 values I've not just an event fired but two.
Can you help me to solve this problem?

I am unable to reproduce this effect using the mouse, although I do see
two identical change events for some keyboard actions, e.g. the left-
and right-arrow keys. The first event is the attempt to change to a new
value; the second is the snap back. In either case, it should be trivial
to ignore duplicates, as the values are fixed.

Alternatively, you might eschew setSnapToTicks() completely and use just
three integral values with custom labels. Your event handler would
translate 0..2 into the preferred angular measure:

<http://java.sun.com/docs/books/tutorial/uiswing/components/slider.html>

[...]

Hope in a next java release this problem will be solved.
Thanks John
 
B

blue indigo

Hope in a next java release this problem will be solved.
Thanks John

A lot of Swing components can generate multiple events when used. One
common situation is if you change something in an event handler, which
causes another event to be sent.

It's a good idea to defensively program around this by making your event
listeners non-recursive and possibly making them cascade changes.

In your case, the slider gets two events for having "changed" to the same
value, so the second time, the value hasn't changed.

Example pseudo-Java for a listener that handles both problems:

private static class MyFooListener {
private boolean entered = false;
private int lastValue = 0; // Or whatever the starting value is.
public void FooHappened (FooEvent e) {
if (entered) return;
final int value = e.getValue();
if (value == lastValue) return;
try {
entered = true;
lastValue = value;
doSomethingWith(value);
SomeSwingControl.twiddleBits(value*17-3);
} finally {
entered = false;
}
}
}

If the value is unchanged, it exits without doing anything. If
twiddleBits() (or doSomethingWith()) directly or indirectly causes another
FooEvent caught by this same listener, the recursive invocation
immediately exits because entered is true at the start of that invocation.
Finally, even if an exception is thrown entered gets put back to false at
the end, so the listener never gets stuck in a "deaf" state. The one thing
it's not is thread-safe, but it should only get called on the EDT anyway.
 
E

etantonio

A lot of Swing components can generate multiple events when used. One
common situation is if you change something in an event handler, which
causes another event to be sent.

It's a good idea to defensively program around this by making your event
listeners non-recursive and possibly making them cascade changes.

In your case, the slider gets two events for having "changed" to the same
value, so the second time, the value hasn't changed.

Example pseudo-Java for a listener that handles both problems:

private static class MyFooListener {
    private boolean entered = false;
    private int lastValue = 0; // Or whatever the starting value is..
    public void FooHappened (FooEvent e) {
        if (entered) return;
        final int value = e.getValue();
        if (value == lastValue) return;
        try {
            entered = true;
            lastValue = value;
            doSomethingWith(value);
            SomeSwingControl.twiddleBits(value*17-3);
        } finally {
            entered = false;
        }
    }

}

If the value is unchanged, it exits without doing anything. If
twiddleBits() (or doSomethingWith()) directly or indirectly causes another
FooEvent caught by this same listener, the recursive invocation
immediately exits because entered is true at the start of that invocation..
Finally, even if an exception is thrown entered gets put back to false at
the end, so the listener never gets stuck in a "deaf" state. The one thing
it's not is thread-safe, but it should only get called on the EDT anyway.

Thanks, it works fine ,
simple and effcient


Antonio
www.etantonio.it/forums/varie
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

aliasing 0
Help in Java swings(internal Frame) 2
problem in java swings 0

Members online

Forum statistics

Threads
473,999
Messages
2,570,246
Members
46,839
Latest member
MartinaBur

Latest Threads

Top