2

I have a JSlider with minimum value of 0 and max value of 100. When the JSlider first launches, the value is 0.

Now, when I click my mouse on the 50, or even the 20 or 100, the JSlider doesn't move to the location I click. It simply jumps a little bit towards the right.

How do I make it so that the value will go to whatever I click?

CodeGuy
  • 28,427
  • 76
  • 200
  • 317
  • 1
    why do you want to implement non-standard behaviour? High potential of confusing your users .. Keep the mouse pressed and the thumb will reach the mouse eventually – kleopatra Aug 18 '11 at 07:34

2 Answers2

3

BasicSliderUI provides a method called valueForXPosition:

Returns the value at the x position. If xPos is beyond the track at the left or the right, this method sets the value to either the minimum or maximum value of the slider, depending on if the slider is inverted or not.

(For vertical sliders use valueForYPosition)

Example adding a MouseListener to a horizontal JSlider using valueForXPosition:

JSlider slider = new JSlider();
slider.setOrientation(JSlider.HORIZONTAL);
slider.setMinimum(0);
slider.setMaximum(100); 
slider.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
       JSlider sourceSlider=(JSlider)e.getSource();
       BasicSliderUI ui = (BasicSliderUI)sourceSlider.getUI();
       int value = ui.valueForXPosition( e.getX() );
       slider.setValue(value);
    }
});
clic
  • 365
  • 1
  • 13
3

Here is the beginning of a class that will do what you need.

The general idea is to detect where the user clicks and calculate the value offset necessary in order to match that new slider location.

// 'E' stands for enhanced
public class EJSlider extends JSlider {

   public EJSlider() {
      super();
      addMouseListener(new MouseAdapter() {
         @Override
         public void mousePressed(MouseEvent e) {
            Point p = e.getPoint();
            double percent = p.x / ((double) getWidth());
            int range = getMaximum() - getMinimum();
            double newVal = range * percent;
            int result = (int)(getMinimum() + newVal);
            setValue(result);
         }
      });
   }

   public static void main(String[] args) {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      f.add(new EJSlider());
      f.pack();
      f.setVisible(true);
   }
}

Simply run the example. The slider will jump to wherever you click your mouse. This has not been thoroughly tested, and will not work with vertical sliders, yet.

A similar solution to this one would be simply adding my custom MouseListener to any JSlider you would like that functionality on.

(Note, I know it's not perfect yet, but it is a good start.)

jjnguy
  • 136,852
  • 53
  • 295
  • 323
  • I would have expected that you would override some method in JSlider. It's not clear why your method is invoked after the one in JSlider that moves the knob. – toto2 Aug 17 '11 at 15:51
  • @toto2, my method is invoked as part of the mouse clicked action. A standard `JSlider` handles the click by advancing the slider one position. My action will move the slider to the value that a user clicks on. It doesn't really matter the order that those happen in. – jjnguy Aug 17 '11 at 16:06
  • I mean the standard JSlider movement also must be invoked from the mouse clicked event handler. The order would be wrong if your method is called first and then the other one after; the slider would end up in the wrong place. – toto2 Aug 17 '11 at 16:15
  • @toto2, I'm not 100% sure what the other method does exactly. But my guess is it will advance the pointer `1` towards the position of the mouse. This behavior is ok if the slider has already moved close to the mouse; in fact, it will help to move the slider closer. – jjnguy Aug 17 '11 at 16:17
  • @toto2, I found that if you remove all listeners the dragging functionality of the component is lost, but this can be fixed by adding your own mouse motion listener. – jjnguy Aug 17 '11 at 16:26