如何在snapToTicks == true时检索最终的Slider值?

我有以下JavaFX场景(请注意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等于false调用侦听器之后 ,JavaFX仍然会将值更改为捕捉值(我甚至会考虑一个错误,但可能我错过了一些东西)。 因此无法访问该方法中的最终snapt值。

根据@ItachiUchiha的提议,我终于提出了以下解决方案。 本质上,该解决方案使用valuePropertyvalueChangingProperty侦听器,并使用一些标志来跟踪当前状态。 最后,当滑块移动完成并且最终值可用时, perform()方法只调用一次。 当使用鼠标或键盘移动滑块时,此function可用。

可以在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() { final double minCompare = slider.getMin() + Math.ulp(slider.getMin()); final double maxCompare = slider.getMax() - Math.ulp(slider.getMax()); @Override public void changed(ObservableValue 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() { @Override public void changed(ObservableValue 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); } }