Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8241999

ChoiceBox: incorrect toggle selected for uncontained selectedItem

XMLWordPrintable

      To reproduce, compile and run the example below
      - see the first item shown (and its toggle selected on opening the popup)
      - click button to select an uncontained item
      - expected and actual: value and selected item are sync'ed (verified by print out)
      [ ignore JDK-8087555:
      - expected uncontained items displayed
      - actual: old selected item displayed
      ]
      - open popup
      - expected: no toggle selected
      - actual: old toggle selected

      Reason is a broken invariant (also partly noted - kind-of, a bit upside down - in JDK-8088012) in the implementation of choiceBox' selectionModel (maybe even in its super SingleSelectionModel?):

      assertEquals(getItems().indexOf(selectedItem), getSelectedIndex())

      Fix in ChoiceBoxSelectionModel, override select(item) to explicitly set selectedIndex to -1 if not contained:

          @Override
          public void select(T obj) {
              super.select(obj);
              // super doesn't updatee selectedIndex for uncontained selectedItem
              // if we don't add this, the incorrect radioItem is marked selected
              // with uncontained selectedItem (after there had been a contained once)
              if (obj != null && !choiceBox.getItems().contains(obj)) {
                  setSelectedIndex(-1);
              }
          }

      It might be cleaner to fix this in SingleSelectionModel (at least in the long run). But ComboBox has a super constraint violation specified as intended behaviour (aside: I think that's utterly impossible!), better not touch super for now.

      The boundary between this issue and JDK-8087555 is that this is a failure in the selectionModel while the other is a failure in the skin


      The example:

      public class ChoiceBoxSelectedToggleBug extends Application {

          ObservableList<String> items = FXCollections.observableArrayList(
                  "5-item", "4-item", "3-item", "2-item", "1-item");
          private String title;

          private Parent getContent() {
              ChoiceBox<String> box = new ChoiceBox<>(items);
              box.setValue(box.getItems().get(0));
              Button setValue = new Button("Set value to uncontained");
              setValue.setOnAction(e -> {
                  box.setValue("myDummyValue");
                  System.out.println("value/ selected item: " + box.getValue() +
                          box.getSelectionModel().getSelectedItem());
              });
              BorderPane pane = new BorderPane(box);
              pane.setBottom(new HBox(10, setValue));
              title = box.getClass().getSimpleName();
              return pane;
          }

          @Override
          public void start(Stage primaryStage) throws Exception {
              Scene scene = new Scene(getContent());
              primaryStage.setScene(scene);
              primaryStage.setTitle(System.getProperty("java.version") + title);
              primaryStage.show();
          }

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

            fastegal Jeanette Winzenburg
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: