2010-11-04 31 views
6

Je voulais créer un JFileChooser avec affichage des vignettes des fichiers image.So j'ai sous-classé FileView et dans la méthode qui crée ImageIcon a fait une mise à l'échelle que les images miniatures sont affichées. Cependant, l'effet global est que le widget filechooser prend un certain temps avant d'ouvrir un répertoire et d'afficher des vignettes. Dans createImageIcon() ci-dessous, je dois appeler deux fois ImageIcon() une fois avec l'image filepath et ensuite avec l'image redimensionnée comme argument constructeur. Je pense que c'est ce qui ralentit le widget.faire jfilechooser afficher les vignettes d'image

Y a-t-il une alternative plus efficace? Toutes suggestions/pointeurs sont les bienvenues.

grâce, marque

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 
} 

Répondre

7

J'ai été réellement surpris de voir que, malgré l'utilisation de l'aspect natif & sentir dans Windows, le sélecteur de fichiers n'a en effet pas une vue miniature. J'ai essayé votre exemple et vous allez dans le bon sens, mais je vois à quel point c'était lent pour les dossiers avec beaucoup de grandes images. Le surdébit est, bien sûr, dû aux E/S lors de la lecture du contenu du fichier, puis à l'interprétation de l'image, ce qui est inévitable.

Ce qui est encore plus grave, est que j'ai trouvé que FileView.getIcon(File) est appelé beaucoup - avant la liste des fichiers est affichée, lorsque vous passez la souris sur une icône, et lorsque les changements de sélection. Si nous ne mettons pas en cache les images après les avoir chargées, nous rechargerons inutilement des images tout le temps. La solution évidente consiste à pousser tout le chargement de l'image sur un autre thread ou pool de threads, et une fois que nous avons notre résultat réduit, placez-le dans un cache temporaire afin qu'il puisse être récupéré à nouveau.

J'ai joué avec Image et ImageIcon beaucoup et j'ai découvert qu'une image de ImageIcon peut être modifié à tout moment en appelant setImage(Image). Ce que cela signifie pour nous est, dans getIcon(File), nous pouvons immédiatement retourner une icône vide ou par défaut, mais gardez une référence, en le passant à un thread de travail qui va charger l'image en arrière-plan et définir l'image de l'icône plus tard quand il est done (Le seul hic est que nous devons appeler repaint() pour voir le changement).

Pour cet exemple, j'utilise un pool de threads mis en cache ExecutorService (c'est le moyen le plus rapide d'obtenir toutes les images, mais utilise beaucoup d'E/S) pour traiter les tâches de chargement d'image. J'utilise également un WeakHashMap comme cache, pour m'assurer que nous ne conservons que les icônes en cache aussi longtemps que nous en aurons besoin. Vous pouvez utiliser un autre type de carte, mais vous devrez gérer le nombre d'icônes que vous gardez, pour éviter de manquer de mémoire.

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

} 

Problèmes connus:

1) Nous ne permettent pas de maintenir le ratio d'aspect de l'image lors du redimensionnement. Cela pourrait entraîner des icônes avec des dimensions étranges qui rompre l'alignement de la vue de liste.La solution est probablement de créer un nouveau BufferedImage de 16x16 et de rendre l'image mise à l'échelle par dessus, centrée. Vous pouvez l'implémenter si vous le souhaitez!

2) Si un fichier n'est pas une image ou est corrompu, aucune icône ne sera affichée du tout. Il semble que le programme ne détecte cette erreur que lors du rendu de l'image, pas lorsque nous la chargeons ou l'agrandissons, donc nous ne pouvons pas la détecter à l'avance. Cependant, nous pourrions détecter si nous fixons problème 1.

0

Vous pouvez utiliser une icône par défaut pour chaque fileand charger les icônes réelles dans un autre thread (peut-être au moyen d'un SwingWorker?). Au fur et à mesure que les icônes sont chargées, SwingWorker peut rappeler et mettre à jour FileView.

Vous ne savez pas si un seul SwingWorker ferait l'affaire, ou s'il serait préférable d'en utiliser un pour chaque icône chargée.

4

Utilisation fileDialog au lieu de JfileChooser pour choising l'image:

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

Suggérant AWT en 2012 en question Swing? Eww ... –