分享
 
 
 

Swing之EventQueue简介

王朝java/jsp·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

在Swing的GUI程序中,EventQueue是一个重要的部分,它负责所有AWTEvent(以及其子类)的分发

EventQueue简单工作原理

简单来讲,在EventQueue中有一个dispatchThread,这是一个线程类,负责事件的分发,当Queue中有事件的时候,它会摘取前面的事件并分发给相应的对象进行处理,等处理完之后再获取下一个,当Queue中没有事件的时候,线程等待。

当有事件触发时,系统会调用EventQueue的push方法将AWTEvent添加到EventQueue的最后,同时唤醒dispatchThread。

为什么界面会死掉

所以可以看到,Swing的事件分发实际上是同步的,并且都是在dispatchThread这个线程中处理的,也就是说是一个事件一个事件处理的,如果有某一个事件处理的时间非常长的时侯,其他事件就会被堵塞在那里,从现象上看得话,就是界面会死掉,如果界面被其他窗口覆盖之后再回到前面的时侯,会变成一片灰色,这是因为PaintEvent被堵塞而不能被分发出去的缘故。

为什么Modal Dialog(Frame)弹出的时候界面不会死

当在处理事件的时侯如果弹出一个Modal Dialog,那么处理方法会停在那里并等待Modal Dialog销毁,这个时候按照上面的分析,dispatchThread也会停在那里,这样的话其他事件也不会被分发,那么界面也应该会死掉才对。实际上在等待Modal Dialog销毁的过程中,如果能够保证事件可以顺利地分发出去的话,界面当然就不会死。先来看这个例子。

import javax.swing.JDialog;

import javax.swing.JButton;

import java.awt.event.ActionListener;

import java.awt.event.ActionEvent;

import java.awt.EventQueue;

import java.awt.AWTEvent;

import java.awt.ActiveEvent;

import java.awt.event.PaintEvent;

import java.awt.Component;

import java.awt.MenuComponent;public class TestEvent {

public static void main(String[] args) {

final JDialog dlg = new JDialog();

dlg.setTitle("Test Event Queue");

JButton btn = new JButton("Test");

dlg.getContentPane().add(btn);

btn.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e){

long now = System.currentTimeMillis();

EventQueue theQueue = dlg.getToolkit().getSystemEventQueue();

System.out.println("at least 5000 millis");

while (System.currentTimeMillis() - now < 5000l) {

try {

// This is essentially the body of EventDispatchThread

AWTEvent event = theQueue.getNextEvent();

Object src = event.getSource();

if (event instanceof ActiveEvent) {

((ActiveEvent) event).dispatch();

}

else if (src instanceof Component) { ((Component) src).dispatchEvent(event);

}

else if (src instanceof MenuComponent) {

((MenuComponent) src).dispatchEvent(event);

}

}

catch (Exception ex) {

ex.printStackTrace();

}

}

System.out.println("end");

}

});

dlg.pack();

dlg.show();

}

}

在上面的例子中,当Button的Action被触发,actionPerformed方法执行的时候,会首先帮助EventQueue分发事件,直到最少5秒之后返回,这时可以看到这个事件处理方法至少执行了5秒钟,但是在这个过程中Dialog仍然可以正常工作,只是因为在这5秒之中并非是Sleep,而是在帮助EventQueue分发事件,如果代码改成

Thread.sleep(5000);

的话,界面将会死掉。

public class TestEvent {

public static void main(String[] args) {

final JDialog dlg = new JDialog();

dlg.setTitle("Test Event Queue");

JButton btn = new JButton("Test");

dlg.getContentPane().add(btn);

btn.addActionListener(new ActionListener(){

public void actionPerformed(ActionEvent e){

long now = System.currentTimeMillis();

EventQueue theQueue = dlg.getToolkit().getSystemEventQueue();

System.out.println("at least 5000 millis");

while (System.currentTimeMillis() - now < 5000l) {

try {

// This is essentially the body of EventDispatchThread

AWTEvent event = theQueue.getNextEvent();

Object src = event.getSource();

if (event instanceof ActiveEvent) {

((ActiveEvent) event).dispatch();

}

else if (src instanceof Component) { ((Component) src).dispatchEvent(event);

}

else if (src instanceof MenuComponent) {

((MenuComponent) src).dispatchEvent(event);

}

}

catch (Exception ex) {

ex.printStackTrace();

}

}

System.out.println("end");

}

});

dlg.pack();

dlg.show();

}

}

在上面的例子中,当Button的Action被触发,actionPerformed方法执行的时候,会首先帮助EventQueue分发事件,直到最少5秒之后返回,这时可以看到这个事件处理方法至少执行了5秒钟,但是在这个过程中Dialog仍然可以正常工作,只是因为在这5秒之中并非是Sleep,而是在帮助EventQueue分发事件,如果代码改成

Thread.sleep(5000);

的话,界面将会死掉。

所以在Modal Dialog弹出的时候,实际上只要在show方法中能够实现类似上面的代码,保证事件可以正常的分发(同时截获父窗口的一些事件,过滤掉一些触发Action的事件),那么父窗口的界面就不会死掉。

当事件处理方法很长时间才能做完该怎么办

当事件处理方法需要很长时间才能执行完的话,如果需要保证界面不死的话,还是只能用多线程,虽然上面的方法实现了事件处理的时候界面不死,但是这和一般的事件处理是有不同的,上面的方法实际上在处理的时候什么都没有做,而我们一般需要有自己的操作(比如访问数据库,访问网络,读写操作等需要很长时间才能处理完的工作),不可能做到一边在操作一边处理Event分发,这个时候只有新建一个线程才是正道。

关于EventQueue的一些方法

Window.getToolkit().getSystemEventQueue();

获取系统的EventQueue

SwingUtilities.isEventDispatchThread();

当前线程是否为EventDispatchThread

EventQueue.push(EventQueue queue);

将一个EventQueue作为当前EventQueue的nextQueue,实际上事件是由最后一个EventQueue来分发的

EventQueue.getNextEvent();

获取下一个事件,如果没有,则等到有再返回

EventQueue.postEvent(AWTEvent theEvent);

添加一个Event

不过关于很多EventQueue和EventDispatchThread的方法都被封装在其实现里面,对外不可视,导致不可能对其进行一些修改,有点不爽。另外在EventQueue中的AWTEvent一般都是给最上层对象的,比如最上层的JDialog或者JFrame,然后由JDialog或者JFrame分发给其他的Component,不过我不知道怎么可以从AWTEvent事件找到真正的拥有者,这一点比较郁闷

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有