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

标签 java javafx slider javafx-8

我有以下 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();
   }
}

呈现如下 slider :

slider screenshot

由于 snapToTicks 设置为 true,一旦松开鼠标按钮, slider 最终将移动到最近的值。

如何检索最终值?

我试过了

slider.valueProperty().addListener( n -> {
    if (!slider.isValueChanging()) {
        System.err.println(n);
    }
});

除了最小值和最大值之外效果很好 - 如果鼠标已经位于 slider 左侧或右侧的位置,则根本不会再调用监听器,因为最终值已经已设置。

我也尝试过使用 valueChangingProperty:

slider.valueChangingProperty().addListener( (prop, oldVal, newVal) -> {
   // NOT the final value when newVal == false!!!!!!!
   System.err.println(prop + "/" + oldVal + "/" + newVal); 
});

但问题是 JavaFX 仍会将值更改为捕捉值 afternewVal 等于 false 调用监听器(我什至会认为这是一个错误,但可能我错过了一些东西)。因此无法在该方法中访问最终的捕捉值。

最佳答案

根据@ItachiUchiha 的建议,我最终想出了以下解决方案。本质上,该解决方案同时使用了 valuePropertyvalueChangingProperty 监听器,并使用一些标志来跟踪当前状态。最后,当 slider 移动完成且最终值可用时,perform() 方法只被调用一次。这在使用鼠标或通过键盘移动 slider 时有效。

作为 Slider 的子类实现的可重用类可在 https://github.com/afester/FranzXaver/blob/master/FranzXaver/src/main/java/afester/javafx/components/SnapSlider.java 获得。 .

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);
    }
}

关于java - 如何在 snapToTicks==true 时检索最终的 Slider 值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35129670/

相关文章:

java - 导入的片段包是否包含在主机包类路径中?

python - Maya 中 MEL/Python 中使用的 AttrFieldSliderGrp 命令

javascript - 我怎样才能让这个 jQuery slider 自动

jquery-mobile - JQuery Mobile slider 更改事件 - 显示图像

java - 下载springframework源码导入idea成功,创建测试模块,依赖不起作用

java - Java中高效的字符串读取?

java - 有界通配符相关的编译器错误

JavaFX - 如何知道是否按下了取消

java - Java 和 JavaFX 中的 MVC 分离 (fxml)

file - JavaFX FileChooser 不返回 Windows 的文件扩展名