我有以下JavaFX场景(请注意Log.v
的设置):
snapToTicks
,它会像这样呈现一个滑块:
由于package com.example.javafx;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.stage.Stage;
public class SliderExample extends Application {
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) {
Slider slider = new Slider(0.25, 2.0, 1.0);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
slider.setMajorTickUnit(0.25);
slider.setMinorTickCount(0);
slider.setSnapToTicks(true); // !!!!!!!!!!
Scene scene = new Scene(slider, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
}
设置为snapToTicks
,一旦释放鼠标按钮,滑块最终会移动到最近的值。
如何检索最终值?
我试过
true
除了最小值和最大值之外效果很好 - 如果鼠标已经位于滑块左侧或滑块右侧的位置,则由于最终值已经存在,因此将不再调用监听器已经确定。
我还尝试使用slider.valueProperty().addListener( n -> {
if (!slider.isValueChanging()) {
System.err.println(n);
}
});
:
valueChangingProperty
但问题是,在slider.valueChangingProperty().addListener( (prop, oldVal, newVal) -> {
// NOT the final value when newVal == false!!!!!!!
System.err.println(prop + "/" + oldVal + "/" + newVal);
});
等于newVal
调用侦听器之后,JavaFX仍会将值更改为快照值(我甚至会考虑)一个错误,但可能我错过了一些东西)。因此,无法访问该方法中的最终snapt值。
答案 0 :(得分:1)
根据@ItachiUchiha的提议,我终于提出了以下解决方案。本质上,该解决方案使用valueProperty
和valueChangingProperty
侦听器,并使用一些标志来跟踪当前状态。最后,当滑块移动完成且最终值可用时,perform()
方法只调用一次。当使用鼠标或键盘移动滑块时,此功能可用。
https://github.com/afester/FranzXaver/blob/master/FranzXaver/src/main/java/afester/javafx/components/SnapSlider.java提供了作为Slider
的子类实现的可重用类。
package com.example.javafx;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.stage.Stage;
public class SliderExample extends Application {
public static void main(String[] args) { launch(args); }
private boolean isFinal = true; // assumption: no dragging - clicked value is the final one.
// variable changes to "false" once dragging starts.
private Double finalValue = null;
@Override
public void start(Stage primaryStage) {
final Slider slider = new Slider(0.25, 2.0, 1.0);
slider.setShowTickLabels(true);
slider.setShowTickMarks(true);
slider.setMajorTickUnit(0.25);
slider.setMinorTickCount(0);
slider.setSnapToTicks(true);
slider.valueProperty().addListener(new ChangeListener<Number>() {
final double minCompare = slider.getMin() + Math.ulp(slider.getMin());
final double maxCompare = slider.getMax() - Math.ulp(slider.getMax());
@Override
public void changed(ObservableValue<? extends Number> observable,
Number oldValue, Number newValue) {
if (isFinal) { // either dragging of knob has stopped or
// no dragging was done at all (direct click or
// keyboard navigation)
perform((Double) newValue);
finalValue = null;
} else { // dragging in progress
double val = (double) newValue;
if (val > maxCompare || val < minCompare) {
isFinal = true; // current value will be treated as final value
// once the valueChangingProperty goes to false
finalValue = (Double) newValue; // remember current value
} else {
isFinal = false; // no final value anymore - slider
finalValue = null; // has been dragged to a position within
// minimum and maximum
}
}
}
});
slider.valueChangingProperty().addListener(new ChangeListener<Boolean>() {
@Override
public void changed(ObservableValue<? extends Boolean> observable,
Boolean oldValue, Boolean newValue) {
if (newValue == true) { // dragging of knob started.
isFinal = false; // captured values are not the final ones.
} else { // dragging of knob stopped.
if (isFinal) { // captured value is already the final one
// since it is either the minimum or the maximum value
perform(finalValue);
finalValue = null;
} else {
isFinal = true; // next captured value will be the final one
}
}
}
});
Scene scene = new Scene(slider, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private void perform(double value) {
System.err.printf("FINAL: %s\n", value);
}
}