【问题标题】:Stage.show() changes value of ComboBoxStage.show() 改变 ComboBox 的值
【发布时间】:2016-08-26 10:16:16
【问题描述】:

考虑以下 MCVE。当然,这个 MCVE 的功能完全没有意义,但我需要它在实际实现中以这种方式工作。

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

@SuppressWarnings("all")
public class MCVE extends Application {

    private static final String OPTION_1 = "Option 1 (www.option1.com)";
    private static final String OPTION_2 = "Option 2 (www.option2.com)";
    private static final String OPTION_3 = "Option 3 (www.option3.com)";
    private static final String OPTION_4 = "Option 4 (www.option4.com)";
    private static final String OPTION_5 = "Option 5 (www.option5.com)";

    ComboBox<String> cb;

    @Override
    public void start(Stage primaryStage) throws Exception {
        VBox outer = new VBox();

        cb = new ComboBox<String>();
        outer.getChildren().add(cb);

        Scene scene = new Scene(outer, 640, 480);
        primaryStage.setScene(scene);

        Task<Void> task = new Task<Void>() {
            @Override
            public Void call() {
                cb.getItems().addAll(OPTION_1, OPTION_2, OPTION_3, OPTION_4, OPTION_5);
                cb.setEditable(true);

                // Adds a listener to the selectedItemProperty that gets the
                // value inside the parenthesis of the selected item and sets
                // this as the text of the ComboBox.
                cb.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> {
                    String[] valSplit = newValue.split("[\\(\\)]");
                    if (valSplit.length > 1) {
                        Platform.runLater(() -> cb.getEditor().setText(valSplit[1]));
                    }
                });

                cb.getEditor().textProperty().addListener((obs, oldValue, newValue) -> {
                    System.out.println("CB value: " + newValue);
                });

                setURL("www.option2.com");

                return null;
            }
        };

        task.setOnSucceeded(e -> {
            primaryStage.show();
        });

        new Thread(task).start();
    }

    public void setURL(String url) {
        // First we check if the classValue is the URL of one of the options in
        // the ComboBox. If it is we select that option.
        for (String option : cb.getItems()) {
            // We retrieve the URL of the option.
            String opURL = option.split("[\\(\\)]")[1];
            // If the URL of the option is equals to the provided URL, we select
            // this option and break the for loop.
            if (opURL.equals(url)) {
                cb.getSelectionModel().select(option);
                break;
            }
        }
    }

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

由于我调用setURL("www.option2.com"),我希望它首先选择带有该URL 的ComboBox 中的选项,然后获取括号内的值并将其设置为ComboBox 的文本。所以我除了ComboBox 的最终值是“www.option2.com”。但这不会发生。相反,最终值为“选项 2 (www.option2.com)”。

由于我在ComboBoxtextProperty 中添加了一个侦听器,我可以看到该值首先是预期的“www.option2.com”,但随后又变回“选项 2 (www.option2 .com)”。经过进一步调查,我发现是调用primaryStage.show() 改变了值。更具体地说,是对已弃用的 Parent.impl_processCSS 的调用改变了值。

因此,如果我在primaryStage.show() 之后设置 URL,则除此之外一切正常。但是,如果我想在显示对话框之前完成所有工作,就像我现在所做的那样,它不会。

那么为什么primaryStage.show() 会改变我的ComboBox 的值,我该如何防止呢?在尝试设置 ComboBox 的值时,我是否应该使用其他方法?

【问题讨论】:

    标签: java javafx combobox stage


    【解决方案1】:

    您可以将设置ComboBoxeditor 文本的部分代码与设置cell factoryconverter 的代码交换。

    cb.setConverter(new StringConverter<String>(){
        @Override
        public String toString(String object) {
            if(object != null) {
                String[] valSplit = object.split("[\\(\\)]");
                return valSplit[1];
            } else 
                return null;
    
        }
    
        @Override
        public String fromString(String string) {
    
            List<String> collect = cb.getItems().stream().filter(s -> s.contains(string)).collect(Collectors.toList());
            if(collect.size() == 1)
                return collect.get(0);
            else
                return null;
        }
    });
    
    cb.setCellFactory(item -> {
        return new ListCell<String>(){
            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
    
                if(item == null || empty)
                    setText("");
                else
                    setText(item);
            }
        };
    });
    

    您的转换器的toString 方法会将所选项目格式化为所需的形式,并且单元工厂确保下拉列表中的项目以原始格式显示。

    注意:我还填了转换器的fromString方法。当用户在编辑器中键入然后按enter 时,将执行此方法。此实现检查列表中的所有项目,如果只有一个项目包含键入的字符串,则该项目将被选中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2023-03-12
      • 2019-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多