I was really surprised to see this, despite the fact that it uses the look and look in Windows, the file selection really has no thumbnails. I tried your example and you are on the right line, but I see how slow it was for folders with lots of large images. The overhead, of course, is associated with I / O when reading the contents of the file, and then with the interpretation of the image, which is inevitable.
What's worse is that I found that FileView.getIcon(File) is called a lot - before displaying a list of files, when you hover over the icon and when the selection changes. If we do not cache the images after they are downloaded, we will uselessly reload the images all the time.
The obvious solution is to pull the entire image load onto another thread or thread pool, and as soon as we get our shortened result, put it in a temporary cache so that it can be retrieved again.
I played a lot with Image and ImageIcon , and I found that ImageIcon image can be changed at any time by calling setImage(Image) . For us, this means that in getIcon(File) we can immediately return an empty or default icon, but keep a link to it, passing it to a workflow that will load the image in the background and set the icon image later when it was done (the only catch we need to call repaint() to see the change).
In this example, I use the thread pool ExecutorService cached streams (this is the fastest way to get all images, but uses a lot of I / O) to handle image loading tasks. I also use WeakHashMap as a cache so that we only keep cached icons for as long as we need them. You can use a different kind of Map, but you will need to control the number of icons you hold on 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 { private static final int ICON_SIZE = 16; private static final Image LOADING_IMAGE = new BufferedImage(ICON_SIZE, ICON_SIZE, BufferedImage.TYPE_INT_ARGB); private final Pattern imageFilePattern = Pattern.compile(".+?\\.(png|jpe?g|gif|tiff?)$", Pattern.CASE_INSENSITIVE); 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(); }
Known Issues:
1) We do not support image aspect ratio when scaling. This can lead to strange sized icons that disrupt the alignment of the list view. Perhaps the solution is to create a new BufferedImage that is 16x16 and displays a scaled image on top of it, centered. You can implement this if you want!
2) If the file is not an image or damaged, the icon will not be displayed at all. It seems that the program detects this error only when rendering the image, and not when loading or scaling, so we can not detect it in advance. However, we can detect this if we fix problem 1.