I have been endeavoring to implement an event listener for an editable ComboBox
which will add the edited item to the end of the list in an application, but this throws IndexOutOfBoundsException
when the edited item is committed. I do not understand why this should be.
Consequently I have created a simplified application as follows and also tried enclosing the code which adds the edited item in a Platform.runLater()
block but the issue persists.
Can anybody please suggest what may be causing this exception?
Thanks very much.
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class ComboBoxTest extends Application {
ComboBox<String> cbItems;
Label lblResponse;
public static void main(String[] args) {
launch(args);
}
public void start(Stage stage) {
stage.setTitle("ComboBox Demo");
FlowPane root = new FlowPane(10, 10);
root.setAlignment(Pos.TOP_CENTER);
Scene scene = new Scene(root, 240, 120);
stage.setScene(scene);
lblResponse = new Label();
ObservableList<String> items =
FXCollections.observableArrayList("item1", "item2", "item3", "item4", "item5");
cbItems = new ComboBox<String>(items);
cbItems.setValue("item1");
cbItems.setEditable(true);
lblResponse.setText("Selected item is " + cbItems.getValue());
// Listen for action events on the combo box.
cbItems.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent ae) {
lblResponse.setText("Selected item is " + cbItems.getValue());
//add the modified item to the end of the list
int i = cbItems.getSelectionModel().getSelectedIndex();
if(!items.get(i).equals(cbItems.getValue())){
items.add(cbItems.getValue());
}
}
});
root.getChildren().addAll(cbItems, lblResponse);
stage.show();
}
}
Look at [the start of] the stack trace...
Exception in thread "JavaFX Application Thread" java.lang.IndexOutOfBoundsException: Index -1 out of bounds for length 5
at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
at java.base/java.util.Objects.checkIndex(Objects.java:359)
at java.base/java.util.ArrayList.get(ArrayList.java:427)
at javafx.base/com.sun.javafx.collections.ObservableListWrapper.get(ObservableListWrapper.java:89)
at jfxprjct/jfxtests.ComboBoxTest$1.handle(ComboBoxTest.java:52)
Now look at line 52 in file ComboBoxTest.java
.
(Note that it may be a different line number in your stack trace.)
For me, this is line 52
if(!items.get(i).equals(cbItems.getValue())){
In other words, the value of i
is -1
(minus one). And i
is assigned a value in the line preceding the if
statement.
int i = cbItems.getSelectionModel().getSelectedIndex();
In other words, there is no selected index. So you should first check the value of i
and not assume that it is a valid index value.
However, a better condition (in my opinion) would be
if(!cbItems.getItems().contains(cbItems.getValue())){
Then you don't need the selected index at all.