使 jfilechooser 显示图像缩略图
我想创建一个带有图像文件缩略图的 JFileChooser
。因此,我对 FileView 进行了子类化,并在创建 ImageIcon
的方法中进行了一些缩放,以便显示缩略图。
然而,总体效果是,filechooser
小部件在打开目录并显示缩略图之前需要一些时间。在下面的 createImageIcon() 中,我需要对图像调用 new 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
}
I wanted to create a JFileChooser
with thumbnail view of image files.So I subclassed FileView and in the method which creates ImageIcon
did some scaling sothat thumbnail images are shown.
However,the overall effect is that, the filechooser
widget takes some time before opening a directory and showing thumbnails..In createImageIcon() below,I need to call new ImageIcon() twice-once with the image filepath and next with the resized image as constructor argument.I think this is what slows the widget .
Is there a more efficient alternative?Any suggestions/pointers most welcome.
thanks,
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
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我实际上很惊讶地看到这一点,尽管使用了原生的外观和效果。感觉在Windows中,文件选择器确实没有缩略图视图。我尝试了你的示例,你正在沿着正确的路线前进,但我发现对于包含大量大图像的文件夹来说它有多慢。当然,开销是由于读取文件内容然后解释图像时的 I/O 造成的,这是不可避免的。
更糟糕的是,我发现
FileView.getIcon(File)
被称为 lot - 在显示文件列表之前,当您将鼠标悬停在图标上时,并且当选择改变时。如果我们在加载图像后不缓存图像,我们将一直毫无意义地重新加载图像。显而易见的解决方案是将所有图像加载推到另一个线程或线程池上,一旦我们得到缩小的结果,将其放入临时缓存中,以便可以再次检索。
我经常使用
Image
和ImageIcon
,我发现ImageIcon
的图像可以通过调用随时更改设置图像(图像)
。这对我们来说意味着,在getIcon(File)
中,我们可以立即返回一个空白或默认图标,但保留对它的引用,将其传递给一个工作线程,该线程将在背景并在完成后设置图标的图像(唯一的问题是我们必须调用repaint()
才能看到更改)。对于此示例,我使用
ExecutorService
缓存线程池(这是获取所有图像的最快方法,但使用大量 I/O)来处理图像加载任务。我还使用WeakHashMap
作为缓存,以确保我们只在需要时保留缓存的图标。您可以使用另一种地图,但您必须管理所持有的图标数量,以避免内存不足。已知问题:
1) 缩放时我们不会保持图像的纵横比。这样做可能会导致图标尺寸奇怪,从而破坏列表视图的对齐方式。解决方案可能是创建一个新的 16x16 的 BufferedImage ,并在其顶部居中渲染缩放后的图像。如果您愿意,您可以实施它!
2) 如果文件不是图像或已损坏,则根本不会显示任何图标。看起来程序只在渲染图像时检测到此错误,而不是在我们加载或缩放图像时检测到此错误,因此我们无法提前检测到此错误。但是,如果解决问题 1,我们可能会检测到它。
I was actually surprised to see that, despite using the native look & feel in Windows, the file chooser indeed doesn't have a thumbnail view. I tried your example and you're going along the right lines, but I see how slow it was for folders with a lot of large images. The overhead is, of course, due to I/O when reading the file contents and then interpreting the image, which is unavoidable.
What's even worse, is that I found out that
FileView.getIcon(File)
is called a lot - before the file list is shown, when you mouse over an icon, and when the selection changes. If we don't cache the images after loading them, we'll be pointlessly reloading images all the time.The obvious solution is to push all the image loading off onto another thread or a thread pool, and once we have our scaled-down result, put it into a temporary cache so it can be retrieved again.
I played around with
Image
andImageIcon
a lot and I discovered that anImageIcon
's image can be changed at any time by callingsetImage(Image)
. What this means for us is, withingetIcon(File)
, we can immediately return a blank or default icon, but keep a reference to it, passing it along to a worker thread that will load the image in the background and set the icon's image later when it's done (The only catch is that we must callrepaint()
to see the change).For this example, I'm using an
ExecutorService
cached thread pool (this is the fastest way to get all images, but uses a lot of I/O) to process the image loading tasks. I'm also using aWeakHashMap
as the cache, to ensure that we only hold onto the cached icons for as long as we need them. You could use another kind of Map, but you would have to manage the number of icons you hold onto, to avoid running out of memory.Known issues:
1) We don't maintain the image's aspect ratio when scaling. Doing so could result in icons with strange dimensions that will break the alignment of the list view. The solution is probably to create a new
BufferedImage
that is 16x16 and render the scaled image on top of it, centered. You can implement that if you wish!2) If a file is not an image, or is corrupted, no icon will be shown at all. It looks like the program only detects this error while rendering the image, not when we load or scale it, so we can't detect this in advance. However, we might detect it if we fix issue 1.
使用
fileDialog
而不是JfileChooser
来选择图像:Use
fileDialog
instead ofJfileChooser
for choising the image:您可以为每个文件使用默认图标,并在另一个线程中加载实际图标(也许使用 SwingWorker?)。当图标加载时,SwingWorker 可以回调并更新 FileView。
不确定单个 SwingWorker 是否可以解决问题,或者为每个正在加载的图标使用一个 SwingWorker 是否会更好。
You could use a default icon for each fileand load the actual icons in another thread (perhaps using a SwingWorker?). As the icons are loaded the SwingWorker could call back and update the FileView.
Not sure if a single SwingWorker would do the trick, or whether it would be better to use one for each icon being loaded.