snapToTicks==true 时如何检索最终的 Slider 值? [英] How to retrieve the final Slider value when snapToTicks==true?

查看:31
本文介绍了snapToTicks==true 时如何检索最终的 Slider 值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下JavaFX场景(注意snapToTicks的设置):

I have the following JavaFX scene (note the setting of 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,一旦松开鼠标按钮,滑块最终会移动到最接近的值.

Since snapToTicks is set to true the slider will finally move to the nearest value once the mouse button is released.

如何检索最终值?

我试过了

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

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

which works well except for the minimum and maximum values - if the mouse is already at a position left to the slider or at a position right to the slider, the listener will not be called at all anymore since the final value has already been set.

我也尝试过使用valueChangingProperty:

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

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

but the problem is that JavaFX will still change the value to the snapped value after that listener has been called with newVal equal to false (which I would even consider a bug, but probably I missed something). So its not possible to access the final, snapped value in that method.

推荐答案

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

I finally came up with the below solution, based on the proposal from @ItachiUchiha. Essentially, the solution uses both, a valueProperty and a valueChangingProperty listener, and uses some flags to track the current state. At the end, the perform() method is called exactly once when the slider movement is done and the final value is available. This works when the slider is moved either with the mouse or through the keyboard.

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

A reusable class implemented as subclass of Slider is available at 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
", value);
    }
}

这篇关于snapToTicks==true 时如何检索最终的 Slider 值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆