2010-12-09 63 views
4

我正在尝试在Java中创建一个程序,它将逐个显示一组图像,以调整每个图像的大小。 我伸出的JPanel显示这样的图像:Java等待组件被绘制

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(); 
      } 
     } 
    } 

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

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

谢谢! Leonty

回答

4

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

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

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

+0

谢谢!它使我走上正轨! 我现在在主线程中执行代码,所有操作现在都是同步的,所以等待绘画完成后才会发生。 – Leonti 2010-12-10 23:47:58

1

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

+0

我试过了,它的工作,但我需要使用包()调整窗口每个图像和我有同样的问题 - 我需要知道什么时候绘画完成调用'pack()'。 – Leonti 2010-12-10 23:51:33

1

这听起来像是你想要图像一个接一个地出现,因为它们被加载(即在网页中),是否正确?如果是这样,你不会得到你当前的代码的效果,因为你的用户界面不会被更新,直到所有图像加载,这是因为你正在加载图像在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 
     } 
    } 
}