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

时间:2016-02-01 11:42:48

标签: java javafx slider javafx-8

我有以下JavaFX场景(请注意Log.v的设置):

snapToTicks

,它会像这样呈现一个滑块:

slider screenshot

由于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值。

1 个答案:

答案 0 :(得分:1)

根据@ItachiUchiha的提议,我终于提出了以下解决方案。本质上,该解决方案使用valuePropertyvalueChangingProperty侦听器,并使用一些标志来跟踪当前状态。最后,当滑块移动完成且最终值可用时,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);
    }
}