前言:啊~时光飞逝,又有几天被我浪费了,觉得现在做什么事情都很浪费时间。GF说我认为除了看书了编程都觉得是浪费时间,而在我看来并不因为我在做什么而感到浪费,而是我得到的是“浪费”而已。GF曾问我,如果以后两个人去做生意会怎样,我的回答是我应该不会开心,只因四个字:学无所用……不奋青了还是,继续我未完成的Basic SWT Widget吧。
这次要讲的是关于事件处理的Basic。
Event:
在早先系列文章中我们介绍了Eclipse事件的结构是通过给按钮定义listener(监听对象)来实现一些基本的事件响应的(原文:In the earlier sections of this document, we introduced the Eclipse event structure by definiing listeners for buttons and a few other simple events.)。我们现在就来看一下Eclipse事件结构的详细内容以及为许多不同的简单通用事件创建listener。
为了在SWT中捕获事件,你需要做两件事。第一,你要创建一个对应事件(你想捕获的事件)的listener。每一种类型的listener都有一个接口供你使用(譬如SelectionListener)。甚至有这样一些对应的class(类)提供给你相对应的事件的信息(如SelectionEvent)。如果你建立了一个listener,那么你必须实现你定义的接口中的所有方法(method)。










如果有一个以上的方法(原文If there is more than one method),那么你可以选择创建一个适配器(adapter,比如SelectionAdapter)。一个适配器用空的方法实现了接口(相当于把里面的所有方法都写一边,内容为空),所以你就不用在listener里面定义那些你不需要的方法(比如上例中的widgetDefaultSelected方法)。注意,在SelectionListener中,我们没有给widgetDefaultSelected()方法定义任何内容。也就是说,我们这里可以用一个adapter来代替,而且只需要实现widgetSelected()方法就可以了。







接下来你要做的第二件事就是把这个listener添加到你的widget里去。每个widget都有一个添加listener的方法(比如addSelectionListener())。(这句话不知怎样翻才好:You pass your listener to this method, and you are all set to capture events.不过,不翻出来也对大家理解没什么障碍。)
Button button = new Button(shell, SWT.PUSH);
button.addSelectionListener(listener);
或者,在我们的例子里面,我们可以这样写:
button.addSelectionListener(adapter);
(Soso said:这里的参数是一个Adapter,而不是一个Listener了。)
现在,我们知道怎样给一个widget添加一个listener了,接下来,我们还会涉及到更多的常用的listener,比如按键监听(KeyListener)和鼠标监听(MouseListener),而刚刚我们介绍的就是其中的一个最常用的listener:SelectionListener。
Key Listener:
KeyListener只有两个方法:keyPressed(按下)和keyReleased(释放)。对应的事件对象是KeyEvent。因为有两个方法,所以同样有一个KeyAdapter来实现一个其中的一个方法。
KeyEvent是一个很有趣的按键捕捉事件(原文为:The KeyEvent is the more interesting feature of capturing key events.)。在大多数情况下,如果你用到一个按键的listener,你应该希望知道是哪个键被按下了。KeyEvent的对象有一个叫做character的属性,它存储了最后一次被按下的字符。你可以通过e.character(e是一个KeyEvent类型的参数)来知道这个字符是什么。你还可以通过按键的按键码(key code)和状态掩码(state mask of the key,比如Ctrl和Alt)来知道刚才你按下的键是什么。特殊的键码(key code)包含在SWT库中,比如SWT.CTRL是表示Control键,SWT.CR是表示回车等。状态掩码(state mask)指明了键盘修饰按键的状态。KeyListener最后的例子给你掩饰了状态掩码的使用。
接下来的例子演示了按键监听器中按键的按下和按键的释放方法。我们把一个按键监听器添加到一个文本widget上,每当你在上面输入字符的时候就会产生并触发一个按键事件。在按下按键的方法中,我们检查是否有特殊按键被按下(比如TAB键、回车等等),同时输出它可读的字符(比如按下ESC键我们就输出“ESC”);如果不是特殊按键,那么我们就输出它的字符。在按键释放的方法中,我们检查是否在其他字符按键按下前有control(Ctrl)键先被按下,比如Control-C。这个方法可以用来捕捉ctrl-key并显示在比如一个文本widget中:


























试试运行这段代码,然后看看当你按下不同的按键时,输出的结果是什么。注意,如果我们用KeyAdapter代替KeyListener的话,我们只需要实现keyPressed或者keyReleased中的一个方法就可以了(Soso said:可以把内容放到一个方法中去么)。
Mouse Listeners:
有三种类型的鼠标监听;MouseListener,它能捕获鼠标按下的事件,MouseMoveListener,它能捕获鼠标移动的事件,最后的MouseTrackListener,它能捕获鼠标指针和控件联系的事件(比如鼠标移到控件区域内)。我们马上就会看到这三类listener的使用。从讲事件(Event)开始就很难用程序相对的图例来显示我们要的效果,所以请你运行下我们给出的代码然后由你自己来看下程序的输出究竟是什么,我想这样对你会更有帮助的。
MouseListener:
MouseListener提供三个方法:mouseDown、mouseUp还有mouseDoubleClick。这三个方法的功能就像它们名字所描述的一样。因为这个listener里面包含了三个方法,所以自然而然也有MouseAdapter存在。相对应的,MouseEvent类存储了这个事件的相关信息。
在MouseEvent中,有几个变量对于MouseListener来说是非常特别的,它们是:x,y,stateMask和button。其中button属性返回鼠标按下或者释放的按键号码(Soso said:左键返回1,右键返回2,中键返回3等等)。“x”和“y”属性返回了事件发生时指针的坐标。stateMask属性返回当事件发生时键盘上的modifier键的状态。
接下来的例子中含有两个MouseAdapter。一个适配器实现了mouseUp和mouseDown方法。这个适配器被依附给了两个不同的按钮。我们可以先创建一个适配器,然后再把这个适配器添加到任何需要用它的widget上去。另一个适配器只实现了mouseDoubleClick方法。当你双击一个Lable时,它会负责打开一个新的窗口:



































试着运行下这段代码吧,特别试着按下鼠标,然后移动一下再放开,你将会看到不同的状态输出。
Mouse Move Listener:
MouseMoveListener只有mouseMove这个方法。当指针移动到一个有此事件的widegt上时将会触发mouseMove方法。当然,还会再产生一个MouseEvent。
在本小节末,你将会看到一个综合的例子。
Mouse Track Listener:
它有三个方法:mouseEnter、mouseExit和mouseHover。当指针进入对应事件的widget区域时会调用mouseEnter方法。同样,当指针移出那个widget区域时,就会调用mouseExit方法。最后,当指针在该widget中移动时,会不停调用mouseHover方法。
下面的例子示范了怎样使用MouseMoveListenr和MouseTrackListener。第一个canvas拥有一个MouseMoveListener。当你在顶部的canvas中移动鼠标的同时,背景颜色会随之变化。第二个canvas有一个MouseTrackListener。当你的指针进入该canvas的时候,canvas中会显示一个数字。每当你在这个canvas中移动鼠标的时候,那个数字会不断增加。当鼠标指针离开该canvas区域时,那个数字将会消失,并且当你下次再移入时会从零开始显示。






































注意,为了在listener对控件做修改,你必须把它声明成final的(这里用来记数的count最好定义成static的,因为final不能修改)。运行给出的代码,看看你得到的是什么样的结果。
Text Listeners:
当你是使用Text的widget的时候你会用到一对非常有用的listener,它们分别是ModifyListener和VerifyListener。当文本内容发生改变时,会调用ModifyListener,但是当改变之前,会调用到VerifyListener。它能用来检查新输入的值是不是合法的(Soso said:当然,合法不合法是由你定的)。
ModifyListener:
它只有一个modifyText方法,对应的事件对象是ModifyEvent。和TypedEvent非常相似,它们都有比如time和widget的属性域。
当我们需要监听文本是否被修改时就需要用到ModifyListener了。文本中每一次内容的变化都会调用一次modifyText方法。在本小节的最后你将会看到一个使用的例子。
VerifyListener:
它也只有一个方法:verifyText。对应的事件对象为VerifyEvent。VerifyEvent拥有TypedEvent和KeyedEvent的所有属性:start、end、doit和text。start和end属性指明了将要修改的范围。text变量指出了新的改变了的文本内容。doit这个标志了我们是否做完这次事件。
我们可以用VerifyListener去检查并保证文本域中输入的字符是什么或者不出现什么。下面的例子中,我们检查输入的是否有星号,如果是,那么这个输入事件将会被取消。注意,无论你输入多少次‘*’,都不会看到有星号出现在文本中。






















Focus Listeners:
这小节我们来看FocusListener和TraverseListener。当widegt接受了焦点后,将会产生一个FocusEvent对象。当你使焦点来回移动时,widget会产生一个TraverseEvent对象。下面我们会讲到这两个事件。
FocusListener:
它拥有focusGained和focusLost两个方法。事件产生一个FocusEvent对象。这个事件对象拥有所有TypedEvent对象的属性。小节最后的例子将会涉及更多的细节。
TraverseListener:
它只有一个keyTraversed方法。当widget来回移动焦点,比如按下TAB或者向上和向下箭头按钮时,会调用此方法。
相对应的,会产生一个TraverseEvent对象。其中比较有用的属性时detail和doit。doit属性就和VerifyListener中的作用一样;它设置一个标记,指明事件该不该继续。detail属性指明了这是一个什么样的“来回事件”。你将会在SWT.TRAVERSE_XXXX这样的定义中找到不同的类型。
下面的例子中,你会看到我们比较TraverseEvent中detail的SWT.TRAVERSE_TAB_PREVIOUS。如果有一个向前的tab(Soso said:比如按住Shift 按TAB),那么这次动作就会取消。













































Basic Widgets Project:
项目中包含了所有该文档中用到过的例子,为了使得每个demo都可以在一个main shell中运行,那么每个demo都要被修改,因为Eclipse不允许一个应用程序创建多个dispaly。为了使得每个demo都能运行,display必须要在run方法(下面就介绍)前创建。
public class ButtonDemo {
public static void main(String[] args) {
ButtonDemo bd = new ButtonDemo();
bd.runDemo();}
public void runDemo() {Display display = new Display();
Shell shell = new Shell(display);
这样,你就可以在一个外部的大框架里面运行各个不同的demo了。
综述:
我们这里只对基本的一些widget作了介绍,如果需要更多信息,请访问Eclipse API文档:
http://download.eclipse.org/downloads/documentation/2.0/html/plugins/org.eclipse.platform.doc.isv/reference/api/
我们将会再以后的文档中介绍更多的widget的使用。