JavaFX滑块-箭头按钮(->;)移动滑块时未触发changeListener

JavaFX滑块-箭头按钮(->;)移动滑块时未触发changeListener,javafx,slider,Javafx,Slider,My valueChangingProperty Listener仅捕获由鼠标引起的事件(用鼠标拖动滑块或在滑块内的某个位置单击鼠标)。当我按下箭头按钮(->)时,它不会对滑块移动做出响应(因此其值会发生变化),尽管我看到它会导致滑块移动 MyController.java private Slider playRewindSlider; playRewindSlider.valueChangingProperty().addListener(new ChangeListener() {

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

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上看到了许多关于滑块的帖子,但没有一篇有效。

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

通常,您希望响应
值本身的更改:

playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
    // process newValue
});
valueChanging
属性的目的是避免在用户拖动拇指时执行大量更新。因此,您可以通过在侦听器中检查
值的属性来限制仅在更改完成时更新:

playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
    if (! playRewindSlider.isValueChanging()) {
        // process newValue
    }
});
请注意,用鼠标拖动拇指不会触发此操作(因为值会发生更改,但在最终更改之前,
valueChanging
不会设置为false)。因此,您需要包含第二个侦听器(您原来的
valueChanging
listener):

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

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

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

}

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

通常,您希望响应
值本身的更改:

playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
    // process newValue
});
valueChanging
属性的目的是避免在用户拖动拇指时执行大量更新。因此,您可以通过在侦听器中检查
值的属性来限制仅在更改完成时更新:

playRewindSlider.valueProperty().addListener((obs, oldValue, newValue) -> {
    if (! playRewindSlider.isValueChanging()) {
        // process newValue
    }
});
请注意,用鼠标拖动拇指不会触发此操作(因为值会发生更改,但在最终更改之前,
valueChanging
不会设置为false)。因此,您需要包含第二个侦听器(您原来的
valueChanging
listener):

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

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

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

}
如何使用箭头(->)捕捉正在更改的滑块

如果要捕获特定事件,可以添加如下事件筛选器:

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").
    }
}); 
如何使用箭头(->)捕捉正在更改的滑块

如果要捕获特定事件,可以添加如下事件筛选器:

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()
的情况下更改(向左箭头或鼠标单击轨迹等),因此,这并不能解决根本问题。我只是在你的答案之后发布了一个附加答案,以防他想知道如何在滑块上跟踪特定的右键按下事件。但OP想要此代码禁用的功能:“如何使用箭头额外捕捉变化的滑块?”以防他想要特定的事件(->)确切地他们确实希望捕捉到这一事件。您的代码完全禁用该事件。另外,在其他情况下,滑块的值可以在不更改
valueChangingProperty()
的情况下更改(向左箭头或鼠标单击轨迹等),所以这并不能解决根本的问题。我只是在你的答案后面加上了我的答案,以防他想知道如何在滑块上跟踪特定的右键按下事件。