如何在 ImageLoader 中同步 ImageIcon
Posted
技术标签:
【中文标题】如何在 ImageLoader 中同步 ImageIcon【英文标题】:How to synchronize ImageIcon in ImageLoader 【发布时间】:2021-12-23 21:31:21 【问题描述】:我最近开始在 Java 中使用多线程,我遇到了一个问题,我认为是由于缺少同步。
这是我写的 ImageLoader:
package util;
import javax.swing.ImageIcon;
public class ImageLoader extends Thread
private String file;
private ImageIcon icon;
public ImageLoader(String file)
this.file = file;
@Override
public void run()
ImageIcon icon = new ImageIcon(this.file);
this.icon = icon;
super.run();
public synchronized ImageIcon returnIcon()
return this.icon;
我在我的 GUI 类中使用这个 ImageLoader:
package gui;
import java.awt.Dimension;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import util.ImageLoader;
public class HauptGui extends JComponent
public HauptGui()
initUI();
private void initUI()
int bilderAnzahl = 3;
this.setLayout(new GridLayout(1, 1));
JPanel bilderPanel = new JPanel(new GridLayout(bilderAnzahl, 1));
for (int i = 0; i < bilderAnzahl; i++)
JLabel jbl = new JLabel();
ImageLoader loader = new ImageLoader("./Picture.jpg");
loader.start();
jbl.setIcon(loader.returnIcon());
jbl.setBorder(BorderFactory.createEtchedBorder());
jbl.setPreferredSize(new Dimension(200, 50));
bilderPanel.add(jbl);
JScrollPane scrPn = new JScrollPane(bilderPanel);
this.add(scrPn);
问题是ImageLoader的returnIcon-Method在Thread调用run-Method之前被调用,因此ImageIcon仍然为null。
如何同步?
【问题讨论】:
ImageIcon(String)
构造函数已经使用异步图像加载。因此,将其执行移至后台线程是没有意义的。
【参考方案1】:
不,您的问题与同步无关,而与创建图像对象之前简单地请求有关。解决方案是在完成加载后在回调中获取图像对象。 SwingWorker 在这种情况下会很好地工作,您可以通过调用 .get()
在工作人员的 done 方法中从 SwingWorker 获取图像对象,或者您可以使用 PropertyChangeListener 进行回调。有关如何使用 SwingWorkers 的详细信息,请参阅Lesson: Concurrency in Swing。
例如(代码未测试)
public class ImageLoader2 extends SwingWorker<BufferedImage, Void>
private String path = ""; /// String to resource path
public BufferedImage doInBackground() throws Exception
return ImageIO.read(ImageLoader2.class.getResource(path));
然后像这样运行它:
ImageLoader2 loader = new ImageLoader2();
loader.addPropertyChangeListener(pce ->
if (evt.getNewValue() == SwingWorker.StateValue.DONE)
try
BufferedImage img = loader.get();
ImageIcon icon = new ImageIcon(img);
// use icon here...
catch catch (InterruptedException | ExecutionException e)
e.printStackTrace();
// handle exception here
);
loader.execute();
附注
-
您几乎应该从不扩展 Thread。
不要将图像作为文件获取,而是将其作为资源获取并使用
ImageIO.read(...)
来执行此操作
资源路径是相对于类路径的,而不是相对于用户目录的,因此它可能与您用于将图像作为文件获取的路径不同。
【讨论】:
以上是关于如何在 ImageLoader 中同步 ImageIcon的主要内容,如果未能解决你的问题,请参考以下文章
Android UI-开源框架ImageLoader的完美例子