ADDITIONAL SYSTEM INFORMATION :
Linux 4.18.0-305.19.1.el8_4.x86_64 #1 SMP Wed Sep 15 19:12:32 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
openjdk version "11.0.13" 2021-10-19 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.13+8-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.13+8-LTS, mixed mode, sharing)
OpenJFX 13.0.1
OpenJFX 17.0.1
A DESCRIPTION OF THE PROBLEM :
ComboBoxes that have their item list (#getItems) bound via Bindings#getContentBindings lose their selected value when the backing list has its contents changed via ObservableList#setAll , even if the new content still contains the previously selected value.
The ComboBox value remains unchanged if the backing list is set via ComboBox#setItems instead of using a content binding.
The difference in behaviour seems as if it is not intentional. Also, the behaviour for the content binding variant seems unintuitive, given that the ComboBox Javadoc states "If the value property is set to a non-null object, and subsequently the items list is cleared, the value property IS NOT nulled out": If the value remains unchanged when the item list is cleared, it should probably also remain unchanged if the item list contents change.
The behaviour is always reproduceable with both OpenJFX 13.0.1 and OpenJFX 17.0.1 .
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Start the demo app
- Observe the state after the backing list's content have been programmatically changed (= when the app shows up), look at console output
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"B" is selected in both ComboBoxes
Expected console output:
(setItems) Value: B
(content binding) Value: B
ACTUAL -
(13.0.1, 17.0.1)
"B" is selected in the "setItems" ComboBox (left), null is selected in the "content binding" ComboBox (right).
Actual console output:
(setItems) Value: B
(content binding) Value: null
---------- BEGIN SOURCE ----------
public static class ComboBoxSetItemsVsContentBindingsSetAllApp extends Application {
/**
* What does this do? <br />
* - Creates two ComboBoxes backed by the same ObservableList. In one case, ComboBox#setItems is used, in the
* other, a content binding on ComboBox#getItems is used. <br />
* - The backing list is initialized with three strings, one of them is "B". "B" is programmatically selected in
* both ComboBoxes.<br />
* - We programmatically change the backing list's contents ("B" is still contained). <br />
* <p>
* What to try? <br />
* - Start the app <br />
* - Observe the state after the backing list's content are changed:<br />
* --- expected: "B" is selected in both ComboBoxes <br />
* --- actual (13.0.1, 17.0.1): "B" is selected in the "setItems" ComboBox (left), null is selected in the
* "content binding" ComboBox (right). <br />
*/
@Override
public void start(final Stage stage) throws Exception {
final ObservableList<String> baseList = FXCollections.observableArrayList();
baseList.addAll(List.of("A", "B", "C"));
final ComboBox<String> comboBoxWithSetItems = new ComboBox<>();
comboBoxWithSetItems.setItems(baseList);
initSelectionListeners(comboBoxWithSetItems, "comboBoxWithSetItems");
comboBoxWithSetItems.setValue("B");
final ComboBox<String> comboBoxWithContentBinding = new ComboBox<>();
Bindings.bindContent(comboBoxWithContentBinding.getItems(), baseList);
initSelectionListeners(comboBoxWithContentBinding, "comboBoxWithContentBinding");
comboBoxWithContentBinding.setValue("B");
System.out.println("Programmatic setAll call");
System.out.println("Changing contents...");
baseList.setAll(List.of("D", "B", "E"));
System.out.println("Changed contents");
final StackPane mainRoot = new StackPane(new VBox( //
new HBox( //
new VBox(new Label("--setItems--|"), comboBoxWithSetItems), //
new VBox(new Label("|--Content Binding--"), comboBoxWithContentBinding) //
)));
final Scene scene = new Scene(mainRoot);
stage.setTitle("ComboBoxSetItemsVsContentBindingsSetAllApp");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
private static void initSelectionListeners(final ComboBox<?> comboBox, String string) {
comboBox.valueProperty().addListener((obs, old, newV) -> {
System.out.println(string + " -- " + "new selected value: " + newV);
});
comboBox.getSelectionModel().selectedItemProperty().addListener((obs, old, newItem) -> {
System.out.println(string + " -- " + "new selected item: " + newItem);
});
comboBox.getSelectionModel().selectedIndexProperty().addListener((obs, old, newIndex) -> {
System.out.println(string + " -- " + "new selected index: " + newIndex);
});
}
public static void main(final String[] args) {
ComboBoxSetItemsVsContentBindingsSetAllApp.launch(args);
}
}
---------- END SOURCE ----------
FREQUENCY : always
Linux 4.18.0-305.19.1.el8_4.x86_64 #1 SMP Wed Sep 15 19:12:32 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
openjdk version "11.0.13" 2021-10-19 LTS
OpenJDK Runtime Environment 18.9 (build 11.0.13+8-LTS)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.13+8-LTS, mixed mode, sharing)
OpenJFX 13.0.1
OpenJFX 17.0.1
A DESCRIPTION OF THE PROBLEM :
ComboBoxes that have their item list (#getItems) bound via Bindings#getContentBindings lose their selected value when the backing list has its contents changed via ObservableList#setAll , even if the new content still contains the previously selected value.
The ComboBox value remains unchanged if the backing list is set via ComboBox#setItems instead of using a content binding.
The difference in behaviour seems as if it is not intentional. Also, the behaviour for the content binding variant seems unintuitive, given that the ComboBox Javadoc states "If the value property is set to a non-null object, and subsequently the items list is cleared, the value property IS NOT nulled out": If the value remains unchanged when the item list is cleared, it should probably also remain unchanged if the item list contents change.
The behaviour is always reproduceable with both OpenJFX 13.0.1 and OpenJFX 17.0.1 .
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
- Start the demo app
- Observe the state after the backing list's content have been programmatically changed (= when the app shows up), look at console output
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"B" is selected in both ComboBoxes
Expected console output:
(setItems) Value: B
(content binding) Value: B
ACTUAL -
(13.0.1, 17.0.1)
"B" is selected in the "setItems" ComboBox (left), null is selected in the "content binding" ComboBox (right).
Actual console output:
(setItems) Value: B
(content binding) Value: null
---------- BEGIN SOURCE ----------
public static class ComboBoxSetItemsVsContentBindingsSetAllApp extends Application {
/**
* What does this do? <br />
* - Creates two ComboBoxes backed by the same ObservableList. In one case, ComboBox#setItems is used, in the
* other, a content binding on ComboBox#getItems is used. <br />
* - The backing list is initialized with three strings, one of them is "B". "B" is programmatically selected in
* both ComboBoxes.<br />
* - We programmatically change the backing list's contents ("B" is still contained). <br />
* <p>
* What to try? <br />
* - Start the app <br />
* - Observe the state after the backing list's content are changed:<br />
* --- expected: "B" is selected in both ComboBoxes <br />
* --- actual (13.0.1, 17.0.1): "B" is selected in the "setItems" ComboBox (left), null is selected in the
* "content binding" ComboBox (right). <br />
*/
@Override
public void start(final Stage stage) throws Exception {
final ObservableList<String> baseList = FXCollections.observableArrayList();
baseList.addAll(List.of("A", "B", "C"));
final ComboBox<String> comboBoxWithSetItems = new ComboBox<>();
comboBoxWithSetItems.setItems(baseList);
initSelectionListeners(comboBoxWithSetItems, "comboBoxWithSetItems");
comboBoxWithSetItems.setValue("B");
final ComboBox<String> comboBoxWithContentBinding = new ComboBox<>();
Bindings.bindContent(comboBoxWithContentBinding.getItems(), baseList);
initSelectionListeners(comboBoxWithContentBinding, "comboBoxWithContentBinding");
comboBoxWithContentBinding.setValue("B");
System.out.println("Programmatic setAll call");
System.out.println("Changing contents...");
baseList.setAll(List.of("D", "B", "E"));
System.out.println("Changed contents");
final StackPane mainRoot = new StackPane(new VBox( //
new HBox( //
new VBox(new Label("--setItems--|"), comboBoxWithSetItems), //
new VBox(new Label("|--Content Binding--"), comboBoxWithContentBinding) //
)));
final Scene scene = new Scene(mainRoot);
stage.setTitle("ComboBoxSetItemsVsContentBindingsSetAllApp");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
private static void initSelectionListeners(final ComboBox<?> comboBox, String string) {
comboBox.valueProperty().addListener((obs, old, newV) -> {
System.out.println(string + " -- " + "new selected value: " + newV);
});
comboBox.getSelectionModel().selectedItemProperty().addListener((obs, old, newItem) -> {
System.out.println(string + " -- " + "new selected item: " + newItem);
});
comboBox.getSelectionModel().selectedIndexProperty().addListener((obs, old, newIndex) -> {
System.out.println(string + " -- " + "new selected index: " + newIndex);
});
}
public static void main(final String[] args) {
ComboBoxSetItemsVsContentBindingsSetAllApp.launch(args);
}
}
---------- END SOURCE ----------
FREQUENCY : always
- relates to
-
JDK-8263942 ComboBox: action incorrectly triggered after items.setAll
-
- Open
-