使用EventDispatchThread vs不显示图像

时间:2015-07-21 02:03:39

标签: java swing animation thread-safety event-dispatch-thread

所以我试图显示我最终会通过用户输入控制的图像(ball)。要知道,图像只是使用线程的睡眠方法间隔显示。

我已经制作了两个类,一个扩展JPanel,另一个扩展JFrameJPanel子类如下所示:

 public class BallPanel extends JPanel {
    private Image ball;
    private int x,y;
    public BallPanel(){
        try {
            ball=ImageIO.read(new File("C:\\Users\\Owner\\Desktop\\ball.png"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        x=10;
        y=10;
        Thread thread = new Thread() {
            @Override
            public void run(){
                    loop();
        }
      };
        thread.start();
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.drawImage(ball,x,y,null);
    }
    public void loop(){
        while(true){
            repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

在循环方法中,我调用sleep方法以允许在一段时间内调用repaint。然后,在构造函数中调用loop()

JFrame子类如下所示:

    public class BallFrame extends JFrame {

    public BallFrame(){
        setVisible(true);
        setSize(800,800);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setContentPane(new BallPanel());
    }
    public static void main(String args[]){
        //SwingUtilities.invokeLater(new Runnable() {
             //   @Override
              //  public void run() {
                    new BallFrame();
               // }
    //});

}
}

现在有趣的,或者令人困惑的事情是,当我按照这里显示的那样运行代码时,匿名的内部类被注释掉,球并不总是出现。有时我需要在显示球之前重新调整框架的大小(即调用repaint)。但是,当我使用匿名内部类通过偶数调度线程调用它时,每次运行代码时都会出现球。这是什么原因?

1 个答案:

答案 0 :(得分:2)

它与从EDT内部启动用户界面没有什么关系(尽管你应该导致这可能导致许多其他奇怪和有趣的问题),更多的是与你所谓的{{{{{ 1}}之前您已经建立了UI的内容。

这可能是尝试启动和运行EDT的系统与操作系统呼叫在其建立之前响应之间的竞争条件的一个示例。

在任何一种情况下,您都应该从EDT中启动用户界面并最后致电setVisible

Swing对于更新UI很懒惰,这实际上是一个深思熟虑的设计选择,也是一个好主意。在您做出的每一项更改(例如添加/删除组件)之后,您并不总是希望更新UI,因此它会将一些控制交给开发人员以确定何时最适合{{1容器层次结构和请求setVisible s

我还会避免使用revalidate更新UI的状态,因为这可能会导致脏涂料,因为Swing使用被动渲染方法(在感觉需要时进行绘制)并考虑使用Swing repaint从EDT内部更新或使用Thread并采用主动渲染方法,然后您可以控制