我正在尝试根据Head First Java练习为一个圆圈制作动画。原始练习要求在“AnimatedBall”类中使用内部“MyDrawPanel”类,但我正在尝试执行外部MyDrawPanel类。我没有错误,但也没有动画。我假设它与我传递值到MyDrawPanel构造函数有关,当我运行for循环时不会更新,但我想知道为什么会这样。
AnimatedBall2.java:
import javax.swing.JFrame;
public class AnimatedBall2 {
JFrame frame = new JFrame();
int height = 300;
int width = 300;
int x = 70;
int y = 70;
public static void main(String[] args){
AnimatedBall2 gui = new AnimatedBall2();
gui.go();
}
public void go(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel panel = new MyDrawPanel(x, y, height, width);
frame.getContentPane().add(panel);
frame.setSize(height,width);
frame.setVisible(true);
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
}
}
MyDrawPanel.java:
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;
public class MyDrawPanel extends JPanel{
int x;
int y;
int height;
int width;
public MyDrawPanel(int x1, int y1, int z1, int z2){
x = x1;
y = y1;
height = z1;
width = z2;
}
public void paintComponent(Graphics g){
g.setColor(Color.white);
g.fillRect(0, 0, height, width);
g.setColor(Color.orange);
g.fillOval(x, y, 100, 100);
}
}
答案 0 :(得分:2)
Swing是一个单线程框架,也就是说,有一个线程负责处理系统中的所有事件并安排绘制。
任何阻止此线程的东西都会阻止它处理新事件或绘制请求。
这是一个非常糟糕的主意......
public void go(){
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyDrawPanel panel = new MyDrawPanel(x, y, height, width);
frame.getContentPane().add(panel);
frame.setSize(height,width);
frame.setVisible(true);
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
}
添加可能会锁定您的应用程序......
查看Concurrency in Swing了解更多详情。您还应该查看Initial Threads
在这种情况下,我建议使用javax.swing.Timer
,有关详细信息,请参阅How to use Swing Timers。
主要问题是,您已在x
课程中取消y
和AnimatedBall2
...
public class AnimatedBall2 {
//...
int x = 70;
int y = 70
在你的MyDrawPanel
班级......
public class MyDrawPanel extends JPanel{
int x;
int y;
但是你的循环正在更新AnimatedBall2
类中的值,这意味着MyDrawPanel
中的值永远不会改变
您需要添加某种“更新”方法,该方法可以告诉MyDrawPanel
它应该相应地更新x
/ y
值...
这让我们看到... Swing不是线程安全的,所有修改或与UI的交互都应该在Event Dispatching Thread的上下文中完成...这就是为什么我建议使用Swing {{1因为它在EDT的上下文中触发它的通知。
执行自定义绘画时,您应该在执行自己的任何自定义绘画之前调用Timer
。你也不应该转发“魔术”号码
super.paintComponent
布局管理器可以根据需要更改组件的大小,相反,您应该使用g.fillRect(0, 0, height, width);
和getWidth
,它将准确地告诉您当前组件的大小是多少
例如......
getHeight
答案 1 :(得分:0)
for(int i = 0; i < 100; i++){
x++;
y++;
panel.repaint();
try{
Thread.sleep(50);
} catch(Exception ex){}
}
x和y是int类型,而不是指针。所以当你做x ++和y ++时。它实际上没有更新你在构造函数中传入的x,y值