带有图标和文件名的 JavaFX 文件列表视图

JavaFX file listview with icon and file name

在 JavaFX 对话框中,我想显示一个文件列表及其图标和文件名。

很容易找到如何获取文件扩展名的图标:

File file = File.createTempFile("icon", ".doc");  
FileSystemView view = FileSystemView.getFileSystemView();      
java.swing.Icon icon = view.getSystemIcon(file);      
file.delete();

但是,如何在 JavaFX ListView 中绘制 Swing Icon

private static class AttachmentListCell extends ListCell<String> {
    @Override
    public void updateItem(String fileName, boolean empty) {
        if (item != null) {

            // Get file Icon for fileName as shown above.
            java.swing.Icon icon = 

            // Transform Icon to something that can be 
            // added to the box, maybe an ImageView.
            javafx.scene.image.ImageView image = ???

            // Label for file name
            Label label = new Label(item);

            HBox box = new HBox();
            box.getChildren().addAll(image, label);
            setGraphic(box);
        }
    }
}

我想出了这段代码,它似乎可以将 getSystemIcon 返回的图标转换为 JavaFX 可以理解的格式。它通过使用 SwingUtilities.invokeLaterPlatform.runLater 的组合来尝试减轻两个项目之间任何潜在的线程问题。 javax.swing.Icon 被绘制为 java.awt.BufferedImage,后者由 SwingFXUtils 转换为 JavaFX 图像。

因此,您询问的代码的 Swing Icon => JavaFX 图像部分似乎有效。唯一的问题是,当我在 OS X 10.7 运行 Oracle Java8u20 上测试应用程序时,我尝试的每个文件扩展名类型都给出了完全相同的图标。因此,OS X 似乎并不真正支持您通过 swing FileSystemView 从系统获取图标的方法(据我所知)。我想你可以在另一个 OS 上试试看它是否适合你(假设在 OS X 上支持这个图标查找功能对你的任务来说不是必需的)。

所以谷歌搜索提出了以下问题:

  • Access file type icons Mac OSX

在这一点上,Sam Barnum 推荐 FileViewFileSystemView 效果好得多 - 对我来说也是如此。我将您的代码切换为使用 FileView,然后开始在 OS X 上为不同的文件类型获取不同的图标。图标仍然非常小,只有 16x16 个图标(我不知道如何检索 hi -res 视网膜图标),但至少检索到的图标显示正确且文件类型特定。

import javafx.application.Application;
import javafx.application.Platform;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

public class FileIconViewer extends Application {

    @Override
    public void start(Stage stage) throws IOException {
        Runnable fetchIcon = () -> {
            File file = null;
            try {
                file = File.createTempFile("icon", ".png");

                // commented code always returns the same icon on OS X...
                // FileSystemView view = FileSystemView.getFileSystemView();
                // javax.swing.Icon icon = view.getSystemIcon(file);

                // following code returns different icons for different types on OS X...
                final javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
                javax.swing.Icon icon = fc.getUI().getFileView(fc).getIcon(file);

                BufferedImage bufferedImage = new BufferedImage(
                    icon.getIconWidth(), 
                    icon.getIconHeight(), 
                    BufferedImage.TYPE_INT_ARGB
                );
                icon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);

                Platform.runLater(() -> {
                    Image fxImage = SwingFXUtils.toFXImage(
                        bufferedImage, null
                    );
                    ImageView imageView = new ImageView(fxImage);
                    stage.setScene(
                        new Scene(
                            new StackPane(imageView), 
                            200, 200
                        )
                    );
                    stage.show();
                });
            } catch (IOException e) {
                e.printStackTrace();
                Platform.exit();
            } finally {
                if (file != null) {
                    file.delete();
                }
            }
        };

        javax.swing.SwingUtilities.invokeLater(fetchIcon);
    }

    public static void main(String[] args) { launch(args); }
}

注意:JavaFX 问题跟踪器中存在将此功能添加到 JavaFX 的现有请求(目前未计划实施,但您可以登录问题跟踪器并为该问题投票,对其发表评论, link 回到这个 Whosebug 问题等):

以下是带有文件图标的列表视图示例:

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

import javax.swing.filechooser.FileSystemView;

public class ListViewCellFactory2 extends Application {

    ListView<String> list = new ListView<String>();
    ObservableList<String> data = FXCollections.observableArrayList(
            "a.msg", "a1.msg", "b.txt", "c.pdf", 
            "d.html", "e.png", "f.zip",
            "g.docx", "h.xlsx", "i.pptx");

    @Override
    public void start(Stage stage) {
        VBox box = new VBox();
        Scene scene = new Scene(box, 200, 200);
        stage.setScene(scene);
        stage.setTitle("ListViewSample");
        box.getChildren().addAll(list);
        VBox.setVgrow(list, Priority.ALWAYS);

        list.setItems(data);

        list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override
            public ListCell<String> call(ListView<String> list) {
                return new AttachmentListCell();
            }
        });

        stage.show();
    }

    private static class AttachmentListCell extends ListCell<String> {
        @Override
        public void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty) {
                setGraphic(null);
                setText(null);
            } else {
                Image fxImage = getFileIcon(item);
                ImageView imageView = new ImageView(fxImage);
                setGraphic(imageView);
                setText(item);
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }


    static HashMap<String, Image> mapOfFileExtToSmallIcon = new HashMap<String, Image>();

    private static String getFileExt(String fname) {
        String ext = ".";
        int p = fname.lastIndexOf('.');
        if (p >= 0) {
            ext = fname.substring(p);
        }
        return ext.toLowerCase();
    }

    private static javax.swing.Icon getJSwingIconFromFileSystem(File file) {

        // Windows {
        FileSystemView view = FileSystemView.getFileSystemView();
        javax.swing.Icon icon = view.getSystemIcon(file);
        // }

        // OS X {
        //final javax.swing.JFileChooser fc = new javax.swing.JFileChooser();
        //javax.swing.Icon icon = fc.getUI().getFileView(fc).getIcon(file);
        // }

        return icon;
    }

    private static Image getFileIcon(String fname) {
        final String ext = getFileExt(fname);

        Image fileIcon = mapOfFileExtToSmallIcon.get(ext);
        if (fileIcon == null) {

            javax.swing.Icon jswingIcon = null; 

            File file = new File(fname);
            if (file.exists()) {
                jswingIcon = getJSwingIconFromFileSystem(file);
            }
            else {
                File tempFile = null;
                try {
                    tempFile = File.createTempFile("icon", ext);
                    jswingIcon = getJSwingIconFromFileSystem(tempFile);
                }
                catch (IOException ignored) {
                    // Cannot create temporary file. 
                }
                finally {
                    if (tempFile != null) tempFile.delete();
                }
            }

            if (jswingIcon != null) {
                fileIcon = jswingIconToImage(jswingIcon);
                mapOfFileExtToSmallIcon.put(ext, fileIcon);
            }
        }

        return fileIcon;
    }

    private static Image jswingIconToImage(javax.swing.Icon jswingIcon) {
        BufferedImage bufferedImage = new BufferedImage(jswingIcon.getIconWidth(), jswingIcon.getIconHeight(),
                BufferedImage.TYPE_INT_ARGB);
        jswingIcon.paintIcon(null, bufferedImage.getGraphics(), 0, 0);
        return SwingFXUtils.toFXImage(bufferedImage, null);
    }

}

编辑:在 HDPI 监视器上,文件图标被剪裁。

  1. 要使图标完全显示在行中,需要做什么?
  2. 如何从 Java 中检索比例因子?