连接具有StringConverter的Slider和Spinner

问题描述 投票:5回答:1

对于数字输入,有时可以方便地将模拟控制同步到文本显示。在这个Swing example中,JSpinnerJSlider各自监听变化事件,并且每个都更新另一个模型以匹配。类似的JavaFX程序,如下所示,连接SpinnerSlider,这些监听器使控件保持协调:

slider.valueProperty().addListener((Observable o) -> {
    spinner.getValueFactory().setValue(slider.getValue());
});
spinner.valueProperty().addListener((Observable o) -> {
    slider.setValue((double) spinner.getValue());
});

不幸的是,当我将StringConverter添加到微调器的SpinnerValueFactory时,初始值未格式化,直到任一控件被更改 - 即使在添加转换器后再次明确设置初始值时:

spinner.getValueFactory().setConverter(…);
spinner.getValueFactory().setValue(INITIAL_VALUE);

我哪里错了?

image

import java.text.NumberFormat;
import javafx.application.Application;
import javafx.beans.Observable;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.Spinner;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.converter.PercentageStringConverter;

/**
 * @see https://stackoverflow.com/a/6067986/230513
 */
public class SpinSlider extends Application {

    private static final double MIN = 0;
    private static final double MAX = 1;
    private static final double INITIAL_VALUE = 0.5;
    private static final double STEP_INCREMENT = 0.1;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("SpinSlider");
        Slider slider = new Slider(MIN, MAX, INITIAL_VALUE);
        slider.setBlockIncrement(STEP_INCREMENT);
        Spinner spinner = new Spinner(MIN, MAX, INITIAL_VALUE, STEP_INCREMENT);
        spinner.getValueFactory().setConverter(
            new PercentageStringConverter(NumberFormat.getPercentInstance()));
        spinner.getValueFactory().setValue(INITIAL_VALUE);
        slider.valueProperty().addListener((Observable o) -> {
            spinner.getValueFactory().setValue(slider.getValue());
        });
        spinner.valueProperty().addListener((Observable o) -> {
            slider.setValue((double) spinner.getValue());
        });
        GridPane root = new GridPane();
        root.addRow(0, slider, spinner);
        root.setPadding(new Insets(8, 8, 8, 8));
        root.setHgap(8);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}
java swing javafx slider spinner
1个回答
6
投票

你的INITIAL_VALUE首先被用作spinner构造函数的initialValue参数。在内部,旋转器的混凝土SpinnerValueFactory是一个DoubleSpinnerValueFactory,在其ChangeListener财产增加了value;当再次设置初始值时,该值并未真正改变。两种方法表明自己:

  1. 为构造函数指定不同的值,并在添加转换器后设置所需的值: Spinner spinner = new Spinner(MIN, MAX, -42, STEP_INCREMENT); spinner.getValueFactory().setConverter(…); spinner.getValueFactory().setValue(INITIAL_VALUE);
  2. 构造一个具有所需初始值的SpinnerValueFactory并使用它来构造微调器: SpinnerValueFactory factory = new SpinnerValueFactory .DoubleSpinnerValueFactory(MIN, MAX, INITIAL_VALUE, STEP_INCREMENT); factory.setConverter(…); Spinner spinner = new Spinner(factory);

此外,下面的示例使用双向绑定替换两个侦听器,该绑定使用弱侦听器来允许属性的垃圾收集:

slider.valueProperty().bindBidirectional(
    spinner.getValueFactory().valueProperty());

平凡的是,旋转器和滑块可以相互控制。更常见的是,每个人都可以在控制另一个模型所持有的财产的过程中保持同步:

model.xProperty().bindBidirectional(slider.valueProperty());
model.xProperty().bindBidirectional(spinner.getValueFactory().valueProperty());

image

import java.text.NumberFormat;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.Spinner;
import javafx.scene.control.SpinnerValueFactory;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.converter.PercentageStringConverter;

/**
 * @see https://stackoverflow.com/a/55427307/230513
 * @see https://stackoverflow.com/a/6067986/230513
 */
public class SpinSlider extends Application {

    private static final double MIN = 0;
    private static final double MAX = 1;
    private static final double INITIAL_VALUE = 0.5;
    private static final double STEP_INCREMENT = 0.1;

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("SpinSlider");
        Slider slider = new Slider(MIN, MAX, INITIAL_VALUE);
        slider.setBlockIncrement(STEP_INCREMENT);
        SpinnerValueFactory factory = new SpinnerValueFactory
            .DoubleSpinnerValueFactory(MIN, MAX, INITIAL_VALUE, STEP_INCREMENT);
        factory.setConverter(new PercentageStringConverter(
            NumberFormat.getPercentInstance()));
        Spinner spinner = new Spinner(factory);
        slider.valueProperty().bindBidirectional(spinner.getValueFactory().valueProperty());
        GridPane root = new GridPane();
        root.addRow(0, slider, spinner);
        root.setPadding(new Insets(8, 8, 8, 8));
        root.setHgap(8);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.