我有一个问题,即当滑块旋钮处于最小或最大极限时,JavaFX滑块不会为valueProperty调用ChangeListener。我只想在更改了滑块值后才执行一些代码(而不是在拖动滑块时)。我尝试使用以下代码实现这一目标:
Slider slider = new Slider();
slider.setMin(0);
slider.setMax(10);
slider.setMajorTickUnit(5);
slider.setMinorTickCount(5);
slider.setBlockIncrement(1);
slider.setSnapToTicks(true);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
ChangeListener<? super Number> valueListener = (observable, oldValue, newValue) -> {
if (!slider.isValueChanging()) {
System.out.println("Value changed");
}
};
slider.valueProperty().addListener(valueListener);
您将看到,当拖动并释放滑块时,每次都会打印出字符串Value changed
,除了在0或10位置上释放滑块的时候。这是预期的行为吗?还是我错过了什么?
答案 0 :(得分:2)
问题是fx属性设计的结果:与ol'bean规范相反,它们是完全独立的,每个更改都彼此独立地触发。结果是,对一个属性的侦听器在对更改做出反应时不得查询任何其他属性。
应用于Slider的value / isValueAdjusting属性的上下文:
归根结底,Slider的api太弱而无法满足常见用例(仅在更改完成后才对更改做出反应)而无需花费大量精力。
一个出路可能是带有增强的api的自定义滑块。下面的概述基于观察(注意:实现细节!),所有内部构件都通过slider.adjustValue(value)
设置了最终值。增强的滑块
大纲(不完整且未经正式测试):
public static class AdjustedSlider extends Slider {
private DoubleProperty adjustedValue;
public AdjustedSlider() {
super();
}
public AdjustedSlider(double min, double max, double value) {
super(min, max, value);
}
public DoubleProperty adjustedValueProperty() {
if (adjustedValue == null) {
adjustedValue = new SimpleDoubleProperty(this, "adjustedValue", 0);
}
return adjustedValue;
}
public double getAdjustedValue() {
return adjustedValueProperty().get();
}
private void setAdjustedValue(double value) {
adjustedValueProperty().set(value);
}
@Override
public void adjustValue(double newValue) {
super.adjustValue(newValue);
setAdjustedValue(getValue());
}
}
答案 1 :(得分:0)
好像已经发布了一个解决方案here。基本上,这归结为添加针对极端的显式检查,以便ChangeListener看起来像这样:
ChangeListener<? super Number> valueListener = (observable, oldValue, newValue) -> {
boolean isOnMin = newValue.doubleValue() == slider.getMin();
boolean isOnMax = newValue.doubleValue() == slider.getMax();
if (!slider.isValueChanging() || isOnMin || isOnMax) {
System.out.println("Value changed");
}
};
但是,该解决方案的缺点是,即使尚未释放鼠标按钮,只要滑块触摸到任一边缘,它都会立即调用System.out.println
。
我发现的另一种解决方案是保留原来的ChangeListener,该ChangeListener仅检查isValueChanging-value,但将以下ChangeListener添加到valueChangingProperty:
ChangeListener<? super Boolean> valueChangingListener = (observable, oldUpdating, newUpdating) -> {
double value = slider.getValue();
boolean notUpdatingAnymore = oldUpdating && !newUpdating;
boolean isOnExtreme = value == slider.getMin() || value == slider.getMax();
if (notUpdatingAnymore && isOnExtreme) {
System.out.println("Value changed");
}
};
slider.valueChangingProperty().addListener(valueChangingListener);
这很丑,但是行得通。我不知道是否有一种更清洁的方法来实现所需的行为。