Java Swing处理双击事件与单击区分开
问题描述
国庆莫得了,开始写Java作业了呜呜呜呜呜。
编写Java程序,创建一个窗体,并实现交互。在窗体内“单击鼠标左键”,在光标处绘制一个“绿圆”;窗体内“单击鼠标右键”,在光标处绘制一个“红色方框”;窗体内“双击鼠标左键”,清空所有已画“圆”和“方”。
本题的难点在于,如何使MouseListener
类分辨单击与双击操做。感觉大体上方向就应该是利用后一次点击来取消前一次点击要做的操做。
我试了一些办法,发现Java处理事件的时候,应该是将发生的事件按照时间顺序放进一个队列中,一个个执行,执行这些操做的线程就是Java Swing的三大线程之一,EDT线程。以下是EDT线程的介绍。
事件派发线程(EDT,Event Dispatcher Thread),顾名思义是用来派发事件(根据事件找到对应的事件处理代码)的线程。EDT接收来自 toolkit 线程的事件,并且将这些事件组织成一个队列,EDT的工作内容就是将这个队列中的事件按照顺序派发给相应的事件监听器,并且调用事件监听器中的回调函数,这也意味着,所有的事件处理代码都是在EDT而不是主线程中执行。
上面说到EDT中维护了一个事件的队列,并且它们是按照顺序派发的。由于事件派发是单线程的操作,所以只有等待前面事件监听器的回调函数执行完毕,才能够执行组件更新的操作,以及继续派发后面的事件。这样导致的一个后果就是:当在一个事件监听回调函数中做了耗时的操作,那么,界面会因此停住,并且界面上所有控件失效(不可触发)。
问题解决
也就是说,Java在处理事件的时候是单线程处理的。后一个操做根本没机会影响到前一个操做。
那么,就应该将事件处理任务分到不同的线程中去,所有的事件处理将依赖于同一个类中字段——按键次数,也就是说所有线程同时操做这个按键次数,达到按键次数实时更新的效果。
同时,将单击操做设定延时触发,给按键次数预留更新时间。如果按键次数在延时之后没有改变为两次,那么单击事件执行,如果更新次数了,那么单击事件不执行。
代码
class Panel extends JPanel{
private int clkCnt;//按键次数
public Panel(){
this.setBackground(Color.white);
this.setSize(400, 400);
addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
new Thread(new Runnable() {
@Override
public void run() {
clkCnt = e.getClickCount();
int btnNum = e.getButton();
if(clkCnt == 2){
paint3();
}
else if(clkCnt == 1){
try {
Thread.sleep(200);//延时操做
} catch (InterruptedException interruptedException) {
interruptedException.printStackTrace();
}
if(btnNum == 1 && clkCnt == 1){
paint1( e.getX(), e.getY());
}
else if(btnNum == 3 && clkCnt == 1){
paint2(e.getX(), e.getY());
}
}
}
}).start();
return;
}