Java 使用EventDispatchThread vs不显示图像

Java 使用EventDispatchThread vs不显示图像,java,swing,animation,thread-safety,event-dispatch-thread,Java,Swing,Animation,Thread Safety,Event Dispatch Thread,所以我试图显示一个图像(ball),最终我将通过用户输入来控制它。要知道,图像只是使用线程的sleep方法每隔一段时间显示 我创建了两个类,一个扩展JPanel,另一个扩展JFrame。 JPanel子类如下所示: public class BallPanel extends JPanel { private Image ball; private int x,y; public BallPanel(){ try { ball=I

所以我试图显示一个图像(
ball
),最终我将通过用户输入来控制它。要知道,图像只是使用线程的sleep方法每隔一段时间显示

我创建了两个类,一个扩展
JPanel
,另一个扩展
JFrame
JPanel
子类如下所示:

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

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

JFrame
子类如下所示:

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

}
}

现在有趣的是,或者说令人困惑的是,当我运行这里显示的代码时,匿名内部类被注释掉了,球并不总是出现。有时,在显示球之前,我需要重新调整帧的大小(即调用
重新绘制
)。然而,当我使用匿名内部类通过偶数分派线程调用它时,每当我运行代码时,球就会出现。原因是什么?

这与是否从EDT内启动UI没有多大关系(尽管您应该引起这可能会导致许多其他奇怪和有趣的问题),更多的是与您在建立UI内容之前调用了
setVisible
这一事实有关

这可能是系统试图启动并运行EDT,而操作系统调用在EDT建立之前做出响应之间的竞争条件的一个示例

在任何一种情况下,您都应该从EDT内启动UI,并最后调用
setVisible

Swing可能懒得更新UI,这实际上是一个深思熟虑的设计选择,也是一个好主意。您并不总是希望UI在每次更改(如添加/删除组件)后更新,因此它会将部分控制权交给开发人员,以决定何时最好重新验证容器层次结构并请求重新绘制


我还避免使用
线程
来更新UI的状态,因为这可能会导致绘制不干净,因为Swing使用被动渲染方法(在感觉需要时绘制)并考虑使用Swing <代码>定时器< /> >从EDT中更新或使用<代码> BufferStrategy < /代码>,并使用主动呈现方法,然后可以控制

1)。2) 为了更快地获得更好的帮助,可以发布一个(最小完整的可验证示例)或(简短、自包含、正确的示例)。3) 例如,获取图像的一种方法是热链接到中看到的图像。在最后一段中,您是指BallPanel构造函数中的线程还是循环方法中的sleep()调用,还是两者都指?我通常指的是使用
线程
,它什么都不做,但“可能”修改
paintComponent
可能需要的一些变量,以更新UI的状态,这可能会生成另一个竞争条件。