Stage.show() 更改 ComboBox 的值
Stage.show() changes value of ComboBox
考虑以下 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")
,我希望它首先 select ComboBox
中的选项与那个 URL,然后获取括号内的值和将其设置为 ComboBox
的文本。所以我除了 ComboBox
的最终值为 "www.option2.com"。但这不会发生。相反,最终值为 "Option 2 (www.option2.com)".
因为我已经为 ComboBox
的 textProperty
添加了一个侦听器,我可以看到该值首先是预期的 "www.option2.com",但随后又变回 "Option 2 (www.option2.com)".经过进一步调查,我发现是 primaryStage.show()
的调用改变了值。更具体地说,是调用已弃用的 Parent.impl_processCSS
更改了值。
因此,如果我在 primaryStage.show()
之后设置 URL,除此之外,一切正常。但是如果我想在显示对话框之前完成所有工作,就像我现在所做的那样,它不会。
那么为什么 primaryStage.show()
会改变我的 ComboBox
的值,我该如何防止呢?在尝试设置 ComboBox
?
的值时,我是否应该使用另一种方法
您可以交换设置 editor of the ComboBox
with some code that sets up a cell factory and a converter 文本的代码部分。
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
时,将执行此方法。此实现检查列表中的所有项目,如果只有一个项目包含键入的字符串,则将选择该项目。
考虑以下 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")
,我希望它首先 select ComboBox
中的选项与那个 URL,然后获取括号内的值和将其设置为 ComboBox
的文本。所以我除了 ComboBox
的最终值为 "www.option2.com"。但这不会发生。相反,最终值为 "Option 2 (www.option2.com)".
因为我已经为 ComboBox
的 textProperty
添加了一个侦听器,我可以看到该值首先是预期的 "www.option2.com",但随后又变回 "Option 2 (www.option2.com)".经过进一步调查,我发现是 primaryStage.show()
的调用改变了值。更具体地说,是调用已弃用的 Parent.impl_processCSS
更改了值。
因此,如果我在 primaryStage.show()
之后设置 URL,除此之外,一切正常。但是如果我想在显示对话框之前完成所有工作,就像我现在所做的那样,它不会。
那么为什么 primaryStage.show()
会改变我的 ComboBox
的值,我该如何防止呢?在尝试设置 ComboBox
?
您可以交换设置 editor of the ComboBox
with some code that sets up a cell factory and a converter 文本的代码部分。
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
时,将执行此方法。此实现检查列表中的所有项目,如果只有一个项目包含键入的字符串,则将选择该项目。