欢迎光临
我们一直在努力

Swing之EventQueue简介-JSP教程,Java技巧及代码

建站超值云服务器,限时71元/月

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

赞(0)
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com 特别注意:本站所有转载文章言论不代表本站观点! 本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。未经允许不得转载:IDC资讯中心 » Swing之EventQueue简介-JSP教程,Java技巧及代码
分享到: 更多 (0)