ハリー・ジョイの助けを借りてノブを隠し、ついに問題を解決することができました.
BasicSliderUI.paintThumb(Graphics)
Harry's answer を確認すると、ノブを非表示にするメソッドのオーバーライドについて読むことができます。Synth (つまり Nimbus を意味する) に基づいていないほとんどの L&F で問題なく動作し、アプローチは異なりますが、L&F のカスタマイズを介して実行できます。
それをインストールするのは少しトリッキーです: L&F の変更をチェックし、コンポーネントに適切な UI デリゲートをインストールする を持っていると、魔法のようになります (このソリューションでは、他のものに基づいたものをコピーして貼り付けているだけですPropertyChangeListener
) 。 . また、最初にクリックされた位置に値を設定するように少し調整しました。デリゲートがノブをペイントする必要があるかどうかを知るために、呼び出された にクライアント プロパティを設定することにしました。このように、デリゲートは、拡張されたものだけでなく、任意の にインストールできます。UIManager
BasicSliderUI
JSlider
"ready"
boolean
JSlider
では、未知の値を管理するにはどうすればよいでしょうか。別の新しいプロパティを追加すると、これはとの両方のタイプ"selectedValue"
にバインドされます。であるかどうかに応じて、またはその逆であり、準備ができていない限り、 と の両方が同じ値 (一方が であり、もう一方が )を保持します。これにより、 が に設定されます。複雑に聞こえるかもしれませんが、そうではありません。また、[Esc] で値をクリアし、実装されたコンポーネントにプロパティを伝達するための微調整もあります。"value"
"ready"
Integer
"ready"
false
true
null
"value"
"selectedValue"
int
Integer
"selectedValue"
null
コードは次のとおりです。
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 用でも、適切なデリゲートを拡張してリスナーに追加する必要があります。