1

I am running Java 8u102. I have a modal window that contains a Combobox whose items are a FilteredList created from a list of Strings. The ComboBox is editable so that the user can enter text (automatically converted to uppercase). The items in the ComboBox popup are then filtered such that only those items that start with the entered text remain. This works great.

The problem is that when you click an item in the filtered popup, the selected item will be properly displayed in the combobox editor and the popup will close, but an IndexOutOfBoundsException is thrown, probably starting in the code that created the window at the line - stage.showAndWait(). Below is the code running the ComboBox.

Any suggestions for a work-around? I plan to add more functionality to the combobox, but I'd like to deal with this issue first. Thanks.

  FilteredList<String> filteredList = 
     new FilteredList(FXCollections.observableArrayList(myStringList), p -> true);
  cb.setItems(filteredList);
  cb.setEditable(true);

  // convert text entry to uppercase
  UnaryOperator<TextFormatter.Change> filter = change -> {
     change.setText(change.getText().toUpperCase());
     return change;
  };
  TextFormatter<String> textFormatter = new TextFormatter(filter);
  cb.getEditor().setTextFormatter(textFormatter);

  cb.getEditor().textProperty().addListener((ov, oldValue, newValue) -> {
     filteredList.setPredicate(item -> {
         if (item.startsWith(newValue)) {
             return true; // item starts with newValue
         } else {
            return newValue.isEmpty(); // show full list if true; otherwise no match
         }
     });
  });
DVarga
  • 21,311
  • 6
  • 55
  • 60
H Dorne
  • 41
  • 4

1 Answers1

2

The problem is the same as in this question: You can wrap the content of the listener on the textProperty into a Platform.runLater block.

cb.getEditor().textProperty().addListener((ov, oldValue, newValue) -> {
    Platform.runLater(() -> {
        filteredList.setPredicate(item -> {
            if (item.startsWith(newValue)) 
                return true; // item starts with newValue
             else 
                return newValue.isEmpty(); // show full list if true; otherwise no match
        });
    });
});

Or the same in short form using ternary operator:

cb.getEditor().textProperty().addListener((ov, oldValue, newValue) -> Platform.runLater(
        () -> filteredList.setPredicate(item -> (item.startsWith(newValue)) ? true : newValue.isEmpty())));
Community
  • 1
  • 1
DVarga
  • 21,311
  • 6
  • 55
  • 60
  • Great answer. It supports my neophyte inclination that when something is acting a bit "goofy" in JavaFx that I'm the goofy one who is not recognizing concurrency issues and that I should consider Platform.runLater(() -> {}); It's interesting that a similar question was asked on the same day (and answered by you). Many thanks. – H Dorne Sep 28 '16 at 02:20
  • @DVarga if we have many items starts with the same letter is shows only the first item. – Menai Ala Eddine - Aladdin Apr 11 '18 at 13:04
  • @MenaiAlaEddine I could not reproduce that behaviour with 200k elements. Which Java version are you using? On which OS? – DVarga Apr 18 '18 at 09:27