首页 > 解决方案 > JavaFX:在 ListView 中显示图像而不破坏选择模型

问题描述

问题

我想显示一个包含文本和图像的列表。我能够做到这一点,但选择模型很时髦。当我用鼠标选择列表中的一个项目时,似乎选择了整个列表视图元素。当我使用箭头键时,选择模型工作正常。

我的代码

在我的控制器中,我有ObservableList<Game> gameList. 游戏类如下所示:

public class Game {
    private String name;
    private Image image;
}

Stack Overflow 上旧解决方案的示例

在搜索有关如何显示图像和名称的解决方案时,我发现许多 Stack Overflow 解决方案都使用了setCellFactory以下代码片段这样的方法:

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);
                }
            }
        });

我的解决方案尝试

但是,我想要显示的图像存储在我的 ObservableList 中的 Game 对象中。根据我的理解,String item上面的参数是 Game 对象toString方法,但是我想在制作自定义 ListCell 时访问整个 Game 对象。我试图更改该解决方案以访问整个 Game 对象。这是我的代码目前的样子:

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);
                }
            }
        });
    }
}

结果

使用上面的代码,我可以在我的 ListView 中显示每个游戏及其名称。 在此处输入图像描述

我试图解决的问题

该列表完全按照我想要的方式显示,但选择模型似乎被破坏了。我listView.getSelectionModel().getSelectedItem();用来获取选定的游戏。当我使用鼠标选择一个项目时,上面的方法返回 null。这是我左键单击列表中的“其他游戏”项时的样子: 在此处输入图像描述

但是,我可以使用箭头键来选择列表中我想要的任何项目。当我这样做时,从我的 ObservableList 中选择的游戏被返回。

有谁知道我该如何解决这个问题?

标签: javaimagelistviewjavafxobservablelist

解决方案


ListCell.updateItem(...)除其他外,默认方法处理选择。所以你需要确保调用它。

文档中:

Cell 的子类正确覆盖 updateItem方法非常重要……请注意此代码示例中的两个重点:

  1. 我们调用 super.updateItem(T, boolean) 方法。如果不这样做,则 item 和 empty 属性设置不正确,您最终可能会遇到图形问题。
  2. ...

所以你需要:

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);
        }
    }
});

推荐阅读