3

I have a simple JSlider with an attached ChangeListerner. Here's the code:

JSlider slider = new JSlider();
slider.setMinorTickSpacing(2);
slider.setMajorTickSpacing(20);
slider.setPaintLabels(true);
slider.setPaintTicks(true);
slider.setSnapToTicks(true);
slider.setOrientation(SwingConstants.VERTICAL);
contentPane.add(slider, BorderLayout.CENTER);

slider.addChangeListener(new SliderListener());

class SliderListener implements ChangeListener {
    public void stateChanged(ChangeEvent e) {
        JSlider source = (JSlider)e.getSource();
        if (!source.getValueIsAdjusting()) {
            System.out.println("boo");
        }    
    }
}

As you can see, the code isn't doing much, all I want to do for now is make sure the event is only firing once, and hence my event is simply to print something to the Console within Eclipse.

But the above code is printing "boo" twice each time I change the Slider. I'm guessing this has got something to do with Mouse Release on Slider, but whatever it is, I want it to only fire the event once, and hence only print the word once.

How can I achieve that?

Thanks

J86
  • 14,345
  • 47
  • 130
  • 228
  • Have you tried to create a program that basically has this slider only and see if you can duplicate the problem? – PM 77-1 Apr 05 '13 at 17:52
  • It would be much better to understand your code if you put your entire code here.. – Vishal K Apr 05 '13 at 18:24
  • @PM77-1 My whole program is that! basically a JSlider. I've figured out some more specific information about the behaviour. It only does it, if I move the slider to a location between the tick labels. Code updated. – J86 Apr 05 '13 at 18:46
  • 1
    @Ciwan - This case seems to be known to the community. See the following discussion: https://groups.google.com/forum/?fromgroups=#!topic/comp.lang.java.programmer/WYg0JmGqyIU – PM 77-1 Apr 05 '13 at 19:02
  • 1
    think of a changeEvent as a shotgun - it fires on several triggers and broadly, nothing you can do against that in the listener. Instead, guard the triggered dependent change (the "real" code that that fills the println) against duplicates, that is do nothing there if its current state isn't effected by the notification. – kleopatra Apr 05 '13 at 22:31
  • @whiskeyspider the answer you deleted (more precisely, its last paragraph) is basically correct :-) – kleopatra Apr 05 '13 at 22:33

2 Answers2

3

Are you certain the listener is not added twice ? The following SSCCE works as expected on my machine (OS X, JDK7)

import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.WindowConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.EventQueue;

public class SliderTest {
  public static void main( String[] args ) {
    EventQueue.invokeLater( new Runnable() {
      @Override
      public void run() {
        JFrame frame = new JFrame(  );
        final JSlider slider = new JSlider( 0, 100 );
        frame.add( slider );
        slider.addChangeListener( new ChangeListener() {
          @Override
          public void stateChanged( ChangeEvent e ) {
            if ( !( slider.getValueIsAdjusting() ) ){
              System.out.println( "SliderTest.stateChanged" );
            }
          }
        } );
        frame.pack();
        frame.setVisible( true );
        frame.setDefaultCloseOperation( WindowConstants.EXIT_ON_CLOSE );
      }
    } );
  }
}
Robin
  • 36,233
  • 5
  • 47
  • 99
  • 3
    OP clarified that it happens when he has **ticks** painted and `setSnapToTicks` is set to `True` and the slider is stopped **between** the ticks. Apparently in this case the second event is automatically fired in order to adjust the slider to the nearest tick. – PM 77-1 Apr 05 '13 at 19:07
-1

I know the issue. My workaround is to set global eventOnwer to all other listeners, That solves other event fires to occure while one is the event owner. And then, to solve the slider, I set the getValueIsAdjusting() to true in a if. In case of another fire, return.