很难说你在做什么,
但似乎您正试图从其方法中覆盖paint()a 。Runnablerun()
这肯定是做不到的。
逻辑是
- 取一个组件
- 覆盖它的paint方法来绘制我们需要的东西
- 调用方法来更新矩形的坐标(或者在这种情况下计时器会这样做)
- 比调用
repaint()组件,因此可以再次调用paint方法并使用其新坐标重新绘制矩形(定时器也会在更改矩形坐标后负责重新绘制)
- 根据需要/想要多次重复最后 2 个步骤
(当我说组件时,我实际上是指JPanel,paint 方法是指覆盖paintComponent(..)的,JPanel因为这是最佳实践。)
一些建议:
1)不要覆盖paint而不是使用JPanel和覆盖paintComponent。
2)不要忘记尊重油漆链并调用super.XXX覆盖paintComponent(Graphics g)(或任何覆盖该事实的方法)的实现,除非故意将其排除在外。IE
class MyPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//do drawings here
}
}
3) 如果在其中绘图,paintComponent通常需要覆盖getPreferredSize()并返回Dimension适合 的内容/绘图的 s JPanel,即:
class MyPanel extends JPanel {
@Override
public Dimension getPreferredSize() {
return new Dimension(300,300);
}
}
3) 查看Swing Timer而不是Thread.sleep(..)assleep会阻塞 GUI 线程并使其看起来被冻结。IE
Timer t = new Timer(10, new AbstractAction() {
int count = 20;
@Override
public void actionPerformed(ActionEvent ae) {
if (count < 1000) {
//increment rectangles y position
//now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
count++;
} else {//counter is at 1000 stop the timer
((Timer) ae.getSource()).stop();
}
}
});
t.start();
4) 另一种选择(因为我现在看到您只是将 aRectangle不是 Swing 组件移动)到 Swing timer is TimerTask,只要不会从其方法中创建/操作任何 Swing 组件(run()如TimerTask不像 Swing Timer 那样在 EDT 上运行)。注意revalidate()和repaint()是线程安全的,因此可以在TimerTask.
上述优点是保留了 EDT 的不必要代码(即通过更改坐标移动 AWT 矩形),即
final TimerTask tt = new TimerTask() {
@Override
public void run() {
if (count < 1000) {
//increment rectangles y position
//now repaint container so we can see changes in co-ordinates (unless you have a timer which repaints for you too)
count++;
} else {//counter is at 1000 stop the timer
cancel();
}
}
};
new Timer().scheduleAtFixedRate(tt, 0, 10);//start in 0milis and call run every 10 milis