【问题标题】:JavaFX Slider - changeListener not triggered when arrow-buttton-press (->) moves sliderJavaFX Slider - 当箭头按钮按下(->)移动滑块时不会触发changeListener
【发布时间】:2020-10-17 09:35:05
【问题描述】:

我的 valueChangingProperty 监听器 仅捕获由鼠标引起的事件(用鼠标拖动滑块或在滑块内的某处单击鼠标)。当我按下箭头按钮 (->) 时,它不会响应滑块的移动(因此它的值会发生变化),尽管我看到它会导致滑块移动。

MyController.java

private Slider playRewindSlider;

playRewindSlider.valueChangingProperty().addListener(new ChangeListener() {

    @Override
    public void changed(ObservableValue observable, Object oldValue, Object newValue) {

        boolean finishedDragging = !(Boolean) observable.getValue();
        
        if (finishedDragging) {
            // logic triggered ONCE after slider moving finished
        }
    }           
});

如何用箭头 (->) 捕捉变化的滑块?

附:我在 SO 上看到很多关于滑块的帖子,但没有一个有效。

【问题讨论】:

    标签: javafx slider


    【解决方案1】:

    valueChanging 属性指示滑块是否正在更改(通常这意味着用户正在拖动滑块拇指)。如果用户执行更改值的单个操作(因为值更改,但滑块从未处于值仍然更改的状态),则不会发生这种情况。

    通常,您希望响应 value 本身的变化:

    playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
        // process newValue
    });
    

    valueChanging 属性的目的是避免在用户拖动拇指时执行大量更新。因此,您可以通过在侦听器中检查 value 的属性来限制仅在更改完成时更新:

    playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
        if (! playRewindSlider.isValueChanging()) {
            // process newValue
        }
    });
    

    请注意,这不会通过用鼠标拖动拇指来触发(因为值会更改,但 valueChanging 直到最终更改后才会设置为 false)。所以你需要包含第二个监听器(你原来的valueChanging监听器):

    playRewindSlider.valueChangingProperty().addListener((obs, wasChanging, isNowChanging) -> {
        if (! isNowChanging) {
            double newValue = playRewindSlider.getValue();
            // process newValue
        }
    });
    

    您可以通过创建添加到两个属性的单个侦听器来减少代码:

    ChangeListener<Object> sliderListener = (obs, oldValue, newValue) -> {
        if (! playRewindSlider.isValueChanging()) {
            double newValue = playRewindSlider.getValue();
            // process newValue
        }
    };
    playRewindSlider.valueProperty().addListener(sliderListener);
    playRewindSlider.valueChangingProperty().addListener(sliderListener);
    

    这是一个完整的例子:

    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.scene.Scene;
    import javafx.scene.control.Slider;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
            Slider slider = new Slider();
            
            ChangeListener<Object> listener = (obs, oldValue, newValue) -> {
                if (! slider.isValueChanging()) {
                    processSliderChange(slider.getValue());
                }
            };
            slider.valueProperty().addListener(listener);
            slider.valueChangingProperty().addListener(listener);
            
            BorderPane root = new BorderPane(slider);
            Scene scene = new Scene(root, 200, 200);
            stage.setScene(scene);
            stage.show();
        }
        
        private void processSliderChange(double value) {
            System.out.printf("%.2f%n", value);
        }
    
        public static void main(String[] args) {
            launch();
        }
    
    }
    

    这里的另一个选择是使用绑定做一些巧妙的工作,如果滑块的valuePropertyvalueChangingProperty 更改,则该绑定无效,但前提是valueChangingProperty 为假:

        DoubleBinding sliderValue = new DoubleBinding() {
            
            {
                InvalidationListener l = obs -> {
                    if (! playRewindSlider.isValueChanging()) invalidate();
                };
                playRewindSlider.valueProperty().addListener(l);
                playRewindSlider.valueChangingProperty().addListener(l);
            }
    
            @Override
            protected double computeValue() {
                return playRewindSlider.getValue();
            }
            
        };
    

    然后

    sliderValue.addListener((obs, oldValue, newValue) -> {
        // process newValue
    });
    

    在你需要的时候触发。

    以下是使用此技术的相同示例:

    import javafx.application.Application;
    import javafx.beans.InvalidationListener;
    import javafx.beans.binding.DoubleBinding;
    import javafx.scene.Scene;
    import javafx.scene.control.Slider;
    import javafx.scene.layout.BorderPane;
    import javafx.stage.Stage;
    
    public class App extends Application {
    
        @Override
        public void start(Stage stage) {
            Slider slider = new Slider();
            
            DoubleBinding sliderValue = new DoubleBinding() {
                
                {
                    InvalidationListener l = obs -> {
                        if (! slider.isValueChanging()) invalidate();
                    };
                    slider.valueProperty().addListener(l);
                    slider.valueChangingProperty().addListener(l);
                }
    
                @Override
                protected double computeValue() {
                    return slider.getValue();
                }
                
            };
    
            sliderValue.addListener((obs, oldValue, newValue) -> 
                processSliderChange(newValue.doubleValue()));
    
            BorderPane root = new BorderPane(slider);
            Scene scene = new Scene(root, 200, 200);
            stage.setScene(scene);
            stage.show();
        }
        
        private void processSliderChange(double value) {
            System.out.printf("%.2f%n", value);
        }
    
        public static void main(String[] args) {
            launch();
        }
    
    }
    

    【讨论】:

      【解决方案2】:

      如何用箭头 (->) 捕捉变化的滑块?

      如果你想捕捉特定的事件,你可以像这样添加一个事件过滤器:

      scene.addEventFilter(KeyEvent.KEY_PRESSED, event -> {
          if(event.getCode() == KeyCode.RIGHT && slider.isFocused()) {
              System.out.println("Value changed because of key right pressed on slider").
          }
      }); 
      

      【讨论】:

      • 但是 OP 想要此代码禁用的功能:“如何另外捕获带有箭头的更改滑块?”
      • 以防万一他想要特定事件(->)。
      • 没错。他们确实希望捕获该事件。您的代码完全禁用该事件。另外,在其他情况下,滑块的值可以在 valueChangingProperty() 不变的情况下更改(向左箭头,或鼠标单击轨道等),因此这并不能解决根本问题。
      • 我只是在你的答案之后发布了我的答案,以防他想知道如何跟踪滑块上的特定右键按下事件。
      猜你喜欢
      • 1970-01-01
      • 2019-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-24
      • 2018-08-24
      • 2015-07-04
      • 2013-12-08
      相关资源
      最近更新 更多