2009-02-27 13 views
9

Estoy escribiendo un editor de diagramas en Java. Esta aplicación tiene la opción de exportar a varios formatos de imagen estándar, como .jpg, .png, etc. Cuando el usuario hace clic en Archivo-> Exportar, obtienes un JFileChooser que tiene un número de FileFilter en él, para , .png, etc.ajustar el archivo seleccionado a FileFilter en un JFileChooser

Ahora aquí es mi pregunta:

¿hay una manera de tener la extensión del defecto ajustar al filtro de archivo seleccionado? P.ej. si el documento se llama "lolcat", la opción predeterminada debe ser "lolcat.png" cuando se selecciona el filtro png, y cuando el usuario selecciona el filtro de archivos jpg, el valor predeterminado debe cambiar a "lolcat.jpg" automáticamente.

¿Esto es posible? ¿Cómo puedo hacerlo?

editar: Basado en la respuesta a continuación, escribí algunos códigos. Pero aún no funciona del todo. He agregado un propertyChangeListener al FILE_FILTER_CHANGED_PROPERTY, pero parece que dentro de este método getSelectedFile() devuelve nulo. Aquí está el código.

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

Respuesta

11

Parece que se puede escuchar a la JFileChooser para un cambio en la propiedad FILE_FILTER_CHANGED_PROPERTY, a continuación, cambiar la extensión del archivo seleccionado apropiadamente usando setSelectedFile().


EDITAR: Tiene razón, esta solución no funciona. Resulta que cuando se cambia el filtro de archivos, el archivo seleccionado se elimina si su tipo de archivo no coincide con el nuevo filtro. Es por eso que obtiene el null cuando intenta getSelectedFile().

¿Ha considerado agregar la extensión más tarde? Cuando estoy escribiendo un JFileChooser, Yo suelo añadir la extensión después de que el usuario ha elegido un archivo que desea utilizar y hacer clic en "Guardar":

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

El uso de getAbsolutePath() en el cambio anterior el directorio actual. Me sorprendió cuando el diálogo JFileChooser que muestra el directorio "Mis documentos" cambia al directorio de proyectos de Netbeans cuando seleccioné un FileFilter diferente, así que lo cambié para usar getName(). También utilicé el JDK 6 FileNameExtensionFilter.

Aquí está el código:

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

Aquí está mi intento de esto. Utiliza la función accept() para comprobar si el archivo pasa el filtro o no. Si el nombre del archivo no, la extensión se agrega al final.

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

También puede utilizar un PropertyChangeListener en el SELECTED_FILE_CHANGED_PROPERTY antes de fijar su sufijo. Cuando el archivo seleccionado se compara con el nuevo filtro (y posteriormente se establece en nulo), el evento SELECTED_FILE_CHANGED_PROPERTY se dispara antes del el evento FILE_FILTER_CHANGED_PROPERTY.

Si evt.getOldValue()! = Null y evt.getNewValue() == null, sabrá que JFileChooser ha destruido su archivo.A continuación, puede tomar el nombre del archivo anterior (usando ((Archivo) evt.getOldValue()). GetName() como se describió anteriormente, saque la extensión usando funciones de análisis de cadenas estándar, y la oculte en una variable de miembro nombrada dentro de su clase .

De esta forma, cuando se desencadena el evento FILE_FILTER_CHANGED (inmediatamente después, lo más cerca que puedo determinar), puede extraer ese nombre raíz oculto de la variable miembro nombrada, aplicar la extensión para el nuevo tipo de filtro de archivo y establecer el archivo seleccionado de JFileChooser en consecuencia.

3

¿Qué tal esto:

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

Aquí está mi solución y funciona bien. Quizás ayude a alguien. Debería crear su propia clase "MyExtensionFileFilter"; de lo contrario, deberá modificar el código.

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

Aquí hay un método para obtener el nombre del archivo actual (como una Cadena). En su cambio oyente propiedad de JFileChooser.FILE_FILTER_CHANGED_PROPERTY, se hace la siguiente llamada:

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

El método getFileName() de javax.swing.plaf.basic.BasicFileChooserUI (el descendiente de FileChooserUI devuelto por JFileChooser.getUI()) devolverá el contenido del cuadro de texto del cuadro de diálogo que se utiliza para escribir el nombre del archivo. Parece que este valor siempre se establece en una cadena no nula (devuelve una cadena vacía si la casilla está vacía). Por otro lado, getSelectedFile() devuelve nulo si el usuario aún no ha seleccionado un archivo existente.

Parece que el diseño del diálogo se rige por el concepto de 'selección de archivos'; es decir, mientras el cuadro de diálogo sea visible getSelectedFile() solo devuelve un valor significativo si el usuario ya ha seleccionado un archivo existente o el programa llamado setSelectedFile(). getSelectedFile() devolverá lo que el usuario escribió en después de el usuario hace clic en el botón de aprobación (es decir, OK).

La técnica solo funcionará para cuadros de diálogo de selección única, sin embargo, la modificación de la extensión de archivo basada en el filtro seleccionado también debería tener sentido para archivos individuales (cuadros de diálogo "Guardar como ...").

Este diseño fue un tema de debate en sun.com en 2003, vea link para más detalles.

Cuestiones relacionadas