2009-02-27 2 views
9

Я пишу редактор диаграмм в java. Это приложение имеет возможность экспортировать в различные стандартные форматы изображений, такие как .jpg, .png и т. Д. Когда пользователь нажимает «Файл-> Экспорт», вы получаете JFileChooser, в котором есть FileFilter с, для .jpg, .png и т. Д.настроить выбранный файл в FileFilter в JFileChooser

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

есть ли способ, чтобы иметь расширение по умолчанию приспособиться к выбранному фильтру файлов? Например. если документ назван «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(); 
      } 
     });  
    } 
} 

ответ

11

Похоже, что вы можете слушать 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)); 
    } 
}); 
0

Использование getAbsolutePath() в предыдущем изменении текущий каталог. Я был удивлен, когда диалог JFileChooser, отображающий каталог «Мои документы», изменился в каталог проектов Netbeans, когда я выбрал другой FileFilter, поэтому я изменил его на использование 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)); 
      } 
     } 
    }); 
0

Вот моя попытка в этом. Он использует функцию 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(); 
     } 
    }; 
4

Вы также можете использовать 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.

3

Как об этом:

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

Ниже приведен метод получения текущего имени файла (в виде строки). В прослушивателе изменения свойств для 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()) вернет содержимое текстового поля диалогового окна, которая используется для ввода имя файла. Кажется, что это значение всегда задано для непустого String (он возвращает пустую строку, если поле пусто). С другой стороны, getSelectedFile() возвращает null, если пользователь еще не выбрал существующий файл.

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

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

Этот проект был предметом спора на sun.com еще в 2003 году, см. link для деталей.

Смежные вопросы