使用 EventDispatchThread 与不使用 EventDispatchThread 显示图像

Display an image using EventDispatchThread vs without

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

我制作了 2 个 classes,一个扩展了 JPanel,另一个扩展了 JFrameJPanel subclass 看起来像这样:

 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 subclass 看起来像这样:

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

}
}

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

这与是否从 EDT 中启动 UI 没有什么关系(尽管你应该导致这可能会导致许多其他奇怪和有趣的问题),更多的是与你的事实有关在建立 UI.

的内容之前,您已经调用了 setVisible

这可能是系统尝试启动 EDT 和 运行 以及 OS 调用在其建立之前响应之间的竞争条件示例。

无论哪种情况,您都应该从 EDT 中启动 UI,最后调用 setVisible

Swing 可以偷懒更新UI,这实际上是一种深思熟虑的设计选择,也是一个好主意。您并不总是希望 UI 在每次更改后更新(例如 adding/removing 组件),因此它会将一些控制权移交给开发人员以决定何时最好 revalidate 容器层次结构和请求 repaints

我也会避免使用 Thread 来更新 UI 的状态,因为这可能会导致油漆变脏,因为 Swing 使用被动渲染方法(在感觉需要时进行绘制)并考虑使用从 EDT 中更新的 Swing Timer 或使用 BufferStrategy 并采用主动渲染方法,然后您可以控制