点击鼠标时我想实现“平稳运动”。以下是我的代码:
public void mouseClicked(MouseEvent event) {
int targetX = event.getX();
int targetY = event.getY();
for(int i=0;i<10;++i) {
x = (x+targetX)/2;
y = (y+targetY)/2;
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) { }
}
}
但效果是运动从一个地方“直接”到点击的地方。我知道线程可以实现这一点,原则是事件调度线程不应该做很多动作但我可能知道为什么上面的代码不起作用?谁能给我一些详细的解释?
class Animation extends Thread {
/* … */
public void run() {
int targetX = event.getX();
int targetY = event.getY();
for(int i=0;i<10;++i) {
panel.x = (panel.x+targetX)/2;
panel.y = (panel.y+targetY)/2;
panel.repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
答案 0 :(得分:2)
EDT做了许多重要的工作,除了处理来自操作系统的系统事件外,它还处理许多内部事件,如绘画。
目的是提供单一,统一的机制来处理单个线程上下文中的事件,降低竞争条件和死锁的风险以及诸如脏/部分颜料之类的不良副作用(因为对象已被绘制,因此内部状态发生了变化,影响了剩下要涂的东西)
public void mouseClicked(MouseEvent event) {
int targetX = event.getX();
int targetY = event.getY();
for(int i=0;i<10;++i) {
x = (x+targetX)/2;
y = (y+targetY)/2;
repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) { }
}
}
我假设mouseClicked
是来自MouseListener
接口的实现。 MouseEvent
传递EventQueue
并在EDT内处理,这意味着在EDT的上下文中调用mouseClicked
。
在该方法存在之前,EDT无法处理任何其他事件。这意味着for-loop
和Thread.sleep
的组合阻止EDT处理事件最多一秒。
重要提示,repaint
不会立即发生,它会通过EventQueue
将彩票事件发布到RepaintManager
。
RepaintManager
的一个副作用是它可以将重复的重绘请求合并到几个实际的绘画事件中。
因此,由于您的for-loop
/ Thread.sleep
,您要么在很短的时间内收到所有的油漆事件(而且您根本无法看到它们更新),或者,更有可能的是,你得到了最后一个。
class Animation extends Thread {
/* … */
public void run() {
int targetX = event.getX();
int targetY = event.getY();
for(int i=0;i<10;++i) {
panel.x = (panel.x+targetX)/2;
panel.y = (panel.y+targetY)/2;
panel.repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
}
第二个例子,虽然表面看起来没问题,但是违反了Swing的单线程规则,也就是说,应该在EDT的上下文中对UI进行任何更新。这是为了确保在油漆循环之间不会发生任何更新,从而可能导致脏涂料或不必要的油漆伪影。
作为一般规则,repaint
是关于我认为是线程安全的唯一方法(还有一些,但我保持简单)。
复杂,但动画也是如此。基本要求是......
虽然你可以使用Thread
来实现这一点,但它变得相当困难并且容易出错,并且需要在线程之间进行更多协调
您可以使用SwingWorker
来完成一些猜测工作,但大多数情况下,简单的Swing Timer
做得很好
This example原则上证明了你想要实现的目标,它稍微复杂一些,因为无论线路长度如何,它都会尝试保持速度,但是& #39;是一个例子