настройка выбранного файла для FileFilter в JFileChooser

Я пишу редактор диаграмм на java. Это приложение имеет возможность экспортировать в различные стандартные форматы изображений, такие как .формат JPG. ,png и др. Когда пользователь нажимает File - >Export, вы получаете JFileChooser, который имеет ряд FileFilters в нем, для .jpg, .png etc.

теперь вот мой вопрос:

есть ли способ настроить расширение по умолчанию для выбранного фильтра файлов? Е. Г. если документ назван "lolcat", то опция по умолчанию должна быть "lolcat.формат PNG" когда фильтр png выбран, и когда пользователь выбирает фильтр файлов jpg, значение по умолчанию должно измениться на " 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<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();
            }
        });     
    }
}

7 ответов


похоже, вы можете слушать JFileChooser изменить на FILE_FILTER_CHANGED_PROPERTY свойство, затем измените расширение выбранного файла соответствующим образом, используя setSelectedFile().


EDIT: вы правы, это решение не работает. Оказывается, при изменении фильтра файлов выбранный файл удаляется, если его тип не соответствует новому фильтру. Вот почему вы получаете null при попытке getSelectedFile().

вы рассматривали возможность добавления расширения позже? Когда я пишу 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));
  }
});

вы также можете использовать PropertyChangeListener на SELECTED_FILE_CHANGED_PROPERTY до присоединения суффикса. Когда выбранный файл проверяется на новый фильтр (а затем устанавливается в значение null), событие SELECTED_FILE_CHANGED_PROPERTY фактически запускается до событие FILE_FILTER_CHANGED_PROPERTY.

Если evt.getOldValue ()!= null и evt.getNewValue () = = null, вы знаете, что JFileChooser взорвал ваш файл. Затем вы можете захватить имя старого файла (используя ((File)evt.getOldValue ()).getName () как описано выше), извлеките расширение с помощью стандартных функций синтаксического анализа строк и спрячьте его в именованную переменную-член в своем классе.

таким образом, когда событие FILE_FILTER_CHANGED запускается (сразу после этого, насколько я могу определить), Вы можете вытащить это скрытое корневое имя из именованной переменной-члена, применить расширение для нового типа фильтра файлов и установить выбранный файл 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 );
     }
    }
   }
  }

вот метод для получения текущего имени файла (в виде строки). В вашем прослушивателе изменения свойства для 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));
    }
});

на getFileName() метод javax.swing.plaf.basic.BasicFileChooserUI (потомок FileChooserUI возвращено JFileChooser.getUI()) возвращает содержимое текстового поля диалогового окна, которое используется для ввода имени файла. Кажется, что это значение всегда устанавливается в ненулевую строку (она возвращает пустую строку, если поле пустое). С другой стороны,--6--> возвращает null, если пользователь еще не выбрал существующий файл.

кажется, что дизайн диалога управляется концепцией "выбор файла"; то есть, в то время как диалог виден getSelectedFile() возвращает только значения, если пользователь уже выбрал существующий файл или программу, под названием setSelectedFile(). getSelectedFile() вернет то, что пользователь набрал в после пользователь нажимает кнопку утвердить (т. е. OK).

метод будет работать только для одно-выбора диалоги, однако изменение расширения файла на основе выбранного фильтра также должно иметь смысл только для отдельных файлов ("Сохранить как..."диалоги или аналогичные).

этот дизайн был предметом обсуждения на sun.com еще в 2003 году см. ссылке для сведения.


использование getAbsolutePath () в предыдущем изменении текущего каталога. Я был удивлен, когда диалоговое окно 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 (), чтобы проверить, проходит ли файл фильтр. Если имя файла не указано, расширение добавляется в конец.

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