ComboBox 占位符未随机显示
ComboBox placeholder not showing randomly
我有一个 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。 OS:windows 8.1 企业。
我无法重现占位符的问题。您使用的 Java 版本是什么?
问题的第二部分。
强制组合框重绘。只需在添加项目之前隐藏它,然后在显示时再次显示它。
task.setOnSucceeded(e -> {
boolean isShowing = false;
if (comboBox.isShowing()) {
comboBox.hide();
isShowing = true;
}
comboBox.getItems().addAll(
task.getValue());
if (isShowing) comboBox.show();
});
您看不到 "loading" 标签的原因是您在任务的状态侦听器中实施的逻辑:
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 Worker
,一个Task
会从READY
状态开始,然后过渡到SCHEDULED
状态,然后再进入RUNNING
状态。状态转换图类似于:
因此,当它从 READY
过渡到 SCHEDULED
时,您的侦听器会将占位符设置为 null
,并且永远不会将其改回。只需将侦听器更改为
task.stateProperty().addListener(
(o, oldState, newState) -> {
if (newState == State.RUNNING) {
comboBox.setPlaceholder(loadLabel);
} else {
comboBox.setPlaceholder(null);
}
});
我有一个 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。 OS:windows 8.1 企业。
我无法重现占位符的问题。您使用的 Java 版本是什么?
问题的第二部分。 强制组合框重绘。只需在添加项目之前隐藏它,然后在显示时再次显示它。
task.setOnSucceeded(e -> {
boolean isShowing = false;
if (comboBox.isShowing()) {
comboBox.hide();
isShowing = true;
}
comboBox.getItems().addAll(
task.getValue());
if (isShowing) comboBox.show();
});
您看不到 "loading" 标签的原因是您在任务的状态侦听器中实施的逻辑:
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 Worker
,一个Task
会从READY
状态开始,然后过渡到SCHEDULED
状态,然后再进入RUNNING
状态。状态转换图类似于:
因此,当它从 READY
过渡到 SCHEDULED
时,您的侦听器会将占位符设置为 null
,并且永远不会将其改回。只需将侦听器更改为
task.stateProperty().addListener(
(o, oldState, newState) -> {
if (newState == State.RUNNING) {
comboBox.setPlaceholder(loadLabel);
} else {
comboBox.setPlaceholder(null);
}
});