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的状态,这可能会生成另一个竞争条件。