Tôi thực sự ngạc nhiên khi thấy rằng, mặc dù sử dụng giao diện gốc & cảm thấy trong Windows, trình chọn tệp thực sự không có chế độ xem hình thu nhỏ. Tôi đã thử ví dụ của bạn và bạn đang đi dọc theo dòng bên phải, nhưng tôi thấy tốc độ của các thư mục với rất nhiều hình ảnh lớn. Tất nhiên, phí trên là do I/O khi đọc nội dung tập tin và sau đó giải thích hình ảnh, điều không thể tránh khỏi.
Điều thậm chí còn tệ hơn, là tôi phát hiện ra rằng FileView.getIcon(File)
được gọi là lô - trước khi danh sách tệp được hiển thị, khi bạn di chuột qua biểu tượng và khi lựa chọn thay đổi. Nếu chúng tôi không lưu trữ hình ảnh sau khi tải chúng, chúng tôi sẽ không ngừng tải hình ảnh mọi lúc.
Giải pháp hiển nhiên là đẩy tất cả tải hình ảnh lên một chủ đề khác hoặc một nhóm luồng và sau khi chúng tôi có kết quả thu nhỏ, hãy đưa nó vào bộ đệm tạm thời để có thể truy xuất lại.
Tôi đã chơi xung quanh với Image
và ImageIcon
rất nhiều và tôi phát hiện thấy hình ảnh của ImageIcon
có thể được thay đổi bất kỳ lúc nào bằng cách gọi setImage(Image)
. Điều này có nghĩa là chúng tôi có thể trả lại một biểu tượng trống hoặc mặc định ngay lập tức, nhưng giữ nguyên tham chiếu đến nó, chuyển nó đến chuỗi công nhân sẽ tải hình ảnh ở chế độ nền và đặt hình ảnh của biểu tượng sau khi nó thực hiện (Việc bắt duy nhất là chúng ta phải gọi repaint()
để xem thay đổi).
Ví dụ này, tôi đang sử dụng một nhóm hồ sơ lưu trữ ExecutorService
được lưu trong bộ nhớ cache (đây là cách nhanh nhất để tải tất cả hình ảnh, nhưng sử dụng nhiều I/O) để xử lý các tác vụ tải hình ảnh. Tôi cũng đang sử dụng WeakHashMap
làm bộ nhớ cache, để đảm bảo rằng chúng tôi chỉ giữ các biểu tượng được lưu trong bộ nhớ cache miễn là chúng tôi cần chúng. Bạn có thể sử dụng một loại bản đồ khác, nhưng bạn sẽ phải quản lý số lượng biểu tượng mà bạn nắm giữ, để tránh hết bộ nhớ.
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();}});
}
}
}
vấn đề đã biết:
1) Chúng tôi không duy trì tỷ lệ khía cạnh của hình ảnh khi mở rộng quy mô. Làm như vậy có thể dẫn đến các biểu tượng có kích thước lạ sẽ phá vỡ căn chỉnh của chế độ xem danh sách.Giải pháp có thể là tạo một BufferedImage
mới là 16x16 và hiển thị hình ảnh được chia tỷ lệ ở trên cùng của nó, được căn giữa. Bạn có thể thực hiện điều đó nếu bạn muốn!
2) Nếu tệp không phải là hình ảnh hoặc bị hỏng, sẽ không có biểu tượng nào được hiển thị. Có vẻ như chương trình chỉ phát hiện lỗi này trong khi hiển thị hình ảnh, chứ không phải khi chúng tôi tải hoặc chia tỷ lệ hình ảnh, vì vậy chúng tôi không thể phát hiện ra điều này trước. Tuy nhiên, chúng ta có thể phát hiện nó nếu chúng ta khắc phục vấn đề 1.
Đề xuất AWT trong một câu hỏi Swing vào năm 2012? Eww… –