【问题标题】:Javafx ListView with Images instead of Strings带有图像而不是字符串的 Javafx ListView
【发布时间】:2015-04-08 13:01:17
【问题描述】:

我正在尝试在我的程序中制作带有电影图片的横幅,但我无法将包含图像网址的列表转换为实际图像。
我该怎么做,这是我当前的代码:

public void initData(boolean onlineProvider, String uritext) {
        op = Providers.createTestProvider();
        List<Movie> films = (List<Movie>) op.getMovieDAO().listFiltered();
        ObservableList<String> posters = FXCollections.observableArrayList();
        for( Movie movie : films){
            String poster = movie.getPoster();
            posters.add(poster);

        }
        banner.setOrientation(Orientation.HORIZONTAL);
        banner.setItems(posters);

    }
}

明确地说,banner 是一个 ListView。

【问题讨论】:

    标签: listview javafx imageview


    【解决方案1】:

    使用细胞工厂。您需要在创建ListView 的位置使用此代码(如果您在 FXML 控制器中,则在 initialize() 方法中):

    banner.setCellFactory(listView -> new ListCell<String>() {
        private ImageView imageView = new ImageView();
    
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setGraphic(null);
            } else {
                // true makes this load in background
                // see other constructors if you want to control the size, etc
                Image image = new Image(item, true) ; 
                imageView.setImage(image);
                setGraphic(imageView);
            }
        }
    });
    

    这是一个在ListView 中显示图像的完整示例:

    import java.io.File;
    import java.io.IOException;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.util.ArrayList;
    import java.util.List;
    
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.geometry.Insets;
    import javafx.geometry.Pos;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.ListCell;
    import javafx.scene.control.ListView;
    import javafx.scene.control.TextField;
    import javafx.scene.image.Image;
    import javafx.scene.image.ImageView;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.layout.HBox;
    import javafx.scene.layout.StackPane;
    import javafx.stage.DirectoryChooser;
    import javafx.stage.Stage;
    
    public class ListViewImageBrowser extends Application {
    
        @Override
        public void start(Stage primaryStage) {
            ObservableList<Path> imageFiles = FXCollections.observableArrayList();
    
            TextField directoryField = new TextField();
            Button browseButton = new Button("Browse");
            Button loadButton = new Button("Load");
    
            EventHandler<ActionEvent> loadHandler = event -> imageFiles.setAll(load(Paths.get(directoryField.getText())));
            loadButton.setOnAction(loadHandler);
            directoryField.setOnAction(loadHandler);
    
            browseButton.setOnAction(event -> {
                DirectoryChooser chooser = new DirectoryChooser();
                File file = chooser.showDialog(primaryStage);
                if (file != null) {
                    directoryField.setText(file.toString());
                    imageFiles.setAll(load(file.toPath()));
                }
            });
    
            HBox controls = new HBox(5, directoryField, browseButton, loadButton);
            controls.setAlignment(Pos.CENTER);
            controls.setPadding(new Insets(5));
    
            ListView<Path> imageFilesList = new ListView<>(imageFiles);
            imageFilesList.setCellFactory(listView -> new ListCell<Path>() {
                private final ImageView imageView = new ImageView();
    
               @Override
                public void updateItem(Path path, boolean empty) {
                    super.updateItem(path, empty);
                    if (empty) {
                        setText(null);
                        setGraphic(null);
                    } else {
                        setText(path.getFileName().toString());
                        imageView.setImage(new Image(path.toUri().toString(), 80, 160, true, true, true));
                        setGraphic(imageView);
                    }
                }
            });
    
    
            ImageView imageView = new ImageView();
            imageFilesList.getSelectionModel().selectedItemProperty().addListener((obs, oldFile, newFile) -> {
                if (newFile == null) {
                    imageView.setImage(null);
                } else {
                    imageView.setImage(new Image(newFile.toUri().toString(), true));
                }
            });
            imageFilesList.setMinWidth(200);
    
            StackPane imageHolder = new StackPane(imageView);
            imageView.fitWidthProperty().bind(imageHolder.widthProperty());
            imageView.fitHeightProperty().bind(imageHolder.heightProperty());
            imageView.setPreserveRatio(true);
    
            BorderPane root = new BorderPane(imageHolder, controls, null, null, imageFilesList);
    
            Scene scene = new Scene(root, 800, 600);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        private List<Path> load(Path directory) {
            List<Path> files = new ArrayList<>();
            try {
                Files.newDirectoryStream(directory, "*.{jpg,jpeg,png,JPG,JPEG,PNG}").forEach(file -> files.add(file));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return files ;
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    【讨论】:

    • 我应该把它放在哪里?在 setItems 或以上? @James_D
    • 初始化列表视图时。不要在每次设置项目时都执行此操作。
    • 我已经把它放在了初始化(方法)中,但是现在我得到了一个没有任何内容的 ListView...甚至没有 URL 字符串,并且 imagesurl 没有任何问题:upload.wikimedia.org/wikipedia/en/c/ca/…@詹姆斯_D
    • 那么可能是 url 没有正确映射。我会通过将ImageView 以相同的方式直接在您的 UI 某处构建来测试其中的一两个。我写了一个有点相似的例子;我会用它来更新答案。
    • 我真的不明白为什么它不起作用,我只是使用了这段代码: Image image = new Image(posters.get(1)); testimage.setImage(图像);我有一个 ImageView,有没有更好的方法来获得带有图像的水平横幅?
    【解决方案2】:

    James_D 为您提供了非基础 fxml 应用程序的答案,如果您在 FXM 和 Controller 应用程序中进行开发,请记住刷新或加载您的 Listview 与 myListViewWithPath.setItems(myObserverFilledWithImages);

    @FXML
        private void browseButton(ActionEvent event) throws Exception {
            System.out.println("browseButton");
            DirectoryChooser chooser = new DirectoryChooser();
            File file = chooser.showDialog(myStage);
            file = new File("E:\\FOLDER\\Imagen_File");
    
            if (file != null) {
                directoryField.setText(file.toString());
                oImage.setAll(load(file.toPath()));
            }
            imageFilesList.setItems(oImage); //this one load or refresh the ListView
        }
    

    【讨论】:

      【解决方案3】:

      最好的答案是:

      ListView<ImageView> listView = new listView();
      ObservableList<ImageView> items = FXCollections.observableArrayList();
      listView.setItems(items);
      

      ListView 是通用的 - 使用它。

      然后使用 将项目(在本例中为图像)添加到您的列表中:

      ImageView item = new ImageView("file:myimage.png");
      listView.getItems().add(item);
      

      【讨论】:

      • 永远不要使用Node 子类作为控件的数据类型。一方面,您将为列表中的每个 item 而不是每个 cell 加载图像,因此您的应用程序将无法扩展 - 对于列表中的足够项目,您将内存不足;另一方面,你正在打破责任分离的范式。
      猜你喜欢
      • 2017-03-20
      • 2013-03-17
      • 2017-05-18
      • 2012-01-02
      • 1970-01-01
      • 2021-03-05
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多