user6866106
user6866106

Reputation: 31

Stopping the jslider from moving when clicked

Is it possible to stop a jslider from moving or changing values when it is clicked on? I want my jslider only to move when it is dragged. I don't want it to do anything at all when I click on it. Would someone please help me with this one.

Upvotes: 3

Views: 1109

Answers (2)

aterai
aterai

Reputation: 9808

There are a few other examples:

  • slider1: Override TrackListener#shouldScroll(...) method to always return false.
  • slider2: Change the left mouse button pressed MouseEvent as a right button by using JLayer.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.*;
import javax.swing.plaf.metal.MetalSliderUI;

public class MainPanel {
  public JComponent makeUI() {
    JSlider slider0 = new JSlider();

    JSlider slider1 = new JSlider() {
      @Override public void updateUI() {
        super.updateUI();
        setUI(new MetalSliderUI() {
          @Override protected TrackListener createTrackListener(JSlider slider) {
            return new TrackListener() {
              @Override public boolean shouldScroll(int direction) {
                return false;
              }
            };
          }
        });
      }
    };

    //http://stackoverflow.com/questions/9736237/how-to-disable-position-change-of-jslider-on-mouse-right-click
    UIManager.put("Slider.onlyLeftMouseButtonDrag", false);
    JSlider slider2 = new JSlider();

    Box box = Box.createVerticalBox();
    box.setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 20));
    box.add(makeTitledPanel("Default", slider0));
    box.add(Box.createVerticalStrut(20));
    box.add(makeTitledPanel(
        "Override TrackListener#shouldScroll(...): false",  slider1));
    box.add(Box.createVerticalStrut(20));
    box.add(makeTitledPanel(
        "JLayer + Slider.onlyLeftMouseButtonDrag: false",
        new JLayer<JSlider>(slider2, new DisableLeftPressedLayerUI())));
    box.add(Box.createVerticalGlue());

    return box;
  }
  private static JComponent makeTitledPanel(String title, JComponent c) {
    JPanel p = new JPanel(new BorderLayout());
    p.setBorder(BorderFactory.createTitledBorder(title));
    p.add(c, BorderLayout.NORTH);
    return p;
  }
  public static void main(String... args) {
    EventQueue.invokeLater(() -> {
      JFrame f = new JFrame();
      f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
      f.getContentPane().add(new MainPanel().makeUI());
      f.setSize(320, 240);
      f.setLocationRelativeTo(null);
      f.setVisible(true);
    });
  }
}

class DisableLeftPressedLayerUI extends LayerUI<JSlider> {
  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_EVENT_MASK);
    }
  }
  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }
  @Override protected void processMouseEvent(MouseEvent e, JLayer<? extends JSlider> l) {
    if (e.getID() == MouseEvent.MOUSE_PRESSED && SwingUtilities.isLeftMouseButton(e)) {
      JSlider slider = (JSlider) e.getComponent();
      MouseEvent me = new MouseEvent(
        slider,
        e.getID(), e.getWhen(),
        InputEvent.BUTTON3_DOWN_MASK, //e.getModifiers(),
        e.getX(), e.getY(),
        e.getXOnScreen(), e.getYOnScreen(),
        e.getClickCount(),
        e.isPopupTrigger(),
        MouseEvent.BUTTON3); //e.getButton());
      e.consume();
      slider.dispatchEvent(me);
    }
  }
}

Upvotes: 1

user5522551
user5522551

Reputation:

Unfortunately, after a fair amount of testing, I could not find any method nor combination of event listeners that could solve this problem. The closest I got was disabling all modifications to slider value, no matter how it was changed:

import javax.swing.JFrame;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class App {
    public static void main(String[] args) {
        final JFrame jframe = new JFrame("Demo");

        final JSlider jslider = new JSlider();

        // Limit user access
        new SliderLocker(jslider).preventSlide = true;

        jslider.setMajorTickSpacing(10);
        jslider.setPaintTicks(true);
        jframe.getContentPane().add(jslider);

        jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jframe.setSize(400, 400);
        jframe.setResizable(false);
        jframe.setVisible(true);
    }

    // Create custom event handler to restore to original value with event system
    private static class SliderLocker implements ChangeListener {
        public boolean preventSlide = false;
        private int oldVal;
        private final JSlider comp;

        public SliderLocker(JSlider c){
            comp = c;
            oldVal = c.getValue();

            c.addChangeListener(this);
        }

        @Override
        public void stateChanged(ChangeEvent ev){
            if(preventSlide){
                comp.setValue(oldVal);
            }
        }
    }
}

Basically it creates a new SliderLocker which has a public flag .preventSlide. When set to true, it will prevent all user interactions (and even code-triggred interactions, such as .setValue()).

My previous code had included some mouse listeners that would attempt to check if the slider was being 'slid' (changed with actual mouse drag) but I later found out that holding down mouse out of slider button and dragging broke the handler.

Upvotes: 0

Related Questions