2010-11-04 1 views
6

Я хотел создать JFileChooser с миниатюрным изображением файлов изображений. Поэтому я подклассифицировал FileView и в методе, который создает ImageIcon, было показано несколько уменьшенных изображений.создание jfilechooser показать изображение thumbnails

Однако общий эффект заключается в том, что виджет filechooser занимает некоторое время, прежде чем открывать каталог и показывать эскизы .. В createImageIcon() ниже, мне нужно вызвать новый ImageIcon() два раза с образцом пути к файлу и следующий с измененным размером в качестве аргумента конструктора. Я думаю, что это то, что замедляет работу виджета.

Есть ли более эффективная альтернатива? Любые предложения/указатели наиболее приветствуются.

спасибо, знака

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 
} 

ответ

7

Я был на самом деле удивлен, увидев, что, несмотря на использование внешнего вида & чувствую себя в Windows, выбор файла действительно не имеет миниатюры. Я попробовал ваш пример, и вы идете по правильной линии, но я вижу, как медленно это было для папок с большим количеством больших изображений. Накладные расходы, конечно, связаны с вводом-выводом при чтении содержимого файла, а затем с интерпретацией изображения, что неизбежно.

Что еще хуже, это то, что я узнал, что FileView.getIcon(File) называется много - до того, как список файлов отображается, при наведении указателя мыши на значок, а при изменении выбора. Если мы не будем кэшировать изображения после их загрузки, мы будем бесполезно перезагружать изображения все время.

Очевидное решение заключается в том, чтобы вытащить всю загрузку изображения в другой поток или пул потоков, и как только мы получим сокращенный результат, поместите его во временный кеш, чтобы его можно было восстановить снова.

Я играл с Image и ImageIcon много, и я обнаружил, что ImageIcon «s изображение может быть изменен в любое время по телефону setImage(Image). Для нас это означает, что в пределах getIcon(File) мы можем сразу же вернуть пустой или по умолчанию значок, но сохраним ссылку на него, передавая его в рабочий поток, который загрузит изображение в фоновом режиме и установит образ значка позже, когда он done (Единственный улов в том, что мы должны позвонить repaint(), чтобы увидеть изменение).

В этом примере я использую пул кэшированных файлов ExecutorService (это самый быстрый способ получить все изображения, но использует много операций ввода-вывода) для обработки задач загрузки изображений. Я также использую WeakHashMap в качестве кеша, чтобы мы держали только кэшированные значки до тех пор, пока они нам нужны. Вы можете использовать другой вид Карты, но вам нужно будет управлять количеством значков, на которых вы держите, чтобы избежать нехватки памяти.

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

} 

Известные проблемы:

1) Мы не поддерживают соотношение формата изображения при масштабировании. Это может привести к появлению значков со странными размерами, которые нарушают выравнивание вида списка.Возможно, решение состоит в создании нового BufferedImage, который составляет 16x16, и отображает масштабированное изображение поверх него, с центром. Вы можете реализовать это, если хотите!

2) Если файл не является изображением или поврежден, значок не будет отображаться вообще. Похоже, программа обнаруживает эту ошибку только при рендеринге изображения, а не при загрузке или масштабировании, поэтому мы не можем обнаружить это заранее. Тем не менее, мы могли бы обнаружить, если мы фиксируем выпуск 1.

0

Вы можете использовать иконку по умолчанию для каждого fileand загрузки фактических иконок в другом потоке (возможно, с помощью SwingWorker?). По мере загрузки значков SwingWorker может перезвонить и обновить FileView.

Не уверен, что один SwingWorker выполнит трюк или будет лучше использовать один для каждого загружаемого значка.

4

Использование fileDialog вместо JfileChooser для choising изображения:

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

Советовать AWT в свинг вопрос в 2012 году? Eww ... –