Java等待组件被绘制

时间:2010-12-09 19:21:58

标签: java swing jpanel jcomponent

我正在尝试用Java创建一个程序,它会一个接一个地显示一组图像,调整每个图像的大小。 我正在扩展JPanel以显示如下图像:

public class ImagePanel extends JPanel{

String filename;
Image image;
boolean loaded = false;

ImagePanel(){}

ImagePanel(String filename){
    loadImage(filename);
}

public void paintComponent(Graphics g){
    super.paintComponent(g);
    if(image != null && loaded){
        g.drawImage(image, 0, 0, this);
    }else{
        g.drawString("Image read error", 10, getHeight() - 10);
    }
}

public void loadImage(String filename){
    loaded = false;         
    ImageIcon icon = new ImageIcon(filename);
    image = icon.getImage();
    int w = image.getWidth(this);
    int h = image.getHeight(this);
    if(w != -1 && w != 0 && h != -1 && h != 0){
        setPreferredSize(new Dimension(w, h));
        loaded = true;
    }else{
        setPreferredSize(new Dimension(300, 300));
    }
}

}

然后在事件线程中我正在做主要工作:

        SwingUtilities.invokeLater(new Runnable(){

        @Override
        public void run(){
            createGUI();
        }
    });

在createGUI()中,我正在浏览图像集:

        ImagePanel imgPan = new ImagePanel();
    add(imgPan);

    for(File file : files){
        if(file.isFile()){
            System.out.println(file.getAbsolutePath());

            imgPan.loadImage(file.getAbsolutePath());
            pack();

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
        }
    }

问题是我的程序正确调整大小,因此图像正确加载但不显示任何内容。 如果我只显示1个图像,它也适用于最后一个图像。我认为问题是在完成图像绘制之前调用Thread.sleep()。

我怎样才能等待我的ImagePanel完成绘画并在此之后开始等待? 或者还有另一种解决问题的方法吗?

谢谢! Leonty

3 个答案:

答案 0 :(得分:5)

所有代码都在Event Dispatch Thread上执行。这有效地导致所有用户交互进入休眠状态,因为事件调度线程负责所有用户交互 - 输入(事件)和输出(绘图)。

你需要等待在美国东部时间之外发生。您需要知道如何在EDT上下执行事件。您可以通过创建新的Runnable然后调用new Thread(runnable)以在EDT上执行它来执行此操作,或者SwingUtilities.invokeLater(runnable)使其在EDT上执行。所有与Swing组件的交互都需要在EDT上进行,因为Swing对象不是线程安全的。所有休眠,等待,文件访问,网络访问,数据库访问或任何其他可能阻止不确定时间的内容都必须在美国东部时间之外进行。

Stack Overflow上有很多与Event Dispatch Thread有关的问题。我建议您查看这些内容以查找更多信息和代码示例,以便以不同的方式执行您要执行的操作。

答案 1 :(得分:1)

而不是使线程休眠使用计时器并将下一个图像作为事件启动。

答案 2 :(得分:1)

听起来您希望图像在加载时逐个显示(即在网页中),这是正确的吗?如果是这样,你就不会对当前代码产生影响,因为在加载所有图像之前你的UI都不会更新,这是因为你在EDT(事件调度线程)上加载图像,这与'我会做这幅画。绘画发生在“有时间”时,在这种情况下意味着在加载所有图像之后。

要解决您的问题,我建议您创建一个SwingWorker子类,如:

public class MyImageLoader extends SwingWorker<Void, String>
{
    // Is executed in background thread, EDT can meanwhile load and paint images
    @Override
    protected Void doInBackground() throws Exception
    {
        for(File file : files)
        {
             if(file.isFile()) // Maybe some more check to see if it's an image
             {
                 publish(file.getAbsolutePath());
                 Thread.sleep(500);
             }
        }
    }

    // Executed on EDT
    @Override
    protected void process(List<String> filePaths)
    {
        for(String path : filePaths)
        {
            // Load ImageIcon to UI
        }
    }
}