SweepingThoughts1
SweepingThoughts1

Reputation: 33

JavaFX Slider: How to only change value when dragging is done while also maintaining keyboard / touch support

JavaFX Slider Graph Application

How can I make the application so that the graph will only update when the slider has been let go, while still maintaining keyboard / touch screen support?

Replacing valueProperty().addListener() with setOnMouseReleased() will not allow the value to be changed with keyboard or touch screen anymore.

package application;

import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;

import javafx.scene.layout.VBox;
import javafx.scene.control.Slider;

import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;

import javafx.geometry.Insets;

public class SavingsCalculatorApplication extends Application {
    @Override
    public void start(Stage stage) {
        NumberAxis xAxis = new NumberAxis();
        NumberAxis yAxis = new NumberAxis();
        
        LineChart chart = new LineChart(xAxis, yAxis);
        chart.setLegendVisible(false);
        chart.setCreateSymbols(false);
        Slider slider = new Slider(0, 100, 10);
        slider.setShowTickLabels(true);
        slider.setShowTickMarks(true);
        slider.setPadding(new Insets(20, 40, 0, 40));
        
        XYChart.Series data = new XYChart.Series();
        chart.getData().add(data);
        
        slider.valueProperty().addListener(event -> {
            data.getData().clear();
            for(int counter = 0; counter < 100; counter++) {
                data.getData().add(new XYChart.Data(counter, counter * slider.getValue()));
            }
        });
        
        VBox layout = new VBox();
        layout.getChildren().add(slider);
        layout.getChildren().add(chart);
        
        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }
    
    public static void main(String[] args) {
        launch(SavingsCalculatorApplication.class);
    }
}

Upvotes: 2

Views: 383

Answers (1)

James_D
James_D

Reputation: 209358

Use the valueChanging property. You can respond when the value changes and valueChanging is false, which will happen if the slider changes by the keyboard (or programmatically), or when the valueChanging changes from true to false (which will happen when a change due to the mouse is completed):

    slider.valueProperty().addListener((obs, oldValue, newValue) -> {
        if ( !slider.isValueChanging()) {
            updateChart(newValue.doubleValue(), data);
        }
    });
    
    slider.valueChangingProperty().addListener((obs, wasChanging, isNowChanging) -> {
        if (! isNowChanging) {
            updateChart(slider.getValue(), data);
        }
    });

with

private void updateChart(double value, XYChart.Series data) {
    data.getData().clear();
    for(int counter = 0; counter < 100; counter++) {
        data.getData().add(new XYChart.Data(counter, counter * value));
    }
}

Never use low-level input events (mouse events, key events, etc) for semantic changes in a control. Always register listeners on the control's properties instead.

Upvotes: 1

Related Questions