ComboBox占位符不随机显示

时间:2015-09-15 10:13:28

标签: javafx combobox placeholder

每次您在另一个组合框中选择特定项目时,我都会显示ComboBox

我有一个Label作为占位符,直到加载了组合框的内容。它应该显示在组合框的弹出菜单中。大多数时候,它工作正常。但有时候,就像每五分之一或十分之一一样,没有占位符。相反,在加载内容之前只有一个白色单元格。

在下面的代码中,我设法重新创建了问题。但它并不完全相同。在我的原始代码中,白色单元格可能在我重新加载组合框时随时发生,但在我的MCVE中,它只在第一次加载组合框时出现(我几乎可以肯定)。

因此,当您重现问题时,启动应用程序并在第一个组合框中选择“bar”并检查占位符,如果正常,请重新启动应用程序并再试一次。如果在首先选择“foo”然后“bar”或直接选择“bar”时找不到任何区别。

对于记录,如果没有仅在第一个组合框中的特定选项上显示组合框,则无法重现该问题,因此可能导致问题。但设计需要这样。

import java.util.Arrays;
import java.util.List;

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

public class MCVE extends Application {

    @Override
    public void start(Stage stage) {

        VBox root = new VBox();
        root.setPrefSize(200, 200);

        ComboBox<String> selector = new ComboBox<String>();
        selector.getItems().addAll("foo", "bar");

        ComboBox<String> comboBox = new ComboBox<String>();

        root.getChildren().add(selector);

        selector.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue.equals("bar")) {
                root.getChildren().add(comboBox);
                comboBox.setEditable(true);

                 // Mock loading task.
                Task<List<String>> task = new Task<List<String>>() {
                    @Override
                    public List<String> call() throws Exception {

                        Thread.sleep(3000);
                        return Arrays.asList("One", "Two", "Three");
                    }
                };

                task.setOnSucceeded(e -> {
                    comboBox.getItems().addAll(
                            task.getValue());
                });

                Label loadLabel = new Label("loading");
                comboBox.setPlaceholder(loadLabel);

                task.stateProperty().addListener(
                        (o, oldState, newState) -> {
                            if (newState == State.RUNNING) {
                                // Do nothing in this MVCE.
                            } else {
                                comboBox.setPlaceholder(null);
                            }
                        });

                new Thread(task).start();

            } else {
                if (root.getChildren().contains(comboBox)) {
                    // This is done to simulate the functionality of the real application, 
                    //where choosing another option would remove the combo box and show something else.
                    comboBox.getItems().clear();
                    root.getChildren().remove(comboBox);    
                }
            }
        });

        Scene scene = new Scene(root);      
        stage.setScene(scene);
        stage.show();
    }

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

另一个问题:当加载弹出列表的内容时,列表将保持占位符的大小,直到您隐藏并再次显示弹出列表。我希望弹出窗口能够立即扩展。这可能吗?

编辑:Java版本1.8.0_60。操作系统:Windows 8.1 Enterprise。

2 个答案:

答案 0 :(得分:2)

你没有看到&#34; loading&#34; label是由于您在任务状态监听器中实现的逻辑:

    Label loadLabel = new Label("loading");
    comboBox.setPlaceholder(loadLabel);

    task.stateProperty().addListener(
            (o, oldState, newState) -> {
                if (newState == State.RUNNING) {
                    // Do nothing in this MVCE.
                } else {
                    comboBox.setPlaceholder(null);
                }
            });

    new Thread(task).start();

根据Javadocs for WorkerTask将在READY状态启动,然后转入SCHEDULED状态,然后再转到RUNNING状态。状态转换图看起来像:

enter image description here

因此,当它从READY过渡到SCHEDULED时,您的听众会将占位符设置为null,并且永远不会将其更改回来。只需将监听器更改为

即可
    task.stateProperty().addListener(
            (o, oldState, newState) -> {
                if (newState == State.RUNNING) {
                    comboBox.setPlaceholder(loadLabel);
                } else {
                    comboBox.setPlaceholder(null);
                }
            });

答案 1 :(得分:1)

我无法使用占位符重现问题。您使用的Java版本是什么?

问题的第二部分。 强制comboBox重绘。只需在添加项目之前隐藏它,然后再显示它是否显示。

            task.setOnSucceeded(e -> {
                boolean isShowing = false;
                if (comboBox.isShowing()) {
                     comboBox.hide();
                     isShowing = true;
                }
                comboBox.getItems().addAll(
                        task.getValue());
                if (isShowing) comboBox.show();
            });
相关问题