每次您在另一个组合框中选择特定项目时,我都会显示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。
答案 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 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);
}
});
答案 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();
});