Swing之EventQueue简介 queueevent

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

EventQueue简单工作原理

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

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

为什么界面会死掉

3)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(); } //Event no dispatch method

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事件找到真正的拥有者,这一点比较郁闷

public class EventQueue extends Object

EventQueue 是一个与平台无关的类,它将来自于底层同位体类和受信任的应用程序类的事件列入队列。

它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue 调用 dispatchEvent(AWTEvent) 方法来指派这些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的事件(注意,正在发送到 EventQueue 中的事件可以被合并)的唯一要求是:

按顺序指派。 也就是说,不允许同时从该队列中指派多个事件。 指派顺序与它们排队的顺序相同。 也就是说,如果 AWTEvent A 比 AWTEvent B 先排入到 EventQueue 中,那么事件 B 不能在事件 A 之前被指派。

一些浏览器将不同代码基中的 applet 分成独立的上下文,并在这些上下文之间建立一道道墙。在这样的场景中,每个上下文将会有一个 EventQueue。其他浏览器将所有的 applet 放入到同一个上下文中,这意味着所有 applet 只有一个全局 EventQueue。该行为是与实现有关的。有关更多信息,请参照浏览器的文档。

有关事件指派机制的线程问题,请参阅 AWT 线程问题。 从以下版本开始: 1.1



构造方法摘要

EventQueue()

方法摘要

protected voiddispatchEvent(AWTEvent event)

指派一个事件。指派事件的方式取决于事件的类型和事件的源对象的类型:

事件类型源类型指派

ActiveEvent所有event.dispatch()

其他Componentsource.dispatchEvent(AWTEvent)

其他MenuComponentsource.dispatchEvent(AWTEvent)

其他其他无动作(忽略)

参数: event - java.awt.AWTEvent 的实例或者是它的子类 抛出:NullPointerException - 如果 event 为 null 从以下版本开始: 1.2

static AWTEventgetCurrentEvent()

返回当前正在被 EventQueue(它与正在调用的线程相关)指派的事件。只有某个方法需要访问事件时,但是并没有被设计为可以将事件作为参数来接受,则此方法很有用。注意,该方法应该只从应用程序的事件指派线程进行调用。如果从另一个线程调用该方法,则返回 null。 返回: 当前正被指派的事件;如果调用该方法的线程不是事件指派线程,则返回 null 从以下版本开始:

static longgetMostRecentEventTime() 返回最近事件的时间戳(如果有),该事件从 EventQueue(它与正在调用的线程相关)进行指派。

如果具有时间戳的事件目前正被指派,则返回它的时间戳。如果没有事件被指派,则返回 EventQueue 的初始化时间。在 JDK 的当前版本中,只有 InputEvent、 ActionEvent 和 InvocationEvent 有时间戳;但是,JDK 的未来版本可能将时间戳添加到其他事件类型中。注意,该方法只应该从应用程序事件的指派线程进行调用。如果从另一个线程调用该方法,则返回当前系统的时间(由 System.currentTimeMillis() 报告)。

返回: 最后一次 InputEvent 的时间戳,要指派的 ActionEvent 或 InvocationEvent,如果在不同于事件指派线程的线程上调用该方法,则返回 System.currentTimeMillis()

从以下版本开始: 1.4

另请参见:InputEvent.getWhen(), ActionEvent.getWhen(), InvocationEvent.getWhen()

AWTEventgetNextEvent() 从 EventQueue 中移除一个事件,并返回该事件。在另一个线程发送事件之前该方法被阻塞。

返回: 下一个 AWTEvent 抛出:InterruptedException - 如果任何线程中断了此线程

static voidinvokeAndWait(Runnable runnable) throws InterruptedException, InvocationTargetException

导致 runnable 的 run 方法在 the system EventQueue 的指派线程中被调用。在所有挂起事件被处理后才发生。在这发生之前调用被阻塞。如果从事件指派线程进行调用,则该方法将抛出 Error。

参数: runnable - Runnable 对象,其 run 方法应该在 EventQueue 上同步执行

抛出:InterruptedException - 如果任何线程中断了该线程

InvocationTargetException - 如果运行 runnable 时抛出一个 throwable

从以下版本开始: 1.2

static voidinvokeLater(Runnable runnable) 导致 runnable 的 run 方法在 the system EventQueue 的指派线程中被调用。 参数: runnable - Runnable 对象,其 run 方法应该在 EventQueue 上同步执行 从以下

版本开始:1.2 另请参见:invokeAndWait(java.lang.Runnable) ~

static booleanisDispatchThread() 如果正在调用的线程是当前 AWT EventQueue 的指派线程,则返回 true。使用此调用确保给定的任务正在当前 AWT EventDispatchThread 上执行(或没有执行)。 返回: 如果给定的任务正在当前 AWT EventQueue 的指派线程上运行,则返回 true。 从以下版本开始: 1.2

AWTEventpeekEvent()

返回 EventQueue 上的第一个事件,而不移除它。

AWTEventpeekEvent(int id) 返回指定 id(如果有) 的第一个事件。

参数: id - 所需事件类型的 id 返回: 指定 id 的第一个事件,如果没有这样的事件,则返回 null

protected voidpop() 停止使用此 EventQueue 指派事件。

任何挂起的事件都被传输到以前的 EventQueue 以备处理。

警告:为了避免死锁,不要在子类中将该方法声明为 synchronized。

抛出:EmptyStackException - 如果以前没有对该 EventQueue 执行 push 操作

从以下版本开始: 1.2

另请参见:push(java.awt.EventQueue)

voidpostEvent(AWTEvent theEvent) 将一个 1.1 样式的事件发送到 EventQueue 中。如果在队列中存在具有相同 ID 和事件源的事件,则调用源 Component 的 coalesceEvents 方法。

参数: theEvent - java.awt.AWTEvent 的实例,或者是它的子类

抛出:NullPointerException - 如果 theEvent 为 null

voidpush(EventQueue newEventQueue) 用指定的事件队列替换现有的 EventQueue。任何挂起的事件都被传输到 EventQueue 以备处理。

参数: newEventQueue - 要使用的 EventQueue(或其子类的)的实例

抛出:NullPointerException - 如果 newEventQueue 为 null

从以下版本开始: 1.2 另请参见:pop()

从类 java.lang.Object 继承的方法

clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

  

爱华网本文地址 » http://www.413yy.cn/a/25101013/151251.html

更多阅读

思科模拟器:2 入门之界面简介

思科模拟器:[2]入门之界面简介——简介思科模拟器是网络工程师经常使用的网络实验模拟软件,它可以很快捷的模拟网络中的各种设备(交换机、路由器、台式电脑、笔记本电脑、服务器、网络云),搭建各种网络环境,模拟网络拓扑结构等。下面天

黑石深渊怎么去熔火之心 艾萨拉之眼地图怎么去

黑石深渊怎么去熔火之心——简介作为一个wow的资深爱好者和一个不算老鸟的80后小玩家来说,想找到60年代的副本我感觉简直是太难了,曾经还需要做各种任务,拿到入场钥匙才能进门等等,感觉根本打不进去啊。。不过随着变简单了之后,一些难的

新车除异味之法 新车异味怎么去除

新车除异味之法——简介 很多有车一族往往会在刚买车后,感到苦恼,因为车就像房一样,新车有一种异味.怎样把这样的气味去除呢,我找到也总结出一些经验,希望跟大家分享一下.据有关部门曾经专门进行过一个针对汽车内部环境污染情况的

DNF异界全攻略 ---之蠕动之城( dnf异界全攻略

DNF异界全攻略 ---之蠕动之城(——简介DNF异界全攻略之----蠕动之城(王者级抗魔底线230)DNF异界全攻略 ---之蠕动之城(——工具/原料DNF 账号联网DNF异界全攻略 ---之蠕动之城(——方法/步骤DNF异界全攻略 ---之蠕动之城( 1、一:

治疗抑郁症之饮食疗法 抑郁症的饮食疗法

治疗抑郁症之饮食疗法——简介抑郁症在西方被称为“蓝色隐忧”。据世界卫生组织统计分析,全球抑郁症的发生率约为3.1%,而在发达国家发病率更是接近6%。2002年全球重症抑郁病患者已有8900多万人,预计到2005年,抑郁症发病率在发达国家将上

声明:《Swing之EventQueue简介 queueevent》为网友星空似海洋分享!如侵犯到您的合法权益请联系我们删除