I want to display a list that contains text and an image. I am able to do that, but the selection model is funky. When I select an item in the list with my mouse, it seems like the entire listview element is selected. When I use the arrow keys, the selection model works fine.
In my controller I have ObservableList<Game> gameList
. The Game class looks like this:
public class Game {
private String name;
private Image image;
}
When searching for a solution on how to display the image and name, I found many Stack Overflow solutions that used the setCellFactory
method like the code snippet below:
listView.setCellFactory(param -> new ListCell<>() {
private final ImageView imageView = new ImageView();
@Override
public void updateItem(String item, boolean empty) {
if (empty) {
setText(null);
setGraphic(null);
} else {
imageView.setImage(/*Some image*/);
setText(game.getName());
setGraphic(imageView);
}
}
});
However, the image that I want to display is stored in the Game object in my ObservableList. From my understanding, the String item
parameter above is the Game objects toString
method, but I want access to the entire Game object when making my custom ListCell. I tried to alter that solution to get access to the entire Game object instead. This is what my code currently looks like:
public class MyController implements Initializable {
@FXML
public ListView<Game> listView;
public ObservableList<Game> gameList;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
gameList = FXCollections.observableList(/*List of games*/);
listView.setItems(gameList);
listView.setCellFactory(param -> new ListCell<>() {
private final ImageView imageView = new ImageView();
@Override
public void updateItem(Game game, boolean empty) {
if (empty) {
setText(null);
setGraphic(null);
} else {
imageView.setImage(game.getImage());
setText(game.getName());
setGraphic(imageView);
}
}
});
}
}
With the code above, I'm able to display each Game and it's name in my ListView.
The list is displayed exactly like I want, but the selection model seems to be broken.
I use listView.getSelectionModel().getSelectedItem();
to fetch the selected Game. When I use my mouse to select an item, the method above returns null. This is what it looks like when I left click on the "Other game" item in the list:
However, I can use my arrow keys to select any item in the list I want. When I do that, the selected Game from my ObservableList is returned.
Does anyone have an idea of how I can solve this?
The default ListCell.updateItem(...)
method handles selection, among other things. So you need to be sure to call it.
From the documentation:
It is very important that subclasses of Cell override the updateItem method properly ... Note in this code sample two important points:
- We call the super.updateItem(T, boolean) method. If this is not done, the item and empty properties are not correctly set, and you are likely to end up with graphical issues.
- ...
So you need:
listView.setCellFactory(param -> new ListCell<>() {
private final ImageView imageView = new ImageView();
@Override
public void updateItem(Game game, boolean empty) {
// call default implementation:
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
imageView.setImage(game.getImage());
setText(game.getName());
setGraphic(imageView);
}
}
});