在 Harry Joy 的大力帮助下隐藏旋钮,我终于能够解决问题。
如果您检查哈利的答案,您可以阅读有关覆盖BasicSliderUI.paintThumb(Graphics)
隐藏旋钮的方法的信息。它适用于大多数不基于 Synth(这意味着 Nimbus)的 L&F,其中方法会有所不同,但可以通过 L&F 上的自定义来实现。
安装它有点棘手:有一个检查 L&FPropertyChangeListener
上UIManager
的任何更改并在组件上安装一个适当的 UI 委托会产生魔力(在这个解决方案中,我只是展示基于BasicSliderUI
其他的一个是复制粘贴) . 此外,我对其进行了一些调整,使其将值设置为第一次单击的位置。为了让代表知道它是否必须绘制旋钮,我决定在被JSlider
调用对象上有一个客户端属性"ready"
,即boolean
. 这样,委托可以安装在任何一个JSlider
,而不仅仅是一个扩展的。
现在,如何管理未知值?添加另一个新属性"selectedValue"
,这个属性绑定到"value"
and"ready"
和Integer
类型。"ready"
is false
ortrue
取决于它是否null
存在,反之亦然,并且两者都"value"
保持"selectedValue"
相同的值(一个存在int
和另一个Integer
),除非没有准备好,这会将 设置"selectedValue"
为null
. 听起来可能很复杂,但事实并非如此。还有一些调整用于使用 [Esc] 清除值并在实现的组件中传播属性。
这是代码:
BasicSliderUIExt
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.plaf.basic.BasicSliderUI;
public class BasicSliderUIExt extends BasicSliderUI {
public BasicSliderUIExt(JSlider slider) {
super(slider);
}
@Override
public void paintThumb(Graphics g) {
if (isReady(super.slider)) {
super.paintThumb(g);
}
}
@Override
protected TrackListener createTrackListener(final JSlider slider) {
return new TrackListener() {
@Override
public void mousePressed(MouseEvent event) {
if (isReady(slider)) {
super.mousePressed(event);
} else {
JSlider slider = (JSlider) event.getSource();
switch (slider.getOrientation()) {
case SwingConstants.VERTICAL:
slider.setValue(valueForYPosition(event.getY()));
break;
case SwingConstants.HORIZONTAL:
slider.setValue(valueForXPosition(event.getX()));
break;
}
super.mousePressed(event);
super.mouseDragged(event);
}
}
@Override
public boolean shouldScroll(int direction) {
if (isReady(slider)) {
return super.shouldScroll(direction);
}
return false;
}};
}
public static boolean isReady(JSlider slider) {
Object ready = slider.getClientProperty(JSliderExt.READY_PROPERTY);
return (ready == null) || (!(ready instanceof Boolean)) || (((Boolean) ready).booleanValue());
}
}
JSliderExt
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Constructor;
import javax.swing.BoundedRangeModel;
import javax.swing.JSlider;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.SliderUI;
public class JSliderExt extends JSlider {
private static final long serialVersionUID = 1L;
public static final String EXTENT_PROPERTY = "extent";
public static final String MAXIMUM_PROPERTY = "maximum";
public static final String MINIMUM_PROPERTY = "minimum";
public static final String READY_PROPERTY = "ready";
public static final String SELECTED_VALUE_PROPERTY = "selectedValue";
public static final String VALUE_PROPERTY = "value";
public static final boolean READY_DEFAULT_VALUE = false;
protected SliderUI uix = new BasicSliderUIExt(this);
public JSliderExt(BoundedRangeModel model, boolean ready) {
super(model);
init(ready);
}
public JSliderExt(BoundedRangeModel model) {
super(model);
init(READY_DEFAULT_VALUE);
}
public JSliderExt(int orientation, int minimmum, int maximum, int value, boolean ready) {
super(orientation, minimmum, maximum, value);
init(ready);
}
public JSliderExt(int orientation, int minimmum, int maximum, int value) {
super(orientation, minimmum, maximum, value);
init(READY_DEFAULT_VALUE);
}
public JSliderExt(int minimmum, int maximum, int value, boolean ready) {
super(minimmum, maximum, value);
init(ready);
}
public JSliderExt(int minimmum, int maximum, int value) {
super(minimmum, maximum, value);
init(READY_DEFAULT_VALUE);
}
public JSliderExt(int minimmum, int maximum, boolean ready) {
super(minimmum, maximum);
init(ready);
}
public JSliderExt(int minimmum, int maximum) {
super(minimmum, maximum);
init(READY_DEFAULT_VALUE);
}
public JSliderExt(int orientation, boolean ready) {
super(orientation);
init(ready);
}
public JSliderExt(int orientation) {
super(orientation);
init(READY_DEFAULT_VALUE);
}
public JSliderExt(boolean ready) {
super();
init(ready);
}
public JSliderExt() {
super();
init(READY_DEFAULT_VALUE);
}
private void init(boolean ready) {
UIManager.addPropertyChangeListener(new PropertyChangeListener() { // Changes the UI delegate in L&F change
@Override
public void propertyChange(PropertyChangeEvent event) {
if ("lookAndFeel".equals(event.getPropertyName())) {
Object newValue = event.getNewValue();
if ((newValue != null) && (newValue instanceof LookAndFeel)) {
LookAndFeel lookAndFeel = (LookAndFeel) newValue;
try {
if (lookAndFeel instanceof MetalLookAndFeel) {
JSliderExt.this.uix = new MetalSliderUIExt();
} else if (lookAndFeel instanceof com.sun.java.swing.plaf.motif.MotifLookAndFeel) {
JSliderExt.this.uix = new MotifSliderUIExt(JSliderExt.this);
} else if (lookAndFeel instanceof com.sun.java.swing.plaf.windows.WindowsLookAndFeel) {
JSliderExt.this.uix = new WindowsSliderUIExt(JSliderExt.this);
} else {
throw new NullPointerException("Default Look & Feel not matched");
}
} catch (Exception e) {
try {
Package sliderPackage = JSliderExt.this.getClass().getPackage();
String lookAndFeelName = lookAndFeel.getName();
if (lookAndFeelName.equals("CDE/Motif")) {
lookAndFeelName = "Motif";
} else if (lookAndFeelName.equals("Windows Classic")) {
lookAndFeelName = "Windows";
} else if (lookAndFeelName.startsWith("JGoodies")) {
lookAndFeelName = "Basic";
}
Class<?> sliderUiType = Class.forName(sliderPackage.getName() + "." + lookAndFeelName
+ "SliderUIExt");
Constructor<?> constructor1 = null;
try {
constructor1 = sliderUiType.getConstructor(JSlider.class);
} catch (Exception e3) { // Nothing to do here
}
Constructor<?> constructor0 = null;
try {
constructor0 = sliderUiType.getConstructor();
} catch (Exception e3) { // Nothing to do here
}
Object sliderUi = null;
if (constructor1 != null) {
sliderUi = constructor1.newInstance(JSliderExt.this);
} else if (constructor0 != null) {
sliderUi = constructor0.newInstance();
}
if ((sliderUi != null) && (sliderUi instanceof SliderUI)) {
JSliderExt.this.setUI((SliderUI) sliderUi);
}
} catch (Exception e2) {
JSliderExt.this.uix = new BasicSliderUIExt(JSliderExt.this);
}
}
} else {
JSliderExt.this.uix = new BasicSliderUIExt(JSliderExt.this);
}
updateUI();
}
}});
addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent event) {
String propertyName = event.getPropertyName();
if (READY_PROPERTY.equals(propertyName)) {
Object newValue = event.getNewValue();
if ((newValue == null) || (!(newValue instanceof Boolean)) || (((Boolean) newValue).booleanValue())) {
setSelectedValue(Integer.valueOf(getValue()));
} else {
setSelectedValue(null);
}
} else if (SELECTED_VALUE_PROPERTY.equals(propertyName)) {
Object newValue = event.getNewValue();
System.out.println(newValue);
if ((newValue != null) && (newValue instanceof Integer)) {
int value = getValue();
int newSelectedValue = ((Integer) newValue).intValue();
if (value != newSelectedValue) {
setValue(newSelectedValue);
}
setReady(true);
} else {
setReady(false);
}
repaint();
} else if (VALUE_PROPERTY.equals(propertyName)) {
setReady(true);
Object newValue = event.getNewValue();
if ((newValue != null) && (newValue instanceof Integer)) {
setSelectedValue((Integer) newValue);
}
}
}});
addKeyListener(new KeyAdapter() { // Enables escape key for clearing value
@Override
public void keyPressed(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.VK_ESCAPE) {
JSliderExt.this.setReady(false);
}
}});
setReady(ready);
}
@Override
public void setValue(int value) {
int oldValue = getValue();
super.setValue(value);
firePropertyChange(VALUE_PROPERTY, Integer.valueOf(oldValue), Integer.valueOf(value));
}
@Override
public void setExtent(int extent) {
int oldExtent = getExtent();
super.setExtent(extent);
firePropertyChange(EXTENT_PROPERTY, Integer.valueOf(oldExtent), Integer.valueOf(extent));
}
@Override
public void setMinimum(int minimum) {
int oldMinimum = getMinimum();
super.setMinimum(minimum);
firePropertyChange(MINIMUM_PROPERTY, Integer.valueOf(oldMinimum), Integer.valueOf(minimum));
}
@Override
public void setMaximum(int maximum) {
int oldMaximum = getMaximum();
super.setMaximum(maximum);
firePropertyChange(MAXIMUM_PROPERTY, Integer.valueOf(oldMaximum), Integer.valueOf(maximum));
}
public Integer getSelectedValue() {
return (Integer) getClientProperty(SELECTED_VALUE_PROPERTY);
}
public void setSelectedValue(Integer selectedValue) {
putClientProperty(SELECTED_VALUE_PROPERTY, selectedValue);
}
public boolean isReady() {
Object ready = getClientProperty(READY_PROPERTY);
return ((ready != null) && (ready instanceof Boolean)) ? ((Boolean) ready).booleanValue()
: READY_DEFAULT_VALUE;
}
public void setReady(boolean waiting) {
putClientProperty(READY_PROPERTY, Boolean.valueOf(waiting));
}
@Override
public void updateUI() {
setUI(this.uix);
updateLabelUIs();
}
}
请注意,使用此代码可能需要根据您的应用程序在选择代理时进行一些更改,因为这适用于 Windows 系统。如前所述,Synth/Nimbus 必须以不同的方式工作,而且任何自定义 L&F 或 OSX 都需要适当的委托来扩展并添加到侦听器上。