2009-02-27 7 views
9

J'écris un éditeur de diagramme en java. Cette application a la possibilité d'exporter vers divers formats d'image standard tels que .jpg, .png etc. Lorsque l'utilisateur clique sur Fichier-> Exporter, vous obtenez un JFileChooser qui a un nombre de FileFilter s dedans, pour .jpg, .png etc.Ajuster le fichier sélectionné à FileFilter dans un JFileChooser

maintenant, voici ma question:

est-il possible d'avoir l'extension de la valeur par défaut d'ajuster au filtre de fichier sélectionné? Par exemple. Si le document est nommé "lolcat" alors l'option par défaut devrait être "lolcat.png" quand le filtre png est sélectionné, et quand l'utilisateur sélectionne le filtre de fichier jpg, la valeur par défaut devrait changer automatiquement "lolcat.jpg".

Est-ce possible? Comment puis-je le faire?

edit: Basé sur la réponse ci-dessous, j'ai écrit du code. Mais ça ne marche pas encore tout à fait. J'ai ajouté un propertyChangeListener au FILE_FILTER_CHANGED_PROPERTY, mais il semble que dans cette méthode getSelectedFile() renvoie null. Voici le code.

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

Répondre

11

Il semble que vous pouvez écouter la JFileChooser pour un changement sur la propriété FILE_FILTER_CHANGED_PROPERTY, puis modifiez l'extension du fichier sélectionné à l'aide appropriée setSelectedFile().


EDIT: Vous avez raison, cette solution ne fonctionne pas. Il s'avère que lorsque le filtre de fichier est modifié, le fichier sélectionné est supprimé si son type de fichier ne correspond pas au nouveau filtre. C'est pourquoi vous obtenez le null lorsque vous essayez de getSelectedFile().

Avez-vous envisagé d'ajouter l'extension plus tard? Quand je suis en train d'écrire un JFileChooser, je l'habitude d'ajouter l'extension après que l'utilisateur a choisi un fichier à utiliser et cliqué sur « Enregistrer »:

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

L'utilisation de getAbsolutePath() dans le précédent changement le répertoire actuel. J'ai été surpris lorsque la boîte de dialogue JFileChooser affichant le répertoire "Mes documents" est passée dans le répertoire du projet Netbeans lorsque j'ai sélectionné un FileFilter différent, donc je l'ai modifié pour utiliser getName(). J'ai également utilisé le JDK 6 FileNameExtensionFilter.

Voici le code:

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

Voici ma tentative de cela. Il utilise la fonction accept() pour vérifier si le fichier passe le filtre. Si le nom de fichier ne le fait pas, l'extension est ajoutée à la fin.

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

Vous pouvez également utiliser un PropertyChangeListener sur la SELECTED_FILE_CHANGED_PROPERTY avant de fixer votre suffixe. Lorsque le fichier sélectionné est vérifié par rapport au nouveau filtre (et par la suite défini sur null), l'événement SELECTED_FILE_CHANGED_PROPERTY est réellement déclenché avant l'événement FILE_FILTER_CHANGED_PROPERTY. Si le evt.getOldValue()! = Null et le evt.getNewValue() == null, vous savez que le JFileChooser a dynamité votre fichier.Vous pouvez ensuite récupérer le nom de l'ancien fichier (en utilisant ((Fichier) evt.getOldValue()). GetName() comme décrit ci-dessus), retirer l'extension en utilisant les fonctions d'analyse de chaîne standard et la stocker dans une variable membre nommée de votre classe . De cette façon, lorsque l'événement FILE_FILTER_CHANGED est déclenché (immédiatement après, aussi proche que je peux déterminer), vous pouvez extraire ce nom racine caché de la variable membre nommée, appliquer l'extension pour le nouveau type de filtre de fichier et définir le fichier sélectionné de JFileChooser en conséquence.

3

Que diriez-vous ceci:

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

Voici ma solution et cela fonctionne très bien. Cela aide peut-être quelqu'un. Vous devriez créer votre propre classe "MyExtensionFileFilter", sinon vous devez modifier le code.

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

Voici une méthode pour obtenir le nom de fichier actuel (sous forme de chaîne). Dans l'écouteur de changement de propriété pour JFileChooser.FILE_FILTER_CHANGED_PROPERTY, vous faites l'appel suivant:

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

La méthode getFileName() de javax.swing.plaf.basic.BasicFileChooserUI (le descendant de FileChooserUI retourné par JFileChooser.getUI()) retourne le contenu de la zone de texte de la boîte de dialogue qui est utilisé pour taper le nom du fichier. Il semble que cette valeur soit toujours définie sur une chaîne non nulle (elle renvoie une chaîne vide si la case est vide). D'autre part, getSelectedFile() renvoie null si l'utilisateur n'a pas encore sélectionné un fichier existant.

Il semble que la conception du dialogue soit régie par le concept de «sélection de fichier»; En d'autres termes, lorsque la boîte de dialogue est visible, getSelectedFile() renvoie uniquement une valeur significative si l'utilisateur a déjà sélectionné un fichier existant ou le programme appelé setSelectedFile(). getSelectedFile() retournera ce que l'utilisateur a tapé après l'utilisateur clique sur le bouton approuver (c'est-à-dire OK).

La technique ne fonctionnera que pour les boîtes de dialogue à sélection unique, cependant changer l'extension du fichier en fonction du filtre sélectionné devrait également avoir un sens pour les fichiers uniques seulement (boîtes de dialogue "Enregistrer sous ...").

Ce motif a fait l'objet d'un débat chez sun.com en 2003, consultez le link pour plus de détails.

Questions connexes