【问题标题】:JavaFX Spinner works incorrectly. Spinner.valueProperty().addListener changed twiceJavaFX Spinner 工作不正常。 Spinner.valueProperty().addListener 改变了两次
【发布时间】:2019-12-13 22:03:22
【问题描述】:

我不明白为什么,如果 Spinner 调用 ChangeListener 两次。我怎样才能让它只调用一次?

Controller.java

public class Controller {
@FXML
Spinner<Double> spinner;
@FXML
public void initialize(){
    spinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0,350,60,1));

    spinner.valueProperty().addListener(new ChangeListener<Double>() {
        @Override
        public void changed(ObservableValue<? extends Double> observable, Double oldValue, Double newValue) {
            System.out.println("Old Value" + oldValue + "New Value" + newValue);
        }
    });
}}

Main.java

 public class Main extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception{
        Parent root =     FXMLLoader.load(getClass().getResource("sample.fxml"));
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();
    }
    public static void main(String[] args) {
        launch(args);
    }}

输出:

Old Value 60.0 New Value 780.0
Old Value 780.0 New Value 350.0

【问题讨论】:

  • 两次调用时输入什么值?大于 350?
  • 是的,例如我输入780

标签: java javafx javafx-8 spinner


【解决方案1】:

因为SpinnerValueFactory:

spinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0,350,60,1));

Spinner 的最大值为 350。您输入 780:该值正在更改为该值,然后由于最大值而变回 350。


更新:

默认情况下,当按下 Enter 键时,Spinner 的编辑器内的值会被提交。

为避免自动绑定,您可以尝试覆盖默认提交逻辑:

spinner.getEditor().setOnAction(e -> {

    String text = spinner.getEditor().getText();
    SpinnerValueFactory<Double> valueFactory = spinner.getValueFactory();
    if (valueFactory != null) {
        StringConverter<Double> converter = valueFactory.getConverter();
        if (converter != null) {
            try{
                Double value = converter.fromString(text);
                if (value >= minValue && value <= maxValue)
                    valueFactory.setValue(value);
                else
                    valueFactory.setValue(Math.max(Math.min(maxValue, value), minValue));

                // This ensures that if the value us e.g. 350, then 450 entered, the text 
                // is updated to 350 again (rather than ramaining 450)
                spinner.getEditor().setText(converter.toString(valueFactory.getValue()));
            } catch(NumberFormatException nfe){
                spinner.getEditor().setText(converter.toString(valueFactory.getValue()));
            }
        }
    }

    e.consume();
});

值定义为:

double maxValue = 350;
double minValue = 0;
spinner.setValueFactory(
    new SpinnerValueFactory.DoubleSpinnerValueFactory(minValue, maxValue, 60, 1));

注意:

最小值和最大值也可以从SpinnerValueFactory 中检索 - 不幸的是,不是以完全干净的方式,而是进行了一些转换:

spinner.getEditor().setOnAction(e -> {
    SpinnerValueFactory.DoubleSpinnerValueFactory valueFactory = (SpinnerValueFactory.DoubleSpinnerValueFactory) spinner.getValueFactory();

    if (valueFactory != null) {
        StringConverter<Double> converter = valueFactory.getConverter();
        if (converter != null) {
            try {
                valueFactory.setValue(Math.max(Math.min(valueFactory.getMax(), 
                        converter.fromString(spinner.getEditor().getText())), valueFactory.getMin()));

                spinner.getEditor().setText(converter.toString(valueFactory.getValue()));

            } catch(NumberFormatException nfe){
                spinner.getEditor().setText(converter.toString(valueFactory.getValue()));
            }
        }
    }

    e.consume();
});

但在这种情况下,不需要存储最小值和最大值,它们是从工厂本身获取的:

spinner.setValueFactory(new SpinnerValueFactory.DoubleSpinnerValueFactory(0, 350, 60, 1));

【讨论】:

  • 是的,但是我怎样才能只做一个调用方法 public void changed() ?
  • 另一种选择是在编辑器上设置TextFormatter,并否决(或修改)超出范围的更改。
  • @James_D 是的,这绝对是真的。我只是不想创建一个 tl;dr 答案:)
猜你喜欢
  • 1970-01-01
  • 2016-10-24
  • 2022-01-06
  • 1970-01-01
  • 2015-12-07
  • 2016-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多