2010-11-04 56 views
6

Quería crear un JFileChooser con una vista en miniatura de los archivos de imagen. Así que subclasé FileView y en el método que crea ImageIcon hice algunas escalas para mostrar las imágenes en miniatura.haciendo jfilechooser mostrar imágenes en miniatura

Sin embargo, el efecto general es que el widget filechooser tarda un tiempo antes de abrir un directorio y mostrar miniaturas .. En CreateImageIcon() a continuación, necesito llamar al nuevo ImageIcon() dos veces: una con la imagen filepath y el siguiente con la imagen redimensionada como argumento de constructor. Creo que esto es lo que ralentiza el widget.

¿Existe una alternativa más eficiente? Cualquier sugerencia/sugerencia más bienvenida.

gracias, marca

public static void main(String[] args) { 
    JFileChooser chooser=new JFileChooser(); 
    ThumbNailView thumbView=new ThumbNailView(); 
    chooser.setFileView(thumbView); 
    } 

class ThumbNailView extends FileView{ 
public Icon getIcon(File f){ 
    Icon icon=null; 
    if(isImageFile(f.getPath())){ 
    icon=createImageIcon(f.getPath(),null); 
    } 
    return icon; 
} 
private ImageIcon createImageIcon(String path,String description) { 
    if (path != null) { 
    ImageIcon icon=new ImageIcon(path); 
    Image img = icon.getImage() ; 
    Image newimg = img.getScaledInstance(16, 16, java.awt.Image.SCALE_SMOOTH) ; 
    return new ImageIcon(newimg); 
    } else { 
    System.err.println("Couldn't find file: " + path); 
    return null; 
    } 
} 

private boolean isImageFile(String filename){ 
    //return true if this is image 
} 

Respuesta

7

De hecho, me sorprendió ver que, a pesar de utilizar el aspecto nativo & en Windows, el selector de archivos no tiene una vista en miniatura. Probé tu ejemplo y vas por las líneas correctas, pero veo lo lento que fue para las carpetas con muchas imágenes grandes. La sobrecarga es, por supuesto, debido a E/S al leer el contenido del archivo y luego interpretar la imagen, que es inevitable.

Lo que es aún peor, es que descubrí que FileView.getIcon(File) se llama un montón- antes de que aparezca la lista de archivos, al pasar el ratón sobre un icono, y cuando cambia la selección. Si no almacenamos en caché las imágenes después de cargarlas, recargaremos sin sentido las imágenes todo el tiempo.

La solución obvia es eliminar toda la carga de imágenes en otro subproceso o un grupo de subprocesos, y una vez que tenemos nuestro resultado reducido, colóquelo en un caché temporal para que pueda recuperarse nuevamente.

He jugado un poco con Image y ImageIcon mucho y he descubierto que un ImageIcon 's imagen se puede cambiar en cualquier momento llamando setImage(Image). Lo que esto significa para nosotros es que, dentro de getIcon(File), podemos devolver inmediatamente un ícono en blanco o predeterminado, pero mantener una referencia, pasarlo a un hilo de trabajo que cargará la imagen en el fondo y establecerá la imagen del ícono más adelante cuando esté hecho (El único inconveniente es que debemos llamar al repaint() para ver el cambio).

Para este ejemplo, estoy usando un grupo de subprocesos en caché ExecutorService (esta es la forma más rápida de obtener todas las imágenes, pero usa mucha E/S) para procesar las tareas de carga de imágenes. También estoy usando un WeakHashMap como caché, para asegurarnos de que solo retengamos los íconos en la memoria caché por el tiempo que los necesitemos. Podría usar otro tipo de Mapa, pero tendría que administrar la cantidad de íconos a los que se agarra, para evitar quedarse sin memoria.

package guitest; 

import java.awt.Image; 
import java.awt.image.BufferedImage; 
import java.io.File; 
import java.util.Map; 
import java.util.WeakHashMap; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.regex.Pattern; 

import javax.swing.Icon; 
import javax.swing.ImageIcon; 
import javax.swing.JFileChooser; 
import javax.swing.SwingUtilities; 
import javax.swing.UIManager; 
import javax.swing.filechooser.FileView; 

public class ThumbnailFileChooser extends JFileChooser { 

    /** All preview icons will be this width and height */ 
    private static final int ICON_SIZE = 16; 

    /** This blank icon will be used while previews are loading */ 
    private static final Image LOADING_IMAGE = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB); 

    /** Edit this to determine what file types will be previewed. */ 
    private final Pattern imageFilePattern = Pattern.compile(".+?\\.(png|jpe?g|gif|tiff?)$", Pattern.CASE_INSENSITIVE); 

    /** Use a weak hash map to cache images until the next garbage collection (saves memory) */ 
    private final Map imageCache = new WeakHashMap(); 

    public static void main(String[] args) throws Exception { 
     UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     JFileChooser chooser = new ThumbnailFileChooser(); 
     chooser.showOpenDialog(null); 
     System.exit(1); 
    } 

    public ThumbnailFileChooser() { 
     super(); 
    } 

    // --- Override the other constructors as needed --- 

    { 
     // This initializer block is always executed after any constructor call. 
     setFileView(new ThumbnailView()); 
    } 

    private class ThumbnailView extends FileView { 
     /** This thread pool is where the thumnnail icon loaders run */ 
     private final ExecutorService executor = Executors.newCachedThreadPool(); 

     public Icon getIcon(File file) { 
      if (!imageFilePattern.matcher(file.getName()).matches()) { 
       return null; 
      } 

      // Our cache makes browsing back and forth lightning-fast! :D 
      synchronized (imageCache) { 
       ImageIcon icon = imageCache.get(file); 

       if (icon == null) { 
        // Create a new icon with the default image 
        icon = new ImageIcon(LOADING_IMAGE); 

        // Add to the cache 
        imageCache.put(file, icon); 

        // Submit a new task to load the image and update the icon 
        executor.submit(new ThumbnailIconLoader(icon, file)); 
       } 

       return icon; 
      } 
     } 
    } 

    private class ThumbnailIconLoader implements Runnable { 
     private final ImageIcon icon; 
     private final File file; 

     public ThumbnailIconLoader(ImageIcon i, File f) { 
      icon = i; 
      file = f; 
     } 

     public void run() { 
      System.out.println("Loading image: " + file); 

      // Load and scale the image down, then replace the icon's old image with the new one. 
      ImageIcon newIcon = new ImageIcon(file.getAbsolutePath()); 
      Image img = newIcon.getImage().getScaledInstance(ICON_SIZE, ICON_SIZE, Image.SCALE_SMOOTH); 
      icon.setImage(img); 

      // Repaint the dialog so we see the new icon. 
      SwingUtilities.invokeLater(new Runnable() {public void run() {repaint();}}); 
     } 
    } 

} 

problemas conocidos

1) No mantener la relación de aspecto de la imagen cuando se escala. Hacerlo podría dar como resultado iconos con dimensiones extrañas que romperán la alineación de la vista de lista.La solución probablemente sea crear un nuevo BufferedImage que sea 16x16 y renderizar la imagen escalada encima, centrada. ¡Puedes implementar eso si lo deseas!

2) Si un archivo no es una imagen, o está dañado, no se mostrará ningún icono en absoluto. Parece que el programa solo detecta este error mientras se procesa la imagen, no cuando la cargamos o escalamos, por lo que no podemos detectar esto por adelantado. Sin embargo, podríamos detectarlo si fijamos tema 1.

0

Se puede usar un icono predeterminado para cada fileand cargar los iconos reales en otro hilo (tal vez mediante un SwingWorker?). A medida que se cargan los iconos, SwingWorker podría devolver la llamada y actualizar FileView.

No estoy seguro de si un único SwingWorker haría el truco, o si sería mejor usar uno para cada icono que se carga.

4

Uso fileDialog en lugar de JfileChooser para choising la imagen:

FileDialog fd = new FileDialog(frame, "Test", FileDialog.LOAD); 
String Image_path 

fd.setVisible(true); 
name = fd.getDirectory() + fd.getFile(); 
     image_path=name; 
     ImageIcon icon= new ImageIcon(name); 
     icon.setImage(icon.getImage().getScaledInstance(jLabel2.getWidth(),jLabel2.getHeight() , Image.SCALE_DEFAULT)); 
     jLabel2.setIcon(icon); 
+0

Sugiriendo AWT en una pregunta de oscilación en el 2012? Eww ... –

Cuestiones relacionadas