Java – make Jfilechooser display image thumbnail

I want to create a Jfilechooser with a thumbnail view of the image file So I subclass fileview and zoom in the method of creating imageicon to display thumbnails

However, the overall effect is that the filechooser widget takes some time before opening the directory and displaying thumbnails In createimageicon () below, I need to call the new imageicon () twice using the image file path, and then use the resized image as the constructor parameter I think it slows down the widget

Is there a more effective alternative? Any suggestion / pointer is the most popular

Thank you, mark

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
}

Solution

I was surprised to see this despite the native look and amplifier I feel that in windows, the file selector does not have a thumbnail view I tried your example. You are moving in the right direction, but I see how slow folders with many large images are Of course, the overhead is due to the I / O when reading the file content and then interpreting the image, which is inevitable

To make matters worse, I found fileview GETICON (file) is heavily invoked - when the mouse hovers over the icon and selects change before displaying the file list If we don't cache the image after loading, we will reload the image meaninglessly

The obvious solution is to push all image loads to another thread or thread pool. Once we get the reduced result, we put it into the temporary cache so that we can retrieve it again

I often use image and imageicon. I find that I can change the image of imageicon at any time by calling SETIMAGE (image) This means to us that in GETICON (file), we can immediately return a blank or default icon, but keep the reference to it and pass it to the worker thread. The worker thread will load the image in the background and set the image of the icon. Later, when it is completed (the only problem is that we must call repaint () to see the changes)

For this example, I use the executorservice cache thread pool (which is the fastest way to get all images, but uses a lot of I / O) to handle the image loading task I also use weakhashmap as a cache to ensure that only cached icons are retained as long as we need them You can use other types of maps, but you must manage the number of icons you keep to avoid running out of memory

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,Image.SCALE_SMOOTH);
            icon.setImage(img);

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

}

Known problems:

1) We do not maintain the aspect ratio of the image when zooming Doing so can cause icons to have strange dimensions, which can break the alignment of the list view The solution might be to create a 16 × 16, and render the scaled image above it, centered If you like, you can achieve it!

2) If the file is not an image or corrupted, no icon will be displayed at all It seems that the program only detects this error when rendering the image, not when we load or scale it, so we can't detect it in advance However, if we solve problem 1, we may detect it

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>