在JFileChooser中将所选文件调整为FileFilter

我正在用java编写一个图编辑器。 此应用程序可以选择导出到各种标准图像格式,如.jpg,.png等。当用户单击文件 – >导出时,您将获得一个JFileChooser ,其中包含许多FileFilter.jpg.png等等

现在这是我的问题:

有没有办法将默认值的扩展调整到所选的文件filter? 例如,如果文档名为“lolcat”,则在选择pngfilter时,默认选项应为“lolcat.png”,当用户选择jpg文件filter时,默认值应自动更改为“lolcat.jpg”。

这可能吗? 我该怎么做?

编辑:基于下面的答案,我写了一些代码。 但它还没有完全奏效。 我已经将一个propertyChangeListener添加到FILE_FILTER_CHANGED_PROPERTY ,但似乎在此方法中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 extensions; private boolean showDirectories; /** * @param name example: "Data files" * @param glob example: "*.txt|*.csv" */ public SimpleFileFilter (String name, String globs) { extensions = new ArrayList(); 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(); } }); } } 

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


编辑:你是对的,这个解决方案不起作用。 事实certificate,当文件filter更改时,如果所选文件的文件类型与新filter不匹配,则会删除所选文件。 这就是为什么当你尝试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)); } }); 

您还可以在附加后缀之前在SELECTED_FILE_CHANGED_PROPERTY上使用PropertyChangeListener。 当针对新filter检查所选文件(并随后设置为null)时,实际上 FILE_FILTER_CHANGED_PROPERTY事件之前触发了SELECTED_FILE_CHANGED_PROPERTY事件。

如果evt.getOldValue()!= null并且evt.getNewValue()== null,则表示JFileChooser已经对文件进行了抨击。 然后,您可以获取旧文件的名称(使用((File)evt.getOldValue())。getName(),如上所述),使用标准字符串解析函数拉出扩展,并将其存储到类中的命名成员变量中。

这样,当触发FILE_FILTER_CHANGED事件时(紧接着就在我可以确定的附近),您可以从命名成员变量中提取该隐藏的根名称,为新文件filter类型应用扩展名,并设置JFileChooser的所选文件因此。

这是我的解决方案,它工作正常。 它可能会帮助某人。 您可以创建自己的“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(); } } } 

这个怎么样:

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

这是获取当前文件名(作为String)的方法。 在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.BasicFileChooserUI (由JFileChooser.getUI()返回的FileChooserUI的后代getFileName()getFileName()方法将返回用于键入文件名的对话框文本框的内容。 似乎该值始终设置为非null String(如果该框为空,则返回空字符串)。 另一方面,如果用户尚未选择现有文件,则getSelectedFile()将返回null。

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

该技术仅适用于单选对话框,但是根据所选filter更改文件扩展名也应仅对单个文件有意义(“另存为…”对话框或类似对话框)。

这个设计是2003年在sun.com上进行辩论的主题,请参阅链接了解详情。

在之前使用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)); } } }); 

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

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