很难说你在做什么,
但您似乎正试图从其run() 方法中覆盖Runnable 的paint()。
这肯定做不到。
逻辑是
- 取一个组件
- 重写它的paint方法来绘制我们需要的东西
- 调用方法来更新矩形的坐标(或者在这种情况下计时器会这样做)
- 比在组件上调用
repaint(),因此可以再次调用paint方法并使用其新坐标重绘矩形(定时器也会在更改矩形坐标后负责重绘)
- 根据需要/想要多次重复最后 2 个步骤
(当我说 component 我实际上是指 JPanel,paint 方法 指的是 JPanel 的覆盖 paintComponent(..),因为这是最佳实践。)
一些建议:
1) 不要覆盖paint,而是使用JPanel 并覆盖paintComponent。
2) 不要忘记尊重 绘制链 并调用覆盖 paintComponent(Graphics g)(或任何覆盖该事实的方法)的 super.XXX 实现,除非故意将其省略。即
class MyPanel extends JPanel {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//do drawings here
}
}
3) 如果在paintComponent 中绘图,通常需要覆盖getPreferredSize() 并返回适合JPanel 的内容/绘图的Dimensions,即:
class MyPanel extends JPanel {
@Override
public Dimension getPreferredSize() {
return new Dimension(300,300);
}
}
3) 查看Swing Timer 而不是Thread.sleep(..),因为sleep 会阻塞GUI 线程并使其看起来被冻结。即
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) 另一种选择(因为我现在看到您只是将不是 Swing 组件的 Rectangle 移动)到 Swing 计时器是 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