How to synchronize slider and spinner ? When the value of one changes, the value of the second changes. How to make them work together?

Code:

 public class Main extends Application { private FlowPane pane; private Scene scene; private Stage stage; private Label label; public void start(Stage stage) { Slider slider = new Slider(); slider.setMin(1); slider.setMax(9); slider.setValue(3); slider.setShowTickLabels(true); slider.setBlockIncrement(1); Spinner <Integer> spinner = new Spinner <Integer> (); final int initialValue= 3; SpinnerValueFactory<Integer> valueFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(1,9,initialValue ); spinner.setValueFactory(valueFactory); this.stage = stage; pane = new FlowPane(); pane.getChildren().addAll(spinner, slider); scene = new Scene(pane , 350 , 150); stage.setScene(scene); stage.show(); } public static void main(String[] args) { launch(args); } } 

    2 answers 2

    With Spinner<Integer> spinner big problems with casting, so you can try this:

     Spinner<Double> spinner = new Spinner<>(); final double initialValue = 3D; SpinnerValueFactory<Double> valueFactory = new SpinnerValueFactory.DoubleSpinnerValueFactory( 1D, 9D, initialValue, 1D ); spinner.setValueFactory( valueFactory ); valueFactory.valueProperty().bindBidirectional( slider.valueProperty().asObject() ); valueFactory.setConverter( new StringConverter<Double>() { private final DecimalFormat df = new DecimalFormat("#"); @Override public String toString( Double value ) { if ( value == null ) return ""; return df.format( value ); } @Override public Double fromString( String value ) { try { if ( value == null ) return null; value = value.trim(); if ( value.length() < 1 ) return null; return df.parse(value).doubleValue(); } catch ( ParseException ex ) { throw new RuntimeException( ex ); } } }); 

      It's funny, but when using the SimpleStringProperty intermediate, only one single option worked:

        // Связываем ObjectProperty<Integer> и DoubleProperty через промежуточное свойство: SimpleStringProperty sp = new SimpleStringProperty(); sp.bindBidirectional(valueFactory.valueProperty(), new IntegerStringConverter()); sp.bindBidirectional(slider.valueProperty(), new DecimalFormat("0")); 

      The final option:

       import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.scene.Scene; import javafx.scene.control.Slider; import javafx.scene.control.Spinner; import javafx.scene.control.SpinnerValueFactory; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.converter.IntegerStringConverter; import java.text.DecimalFormat; public class SliderSpinnerMain extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { Slider slider = new Slider(); slider.setMin(1); slider.setMax(9); slider.setValue(3); slider.setShowTickLabels(true); slider.setBlockIncrement(1); // еще немного приукрасим: slider.setSnapToTicks(true); slider.setMajorTickUnit(1); slider.setMinorTickCount(0); Spinner<Integer> spinner = new Spinner<Integer>(); final int initialValue = 3; SpinnerValueFactory<Integer> valueFactory = new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 9, initialValue); spinner.setValueFactory(valueFactory); // Связываем ObjectProperty<Integer> и DoubleProperty через промежуточное свойство: SimpleStringProperty sp = new SimpleStringProperty(); sp.bindBidirectional(valueFactory.valueProperty(), new IntegerStringConverter()); sp.bindBidirectional(slider.valueProperty(), new DecimalFormat("0")); VBox root = new VBox(spinner, slider); Scene scene = new Scene(root, 430, 200); primaryStage.setScene(scene); primaryStage.show(); } } 

      On the other hand, it is possible to do without the intermediate SimpleStringProperty - just handlers to write:

        // Связываем ObjectProperty<Integer> и DoubleProperty: slider.valueProperty().addListener( (ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> { valueFactory.setValue((int) Math.round(newValue.doubleValue())); }); spinner.valueProperty().addListener( (ObservableValue<? extends Integer> observable, Integer oldValue, Integer newValue) -> { if (newValue != (int) Math.round(slider.getValue())) slider.setValue(newValue); });