【问题标题】:Java wait for component to be paintedJava等待组件被绘制
【发布时间】:2011-05-23 01:52:01
【问题描述】:

我正在尝试用 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();
            } 
        }
    }

问题是我的程序正确地调整了大小,所以图像被正确加载但它不显示任何东西。 如果我只显示一张图像,它也适用于最后一张图像。我认为问题是在图像绘制完成之前调用了 Thread.sleep()。

如何等待我的 ImagePanel 完成绘画并在那之后开始等待? 或者有没有其他方法可以解决这个问题?

谢谢! 莱昂蒂

【问题讨论】:

    标签: java swing jpanel jcomponent


    【解决方案1】:

    您的所有代码都在事件调度线程上执行。这有效地导致所有用户交互进入休眠状态,因为事件调度线程负责所有用户交互——包括输入(事件)和输出(绘画)。

    您需要在 EDT 之外等待。您需要知道如何在 EDT 内外执行事件。为此,您可以创建一个新的 Runnable,然后调用 new Thread(runnable) 以在 EDT 之外执行它,或者调用 SwingUtilities.invokeLater(runnable) 使其在 EDT 上执行。与 Swing 组件的所有交互都需要在 EDT 上进行,因为 Swing 对象不是线程安全的。所有睡眠、等待、文件访问、网络访问、数据库访问或任何其他可能在不确定的时间段内阻塞的事情都必须在 EDT 之外进行。

    关于堆栈溢出的许多问题都与事件调度线程有关。我建议您查看这些以查找更多信息和代码示例,以便以不同的方式执行您希望执行的操作。

    【讨论】:

    • 谢谢!它让我走上了正轨!我现在在主线程中执行代码,所有操作现在都是同步的,所以只有在绘制完成后才会等待。
    【解决方案2】:

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

    【讨论】:

    • 我试过了,它成功了,但我需要使用 pack() 来调整每个图像的窗口大小,我遇到了同样的问题 - 我需要知道绘画何时完成才能调用 'pack()' .
    【解决方案3】:

    听起来您希望图像在加载时一张一张地出现(例如在网页中),对吗?如果是这样,您将不会使用当前代码获得这种效果,因为在加载所有图像之前,您的 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
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      相关资源
      最近更新 更多