2010-11-04 12 views
6

Volevo creare un JFileChooser con la visualizzazione di anteprima dei file di immagine. Quindi ho creato una sottoclasse di FileView e nel metodo che crea ImageIcon sono state mostrate alcune immagini di anteprima di sothat di ridimensionamento.rendendo jfilechooser mostra le miniature delle immagini

Tuttavia, l'effetto complessivo è che, il widget filechooser richiede un certo tempo prima di aprire una directory e mostrando thumbnails..In createImageIcon() di seguito, ho bisogno di chiamare nuova ImageIcon() due volte, una volta con il percorso del file immagine e la successiva con l'immagine ridimensionata come argomento del costruttore. Penso che questo sia ciò che rallenta il widget.

Esiste un'alternativa più efficiente? Qualsiasi suggerimento/suggerimento è il benvenuto.

grazie, marchio

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 
} 

risposta

7

Sono stato davvero sorpreso di vedere che, nonostante si usi il look nativo &, in Windows il selettore di file non ha una vista di anteprima. Ho provato il tuo esempio e stai seguendo le linee giuste, ma vedo quanto fosse lento per le cartelle con molte immagini di grandi dimensioni. Il sovraccarico è, ovviamente, dovuto all'I/O durante la lettura del contenuto del file e quindi all'interpretazione dell'immagine, il che è inevitabile.

Ciò che è peggio, è che ho scoperto che FileView.getIcon(File) è chiamato un sacco - prima che venga visualizzato l'elenco dei file, quando il mouse su un'icona, e quando cambia la selezione. Se non salviamo in cache le immagini dopo averle caricate, ricaricheremo inutilmente le immagini tutto il tempo.

La soluzione ovvia è di spingere tutte le caricamento immagine via sopra un altro filo o un pool di thread, e una volta che il nostro risultato in scala ridotta, inserirlo in una cache temporanea in modo che possa essere recuperato nuovamente.

Ho suonato in giro con Image e ImageIcon molto e ho scoperto che un'immagine ImageIcon s' possono essere modificati in qualsiasi momento chiamando setImage(Image). Ciò che questo significa per noi è, entro getIcon(File), è possibile restituire immediatamente un'icona vuota o predefinita, ma mantenere un riferimento ad esso, passarlo a un thread di lavoro che caricherà l'immagine in background e impostare l'immagine dell'icona in un secondo momento quando è fatto (l'unica presa è che dobbiamo chiamare repaint() per vedere la modifica).

Per questo esempio, sto utilizzando un pool di thread memorizzato nella cache ExecutorService (questo è il modo più veloce per ottenere tutte le immagini, ma utilizza molti I/O) per elaborare le attività di caricamento dell'immagine. Sto anche usando uno WeakHashMap come cache, per assicurarci di rimanere sulle icone della cache solo per il tempo necessario. Potresti usare un altro tipo di mappa, ma dovresti gestire il numero di icone su cui tieni premuto, per evitare di esaurire la 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();}}); 
     } 
    } 

} 

Problemi noti:

1) Noi non mantenere le proporzioni dell'immagine durante il ridimensionamento. Ciò potrebbe causare la comparsa di icone con dimensioni strane che interromperanno l'allineamento della visualizzazione elenco.La soluzione è probabilmente quella di creare un nuovo BufferedImage che sia 16x16 e rendere l'immagine ridimensionata su di essa, centrata. Puoi implementarlo se lo desideri!

2) Se un file non è un'immagine o è danneggiato, non verrà visualizzata alcuna icona. Sembra che il programma rilevi questo errore solo durante il rendering dell'immagine, non quando lo cariciamo o lo ridimensioniamo, quindi non possiamo rilevarlo in anticipo. Tuttavia, potremmo rilevare se fissiamo problema 1.

0

si potrebbe utilizzare un'icona predefinita per ogni fileand caricare le icone effettivi in ​​un altro thread (magari utilizzando uno SwingWorker?). Quando le icone vengono caricate, SwingWorker può richiamare e aggiornare FileView.

Non sicuro se un singolo SwingWorker farebbe il trucco, o se sarebbe meglio usarne uno per ogni icona caricata.

4

Uso fileDialog invece di JfileChooser per choising l'immagine:

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

Suggerendo AWT in una domanda swing nel 2012? Eww ... –

Problemi correlati