【问题标题】:adjust selected File to FileFilter in a JFileChooser在 JFileChooser 中将选定的文件调整为 FileFilter
【发布时间】:2009-02-27 20:09:05
【问题描述】:

我正在用 java 编写图表编辑器。此应用程序可以选择导出为各种标准图像格式,例如 .jpg、.png 等。当用户单击“文件”->“导出”时,您会得到一个 JFileChooser,其中包含多个 FileFilters,用于 @ 987654323@、.png

现在这是我的问题:

有没有办法让默认的扩展名调整为选定的文件过滤器?例如。如果文档名为“lolcat”,则在选择 png 过滤器时默认选项应为“lolcat.png”,当用户选择 jpg 文件过滤器时,默认应自动更改为“lolcat.jpg”。

这可能吗?我该怎么做?

编辑: 根据下面的答案,我写了一些代码。但它还没有完全奏效。我在FILE_FILTER_CHANGED_PROPERTY 中添加了propertyChangeListener,但似乎在此方法中getSelectedFile() 返回null。这是代码。

package nl.helixsoft;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.filechooser.FileFilter;

public class JFileChooserTest {
    public class SimpleFileFilter extends FileFilter {
        private String desc;
        private List<String> extensions;
        private boolean showDirectories;

        /**
         * @param name example: "Data files"
         * @param glob example: "*.txt|*.csv"
         */
        public SimpleFileFilter (String name, String globs) {
            extensions = new ArrayList<String>();
            for (String glob : globs.split("\\|")) {
                if (!glob.startsWith("*.")) 
                    throw new IllegalArgumentException("expected list of globs like \"*.txt|*.csv\"");
                // cut off "*"
                // store only lower case (make comparison case insensitive)
                extensions.add (glob.substring(1).toLowerCase());
            }
            desc = name + " (" + globs + ")";
        }

        public SimpleFileFilter(String name, String globs, boolean showDirectories) {
            this(name, globs);
            this.showDirectories = showDirectories;
        }

        @Override
        public boolean accept(File file) {
            if(showDirectories && file.isDirectory()) {
                return true;
            }
            String fileName = file.toString().toLowerCase();

            for (String extension : extensions) {   
                if (fileName.endsWith (extension)) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public String getDescription() {
            return desc;
        }

        /**
         * @return includes '.'
         */
        public String getFirstExtension() {
            return extensions.get(0);
        }
    }

    void export() {
        String documentTitle = "lolcat";

        final JFileChooser jfc = new JFileChooser();
        jfc.setDialogTitle("Export");
        jfc.setDialogType(JFileChooser.SAVE_DIALOG);
        jfc.setSelectedFile(new File (documentTitle));
        jfc.addChoosableFileFilter(new SimpleFileFilter("JPEG", "*.jpg"));
        jfc.addChoosableFileFilter(new SimpleFileFilter("PNG", "*.png"));
        jfc.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent arg0) {
                System.out.println ("Property changed");
                String extold = null;
                String extnew = null;
                if (arg0.getOldValue() == null || !(arg0.getOldValue() instanceof SimpleFileFilter)) return;
                if (arg0.getNewValue() == null || !(arg0.getNewValue() instanceof SimpleFileFilter)) return;
                SimpleFileFilter oldValue = ((SimpleFileFilter)arg0.getOldValue());
                SimpleFileFilter newValue = ((SimpleFileFilter)arg0.getNewValue());
                extold = oldValue.getFirstExtension();
                extnew = newValue.getFirstExtension();
                String filename = "" + jfc.getSelectedFile();
                System.out.println ("file: " + filename + " old: " + extold + ", new: " + extnew);
                if (filename.endsWith(extold)) {
                    filename.replace(extold, extnew);
                } else {
                    filename += extnew;
                }
                jfc.setSelectedFile(new File (filename));
            }
        });
        jfc.showDialog(frame, "export");
    }

    JFrame frame;

    void run() {
        frame = new JFrame();
        JButton btn = new JButton ("export");
        frame.add (btn);
        btn.addActionListener (new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                export();
            }
        });
        frame.setSize (300, 300);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {     
            public void run() {
                JFileChooserTest x =  new JFileChooserTest();
                x.run();
            }
        });     
    }
}

【问题讨论】:

    标签: java swing jfilechooser


    【解决方案1】:

    您似乎可以收听JFileChooser 以更改FILE_FILTER_CHANGED_PROPERTY 属性,然后使用setSelectedFile() 适当地更改所选文件的扩展名。


    编辑:你说得对,这个解决方案不起作用。事实证明,当文件过滤器更改时,如果所选文件的文件类型与新过滤器不匹配,则会将其删除。这就是为什么当您尝试getSelectedFile() 时会收到null

    您是否考虑过稍后添加扩展程序?当我写JFileChooser时,我通常会在用户选择要使用的文件并单击“保存”后添加扩展名:

    if (result == JFileChooser.APPROVE_OPTION)
    {
      File file = fileChooser.getSelectedFile();
      String path = file.getAbsolutePath();
    
      String extension = getExtensionForFilter(fileChooser.getFileFilter());
    
      if(!path.endsWith(extension))
      {
        file = new File(path + extension);
      }
    }
    

    fileChooser.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener()
    {
      public void propertyChange(PropertyChangeEvent evt)
      {
        FileFilter filter = (FileFilter)evt.getNewValue();
    
        String extension = getExtensionForFilter(filter); //write this method or some equivalent
    
        File selectedFile = fileChooser.getSelectedFile();
        String path = selectedFile.getAbsolutePath();
        path.substring(0, path.lastIndexOf("."));
    
        fileChooser.setSelectedFile(new File(path + extension));
      }
    });
    

    【讨论】:

      【解决方案2】:

      这个怎么样:

      class MyFileChooser extends JFileChooser {
         public void setFileFilter(FileFilter filter) {
      
          super.setFileFilter(filter);
      
          FileChooserUI ui = getUI();
      
          if( ui instanceof BasicFileChooserUI ) {
           BasicFileChooserUI bui = (BasicFileChooserUI) ui;
      
           String file = bui.getFileName();
      
           if( file != null ) {
            String newFileName = ... change extension 
            bui.setFileName( newFileName );
           }
          }
         }
        }
      

      【讨论】:

        【解决方案3】:

        您还可以在附加后缀之前在 SELECTED_FILE_CHANGED_PROPERTY 上使用 PropertyChangeListener。 When the selected file gets checked against the new filter (and subsequently set to null), the SELECTED_FILE_CHANGED_PROPERTY event is actually fired before the FILE_FILTER_CHANGED_PROPERTY event.

        如果 evt.getOldValue() != null 和 evt.getNewValue() == null,你知道 JFileChooser 已经炸毁了你的文件。然后,您可以获取旧文件的名称(使用 ((File)evt.getOldValue()).getName() 如上所述),使用标准字符串解析函数提取扩展,并将其存储到类中的命名成员变量中.

        这样,当触发 FILE_FILTER_CHANGED 事件时(紧随其后,尽可能接近我可以确定),您可以从命名成员变量中提取隐藏的根名称,应用新文件过滤器类型的扩展名,并设置JFileChooser 相应选择的文件。

        【讨论】:

          【解决方案4】:

          这是我的解决方案,效果很好。它可能会帮助某人。您应该创建自己的“MyExtensionFileFilter”类,否则您必须修改代码。

          public class MyFileChooser extends JFileChooser {
              private File file = new File("");
          
              public MyFileChooser() {
                  addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() {
                      public void propertyChange(PropertyChangeEvent e) {
                          String filename = MyFileChooser.this.file.getName();
                          String extold = null;
                          String extnew = null;
                          if (e.getOldValue() == null || !(e.getOldValue() instanceof MyExtensionFileFilter)) {
                              return;
                          }
                          if (e.getNewValue() == null || !(e.getNewValue() instanceof MyExtensionFileFilter)) {
                              return;
                          }
                          MyExtensionFileFilter oldValue = ((MyExtensionFileFilter) e.getOldValue());
                          MyExtensionFileFilter newValue = ((MyExtensionFileFilter) e.getNewValue());
                          extold = oldValue.getExtension();
                          extnew = newValue.getExtension();
          
                          if (filename.endsWith(extold)) {
                              filename = filename.replace(extold, extnew);
                          } else {
                              filename += ("." + extnew);
                          }
                          setSelectedFile(new File(filename));
                      }
                  });
              }
          
              @Override
              public void setSelectedFile(File file) {
                  super.setSelectedFile(file);
                  if(getDialogType() == SAVE_DIALOG) {
                      if(file != null) {
                          super.setSelectedFile(file);
                          this.file = file;
                      }
                  }
              }
          
              @Override
              public void approveSelection() { 
                  if(getDialogType() == SAVE_DIALOG) {
                      File f = getSelectedFile();  
                      if (f.exists()) {  
                          String msg = "File existes ...";  
                          msg = MessageFormat.format(msg, new Object[] { f.getName() });  
                          int option = JOptionPane.showConfirmDialog(this, msg, "", JOptionPane.YES_NO_OPTION);
                          if (option == JOptionPane.NO_OPTION ) {  
                              return;  
                          }
                      }
                  }
                  super.approveSelection();   
              }
          
              @Override
              public void setVisible(boolean visible) {
                  super.setVisible(visible);
                  if(!visible) {
                      resetChoosableFileFilters();
                  }
              }
          }
          

          【讨论】:

            【解决方案5】:

            这是一种获取当前文件名(作为字符串)的方法。在 JFileChooser.FILE_FILTER_CHANGED_PROPERTY 的属性更改侦听器中,您进行以下调用:

            final JFileChooser fileChooser = new JFileChooser();
            fileChooser.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener()
            {
                @Override
                public void propertyChange(PropertyChangeEvent e) {
                    String currentName = ((BasicFileChooserUI)fileChooser.getUI()).getFileName();
                    MyFileFilter filter = (MyFileFilter) e.getNewValue();
            
                    // ... Transform currentName as you see fit using the newly selected filter.
                    // Suppose the result is in newName ...
            
                    fileChooser.setSelectedFile(new File(newName));
                }
            });
            

            javax.swing.plaf.basic.BasicFileChooserUIgetFileName() 方法(FileChooserUI 的后代由JFileChooser.getUI() 返回)将返回用于键入文件名的对话框文本框的内容。似乎该值始终设置为非空字符串(如果框为空,则返回空字符串)。另一方面,如果用户尚未选择现有文件,getSelectedFile() 将返回 null。

            对话框的设计似乎受“文件选择”概念的支配;也就是说,当对话框可见时,getSelectedFile() 仅在用户已经选择了现有文件或名为setSelectedFile() 的程序时才返回有意义的值。 getSelectedFile() 将返回用户用户单击批准(即确定)按钮后输入的内容。

            该技术仅适用于单选对话框,但基于所选过滤器更改文件扩展名也应该仅适用于单个文件(“另存为...”对话框或类似对话框)。

            早在 2003 年,该设计就曾在 sun.com 上引起过争论,详情请参阅 link

            【讨论】:

              【解决方案6】:

              前面使用getAbsolutePath()改变当前目录。 当我选择不同的 FileFilter 时,当 JFileChooser 对话框显示“我的文档”目录更改为 Netbeans 的项目目录时,我感到很惊讶,因此我将其更改为使用 getName()。 我还使用了 JDK 6 FileNameExtensionFilter。

              代码如下:

                  final JFileChooser fc = new JFileChooser();
                  final File sFile = new File("test.xls");
                  fc.setSelectedFile(sFile);
                  // Store this filter in a variable to be able to select this after adding all FileFilter
                  // because addChoosableFileFilter add FileFilter in order in the combo box
                  final FileNameExtensionFilter excelFilter = new FileNameExtensionFilter("Excel document (*.xls)", "xls");
                  fc.addChoosableFileFilter(excelFilter);
                  fc.addChoosableFileFilter(new FileNameExtensionFilter("CSV document (*.csv)", "csv"));
                  // Force the excel filter
                  fc.setFileFilter(excelFilter);
                  // Disable All Files
                  fc.setAcceptAllFileFilterUsed(false);
              
                  // debug
                  fc.addPropertyChangeListener(new PropertyChangeListener() {
              
                      public void propertyChange(PropertyChangeEvent evt) {
                          System.out.println("Property name=" + evt.getPropertyName() + ", oldValue=" + evt.getOldValue() + ", newValue=" + evt.getNewValue());
                          System.out.println("getSelectedFile()=" + fc.getSelectedFile());
                      }
                  });
              
                  fc.addPropertyChangeListener(JFileChooser.FILE_FILTER_CHANGED_PROPERTY, new PropertyChangeListener() {
              
                      public void propertyChange(PropertyChangeEvent evt) {
                          Object o = evt.getNewValue();
                          if (o instanceof FileNameExtensionFilter) {
                              FileNameExtensionFilter filter = (FileNameExtensionFilter) o;
              
                              String ex = filter.getExtensions()[0];
              
                              File selectedFile = fc.getSelectedFile();
                              if (selectedFile == null) {
                                  selectedFile = sFile;
                              }
                              String path = selectedFile.getName();
                              path = path.substring(0, path.lastIndexOf("."));
              
                              fc.setSelectedFile(new File(path + "." + ex));
                          }
                      }
                  });
              

              【讨论】:

                【解决方案7】:

                这是我的尝试。它使用accept() 函数来检查文件是否通过过滤器。如果文件名没有,则将扩展名附加到末尾。

                JFileChooser jfc = new JFileChooser(getFile()) {
                        public void approveSelection() {
                            if (getDialogType() == SAVE_DIALOG) {
                                File selectedFile = getSelectedFile();
                
                                FileFilter ff = getFileFilter();
                
                                // Checks against the current selected filter
                                if (!ff.accept(selectedFile)) {
                                    selectedFile = new File(selectedFile.getPath() + ".txt");
                                }
                                super.setSelectedFile(selectedFile);
                
                                if ((selectedFile != null) && selectedFile.exists()) {
                                    int response = JOptionPane.showConfirmDialog(
                                            this,
                                            "The file " + selectedFile.getName() + " already exists.\n" +
                                            "Do you want to replace it?",
                                            "Ovewrite file",
                                            JOptionPane.YES_NO_OPTION,
                                            JOptionPane.WARNING_MESSAGE
                                    );
                                    if (response == JOptionPane.NO_OPTION)
                                        return;
                                }
                            }
                            super.approveSelection();
                        }
                    };
                

                【讨论】:

                  【解决方案8】:

                  如果您的 Java 版本支持,我建议使用 FileNameExtensionFilter 而不是 FileFilter。否则,创建您自己的新的类似抽象类,该类从FileFilter 扩展并添加了方法getExtension(类似于FileNameExtensionFilter.getExtensions)。然后为您打算使用的每个导出过滤器覆盖 getExtension

                  public abstract class MyFileFilter extends FileFilter {
                      abstract public String getExtension();
                  }
                  

                  那么对于一个示例 JPG 过滤器,您只需要覆盖一个比以前额外的方法:

                      MyFileFilter filterJPG = new MyFileFilter () {
                          @Override
                          public String getDescription() {
                              return "A JPEG image (*." + getExtension() + ")";
                          }
                          @Override
                          public boolean accept(File f) {
                              String filename = f.getName().toLowerCase();
                              return filename.endsWith("."+getExtension());
                          }
                          @Override
                          public String getExtension() { return "jpg"; }
                      };
                  

                  用户选择文件后,只需调用getFileFilter 来确定用户选择的过滤器:

                  jfc.showDialog(frame, "export");
                  File file = jfc.getSelectedFile();
                  RvFileFilter filter = (RvFileFilter)jfc.getFileFilter();
                  String sExt = filter.getExtension(); //The extension to ensure the file has
                  

                  如果您能够使用FileNameExtensionFilter.getExtensions(),那么您可以简单地使用数组中的第一个条目。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-12-17
                    • 2020-04-30
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-05-26
                    • 1970-01-01
                    相关资源
                    最近更新 更多