How to disable position change of JSlider on mouse right click
Question
I am using a JSlider
in my application. I want only left click to slide JSlider
, and I want to disable right click for JSlider
. I am able to get event on right click, but slider is changing its value to other position.
jSlider.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
//code
}
});
jSlider.addMouseListener(new MouseAdapter() {
public void mouseReleased(MouseEvent e) {
if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) {
//code
} else {
//code
}
}
});
Solution
I am using JDK1.7.0_03, Windows 7
UIManager.put("Slider.onlyLeftMouseButtonDrag", Boolean.TRUE);
JDK1.6.0_31:
Bug ID: 6614972 JSlider value should not change on right-click
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.metal.MetalSliderUI;
public class SliderOnlyLeftMouseButtonDragTest {
public JComponent makeUI() {
JSlider slider00 = new JSlider(0,10,5);
JSlider slider01 = new JSlider(0,10,5);
slider01.setUI(new MetalSliderUI() {
protected TrackListener createTrackListener(JSlider slider) {
return new TrackListener() {
@Override public void mousePressed(MouseEvent e) {
if(!SwingUtilities.isLeftMouseButton(e)) {
return;
}
super.mousePressed(e);
}
};
}
});
JPanel p = new JPanel();
p.add(slider00);
p.add(slider01);
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SliderOnlyLeftMouseButtonDragTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
OTHER TIPS
Another approach to work around bugs in ui listeners is to
- find the listener
- implement a wrapper which delegates to the original only if appropriate (here: not for right button)
- remove the original and add the wrapper
The slight advantage compared with @aterai's approach is that it's independent of LAF, that is you can apply it in the exact same manner for each instead of subclassing the ui delegate for each.
In code something like:
MouseListener[] listeners = slider.getMouseListeners();
MouseListener uiListener = null;
for (MouseListener l : listeners) {
LOG.info(l.getClass().getName());
if (l.getClass().getName().contains("Track")) {
uiListener = l;
break;
}
}
final MouseListener delegate = uiListener;
MouseListener wrapper = new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
if (filter(e)) return;
delegate.mouseClicked(e);
}
private boolean filter(MouseEvent e) {
return SwingUtilities.isRightMouseButton(e);
}
@Override
public void mousePressed(MouseEvent e) {
if (filter(e)) return;
delegate.mousePressed(e);
}
@Override
public void mouseReleased(MouseEvent e) {
if (filter(e)) return;
delegate.mouseReleased(e);
}
@Override
public void mouseEntered(MouseEvent e) {
delegate.mouseEntered(e);
}
@Override
public void mouseExited(MouseEvent e) {
delegate.mouseExited(e);
}
};
slider.removeMouseListener(uiListener);
slider.addMouseListener(wrapper);
I Case he is not working with 1.7 First you must remove all mouseListeners from your slider
for (MouseListener ml : slider.getMouseListeners()){
slider.removeMouseListener(ml);
}
after that you can implement your own mouseListener and add that one to the slider. In your mouselistener you must implement the calculations to set the value of your slider... e.g. sth like
public void mouseReleased(MouseEvent e) {
if (e.getButton() == java.awt.event.MouseEvent.BUTTON3) {
//code whatever should happen on right click
} else {
e.getX()*slider.getMaximum()/slider.getWidth();
}
}
I guess the calculation could be improved because of rounding and so on.. But this idea should lead you to success