很难说你在做什么,
但似乎您正试图从其方法中覆盖paint()
a 。Runnable
run()
这肯定是做不到的。
逻辑是
- 取一个组件
- 覆盖它的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