【问题标题】:How to list recently used files in JFileChooser Swing component如何在 JFileChooser Swing 组件中列出最近使用的文件
【发布时间】:2014-07-31 05:18:20
【问题描述】:

我在我的 Java 项目中使用 javax.swing.JFileChooser swing 组件通过对话框打开文件。如何列出最近使用的文件以在 JFileChooser 中进行选择。每次我进入目录并选择耗时的文件。

如何在组件本身中列出最近使用的几个文件,这样我们就不需要一次又一次地浏览目录来选择文件?

【问题讨论】:

    标签: java swing list jfilechooser


    【解决方案1】:

    JFileChooser 允许您提供一个accessory Component,它被添加到Windows 右侧的JFileChooser 组件中。

    你能做的是……

    • 创建JListListModel,将JList设置为JFileChoosersaccessory(包裹在JScrollPane中)
    • 每次选择文件时,将其添加到Set
    • 每次打开 JFileChooser 时,使用 Set 中的值更新 JList 的模型(或使用 Set 返回模型)。
    • 每次用户从列表中选择一个值时,您都需要更改 JFileChoosers selectedFile 属性以反映更改...

    更多详情,请查看Providing an Accessory Component了解更多详情...

    更新

    import java.awt.BorderLayout;
    import java.awt.Component;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.GridBagLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.io.File;
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.AbstractListModel;
    import javax.swing.DefaultListCellRenderer;
    import javax.swing.Icon;
    import javax.swing.JButton;
    import javax.swing.JFileChooser;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JScrollPane;
    import javax.swing.ListSelectionModel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    import javax.swing.event.ListSelectionEvent;
    import javax.swing.event.ListSelectionListener;
    import javax.swing.filechooser.FileSystemView;
    
    public class TestFileChooser {
    
        public static void main(String[] args) {
            new TestFileChooser();
        }
    
        public TestFileChooser() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    JFrame frame = new JFrame("Testing");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setLayout(new BorderLayout());
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
    
            private JFileChooser fc;
            private RectentFileList rectentFileList;
    
            public TestPane() {
                setLayout(new GridBagLayout());
                JButton chooser = new JButton("Choose");
                chooser.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        if (fc == null) {
                            fc = new JFileChooser();
                            rectentFileList = new RectentFileList(fc);
                            fc.setAccessory(rectentFileList);
                            fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
                        }
                        switch (fc.showOpenDialog(TestPane.this)) {
                            case JOptionPane.OK_OPTION:
                                File file = fc.getSelectedFile();
                                rectentFileList.add(file);
                                break;
                        }
                    }
                });
                add(chooser);
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
        }
    
        public class RectentFileList extends JPanel {
    
            private final JList<File> list;
            private final FileListModel listModel;
            private final JFileChooser fileChooser;
    
            public RectentFileList(JFileChooser chooser) {
                fileChooser = chooser;
                listModel = new FileListModel();
                list = new JList<>(listModel);
                list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
                list.setCellRenderer(new FileListCellRenderer());
    
                setLayout(new BorderLayout());
                add(new JScrollPane(list));
    
                list.addListSelectionListener(new ListSelectionListener() {
                    @Override
                    public void valueChanged(ListSelectionEvent e) {
                        if (!e.getValueIsAdjusting()) {
                            File file = list.getSelectedValue();
                            // You might like to check to see if the file still exists...
                            fileChooser.setSelectedFile(file);
                        }
                    }
                });
            }
    
            public void clearList() {
                listModel.clear();
            }
    
            public void add(File file) {
                listModel.add(file);
            }
    
            public class FileListModel extends AbstractListModel<File> {
    
                private List<File> files;
    
                public FileListModel() {
                    files = new ArrayList<>();
                }
    
                public void add(File file) {
                    if (!files.contains(file)) {
                        if (files.isEmpty()) {
                            files.add(file);
                        } else {
                            files.add(0, file);
                        }
                        fireIntervalAdded(this, 0, 0);
                    }
                }
    
                public void clear() {
                    int size = files.size() - 1;
                    if (size >= 0) {
                        files.clear();
                        fireIntervalRemoved(this, 0, size);
                    }
                }
    
                @Override
                public int getSize() {
                    return files.size();
                }
    
                @Override
                public File getElementAt(int index) {
                    return files.get(index);
                }
            }
    
            public class FileListCellRenderer extends DefaultListCellRenderer {
    
                @Override
                public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
                    super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
                    if (value instanceof File) {
                        File file = (File) value;
                        Icon ico = FileSystemView.getFileSystemView().getSystemIcon(file);
                        setIcon(ico);
                        setToolTipText(file.getParent());
                        setText(file.getName());
                    }
                    return this;
                }
    
            }
    
        }
    
    }
    

    持久性问题是一个广泛的问题,取决于您的个人需求,例如,您可以将文件列表转储到平面文件中,这可能是最简单的解决方案,因为这意味着您可以简单地阅读文件从头到尾,并且知道您拥有全部内容。此外,再次写出文件将覆盖任何先前的值,使其易于管理。

    其他解决方案可能需要提供“计数”属性,然后您可以将其添加到已知键的后缀以列出值,这需要在更新详细信息时手动删除旧值。您也可以尝试使用定界符将所有值作为单个值保存在持久性存储中,但这会导致选择不会在文件名中使用的定界符的问题(路径分隔符可能会:D)

    查看How can I save the state of my program and then load it? 了解更多想法...

    更新

    经过一番思考,您可以使用Preferences API 通过使用File.pathSeparator 使用单个键来存储文件列表,因为这应该是唯一的,而不是由文件名/路径使用。

    例如,您可以使用类似...的方式保存列表

    StringBuilder sb = new StringBuilder(128);
    for (int index = 0; index < listModel.getSize(); index++) {
        File file = listModel.getElementAt(index);
        if (sb.length() > 0) {
            sb.append(File.pathSeparator);
        }
        sb.append(file.getPath());
    }
    System.out.println(sb.toString());
    Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
    p.put("RectentFileList.fileList", sb.toString());
    

    然后使用类似...的东西再次加载它

    Preferences p = Preferences.userNodeForPackage(TestFileChooser.class);
    String listOfFiles = p.get("RectentFileList.fileList", null);
    if (listOfFiles != null) {
        String[] files = listOfFiles.split(File.pathSeparator);
        for (String fileRef : files) {
            File file = new File(fileRef);
            if (file.exists()) {
                add(file);
            }
        }
    }
    

    【讨论】:

      【解决方案2】:
      Use setSelectedFile(File file) method of JFileChooser.
      

      文档说:

      public void setSelectedFile(File file)
      

      设置选定的文件。如果文件的父目录不是 当前目录,将当前目录更改为文件的 父目录。

      This links may be helpful

      example by peeskillet

      【讨论】:

      • setSelectedFile 要求硬编码文件路径。假设我第一次运行程序并退出时选择了一个文件。当我再次运行程序时,我希望 JFileChooser 列出我在上次运行时选择的文件。
      • 那么您应该参考链接,因为没有直接的方法可以实现,您必须查看 2-3 示例如何实现您想要的。@TheGame
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-08
      • 1970-01-01
      • 1970-01-01
      • 2015-10-31
      • 2014-06-06
      • 2011-06-04
      • 2011-02-01
      相关资源
      最近更新 更多