Java程序设计语言--------事件处理计算机科学与技术学院GUI组件概述awt:Abstr actWindowToolkit——抽象窗口工具集从Java1.0中出现。awt处理用户界面元素的方法是把这些元素的创建和 行为委托给每个目标平台(如windows,Linux)上的本地GUI处理。每个平台提供的图形界面元素都不一样。不同平台上的aw t库存在不同Bug。awt的事件处理模型在Java1.1版进行了大的改动后,到目前的版本基本没变。swing:Java2. 0中出现。Swing组件全部是由纯Java编写的,用户界面元素都绘制在空白窗口上,绘制和行为都由swing类自己完成。各平台之间 唯一不同的就是最外层窗口的创建。总结:尽管awt的用户界面组件仍然可以用,但是建议最好不要使用。现在编写Java图形界面程序 ,使用swing组件+awt事件处理模型。事件处理概述图形用户界面编程中,必须使用事件处理。支持GUI的操作环境会不断监 视事件,并把事件报告给正在运行的程序。这是多任务的需要。每个程序决定如何相应这些事件。Java的事件处理采用的是事件监听器方式 。事件监听器是一个实现了监听器接口的对象。事件源(如按钮组件)是一个能够注册监听器并为它们发送事件的对象。每个事件源拥有自己 的事件监听器,可以有多个。当事件源产生了一个事件后,事件源就会给所有监听器对象发送通知,即调用事件监听器对象的相应方法。事件的 信息被封装在一个对象中,不同事件源能够产生不同种类的事件。编程人员要做的就是编写事件监听器类,创建一个事件监听器对象,并注册到相 应的事件源。事件监听器编写编写事件处理程序的步骤如下:编写监听器类;在监听器类中实现接口中需要的方法;方法中可以使用A ctionEvent对象判断事件;创建一个事件监听器对象;将该对象添加到事件源。见Example1.javaimport java.awt.;importjava.awt.event.;importjavax.swing.;public classExample1extendsJFrame{publicExample1(){ se tSize(320,200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); ContainercontentPane=getContentPane(); JButtontestButton= newJButton("Test"); testButton.addActionListener(newMyListener 1()); contentPane.setLayout(newBorderLayout()); contentPane.ad d(testButton,BorderLayout.SOUTH);}}classMyListener1imp lementsActionListener{publicvoidactionPerformed(ActionEv ente){ JOptionPane.showMessageDialog(null, "ActionComma nd:"+e.getActionCommand());}}事件源与监听器的关系一个事件源可以对应多个监听器。 一个监听器可以对应多个事件源。classMyListener2implementsActionListener{ publicvoidactionPerformed(ActionEvente){ Stringaction Command=e.getActionCommand(); ColorbkColor=null; if(action Command.equals("Red"))bkColor=newColor(255,0,0); elseif(acti onCommand.equals("Green"))bkColor=newColor(0,255,0); elseif( actionCommand.equals("Blue"))bkColor=Color.blue; getContentPan e().setBackground(bkColor);}}见Example2.javaclassMyListe ner1implementsActionListener{publicvoidactionPerformed( ActionEvente){ JOptionPane.showMessageDialog(null, "Acti onCommand:"+e.getActionCommand());}}myListener2myListen er1事件监听器类的各种写法监听器类的声明:将事件监听器作为单独的类。将事件监听器作为组件的内部类。直接使用已有类(通常 是包含事件源的组件)作为事件监听器。使用匿名内部类。监听器类的实现:一个监听器类实现多个组件的监听器对象。通过类中的实例字 段来区分不同的监听器对象。一个监听器对象作为多个组件的监听器。在事件的响应方法中通过事件源区分不同的事件。publiccl assExample1extendsJFrame implementsActionListener{publi cvoidactionPerformed(ActionEvente){…}}见Example3.javaredButt on.addActionListener(newActionListener() //匿名内部类监听器{ publ icvoidactionPerformed(ActionEvente) { …… }});改变观感改变 观感使用两个静态方法:UIManager.setLookAndFeel(plaf)设置要使用的观感参数plaf为观感的名字,实 际为一个类名,可以为以下字符串:javax.swing.plaf.metal.MetalLookAndFeelcom.sun. java.swing.plaf.windows.WindowsLookAndFeelcom.sun.java.swing.pla f.motif.MotifLookAndFeelSwingUtilities.updateComponentTreeUI(pan el)刷新要改变的组件参数panel给出面板中的一个组件即可刷新整个面板。见Example4.javatButton.add ActionListener(newActionListener(){publicvoidactionPerfo rmed(ActionEventaEvent){ try{ UIManager.setLookAnd Feel(aPlafName); SwingUtilities.updateComponentTreeUI(Exam ple4.this); }catch(Exceptione){ e.printStackTrace(); }; }});窗口事件ActionListener接口非常简单,用于按钮事件处理。相应的,WindowListene r接口用于窗口事件处理。见Example5.javapublicclassExample5extendsJFrame {publicExample5(){ … setDefaultCloseOperation(JFram e.DO_NOTHING_ON_CLOSE); addWindowListener(newMyWindowListener() );}privateclassMyWindowListenerimplementsWindow Listener{ publicvoidwindowOpened(WindowEvente){} publi cvoidwindowClosing(WindowEvente) {intresult=JOptionPa ne.showConfirmDialog(……); if(result==JOptionPane.OK_OPT ION)System.exit(0); } publicvoidwindowClosed(WindowEvente){} publicvoidwindowIconified(WindowEvente){} publicvoidwindo wDeiconified(WindowEvente){} publicvoidwindowActivated(Window Evente){} publicvoidwindowDeactivated(WindowEvente){} }}添加窗口事件监听器窗口事件监听器实现WindowListener接口要处理的窗口事件适配器类问题:仅仅需要处理关 闭窗口事件,但却要写另外六个空方法。解决方法:使用适配器类。适配器类是一个实现了某个接口,但其中所有方法都为空的类。每个具有 不止一个方法的监听器接口都对应有一个适配器类。编写监听器类时只需从适配器类派生一个子类即可。见Example6.javapr ivateclassMyWindowListenerextendsWindowAdapter{ publicvoid windowClosing(WindowEvente) {intresult=JOptionPane.sho wConfirmDialog(……); if(result==JOptionPane.OK_OPTION)Sy stem.exit(0); }}由实现接口改为继承自适配器类,从而不用再写另外六个无用方法。见Example6.ja vaaddWindowListener(newWindowAdapter(){ publicvoidwindo wClosing(WindowEvente) {intresult=JOptionPane.showConfi rmDialog(……); if(result==JOptionPane.OK_OPTION)System.e xit(0); }});也可写成匿名内部类WindowListenerWindowAdapterMyWin dowAdapterJava事件概述Java中所有事件都从java.util.EventObject类继承而来。两个包中定义 了事件:java.awt.event:awt的事件、监听器及适配器定义。java.swing.event:专门用于swing组 件的附加事件。如何查找组件能够发出哪些事件:查找组件能够添加哪些事件监听器(addListener)根据方法参数查找相 应的接口,即可知道具体的事件含义java.awt.event包中定义了11个监听器接口、7个适配器类java.awt.even t包中的11个监听器接口ActionListener WindowListenerAdjustmentListener Com ponentListenerContainerListener FocusListenerItemListener KeyLi stenerMouseListener MouseMotionListenerTextListenerjava.awt.ev ent包中的7个适配器类WindowAdapter ComponenAdapterContainerAdapter Focus AdapterKeyAdapter MouseAdapterMouseMotionAdapterawt事件虽然接口和类比较 多,但原理都一样。定义实现监听器接口的监听器类,在相应方法中添加事件处理代码。创建一个监听器类的对象,添加到事件源的监听器列表 中。awt事件分为语义事件和低级事件。语义事件是有明确意义的事件。ActionEvent:按钮按下、菜单选择、选择列表项、文 本域中按回车AdjustmentEvent:调整滚动条ItemEvent:从一组选择框或列表项中选择一个TextEvent: 文本域或文本框中内容发生变化低级事件是较小的基本事件。ComponentEvent:组件被显示、隐藏、改变位置、改变大小Ke yEvent:键盘上的一个键被按下或者释放MouseEvent:鼠标按键的按下和释放,鼠标移动或拖动FocusEvent:组件 得到焦点或失去焦点WindowEvent:窗口被显示、隐藏、关闭、激活、图标化、还原ContainerEvent:容器中加入或 移除一个组件键盘事件键盘事件监听器KeyListener有三个方法:voidkeyPressed(KeyEvente): 对应于按键按下。voidkeyReleased(KeyEvente):对应于按键弹起。voidkeyTyped(KeyE vente):结合上述两个事件,直接报告按了按键,用于不须区分按下和弹起的情况。键盘事件类KeyEvent的主要方法有:ch argetKeyChar():得到按键对应的字符。intgetKeyCode():得到按键对应的扫描码。staticSt ringgetKeyText(intkeyCode):将扫描码转化为说明字符串。如何处理键盘事件:(示例见KeyExampl e.java)用按键的扫描码可以准确的确定按键。KeyEvent类中定义了所有按键的扫描码常量,如:VK_A,VK_SHIFT ,VK_F10,VK_ENTER,VK_LEFT,VK_NUMPAD1。判断SHIFT,CONTROL,ALT的状态可以 使用KeyEvent的isShiftDown,isControlDown,isAltDown方法。JPanel的键盘事件键 盘事件只在事件源组件获得输入焦点时触发。缺省情况下,JPanel因无法得到输入焦点,所以不能得到键盘事件。解决方法是:覆盖其i sFocusTraversable方法,使其返回true,从而使JPanel可以得到输入焦点,接收键盘事件。主意,窗口中不能同时 出现其他能够获得输入焦点的组件。见KeyExample1.javaJPaneltestPanel=newKeyPane l();//若将上面的KeyPanel()改为JPanel(),则无法接收键盘事件testPanel.addKeyListe ner(…)classKeyPanelextendsJPanel{ publicbooleanisFocusTra versable() { returntrue; }}销毁键盘事件问题:设计一个JTextField,用于输入电话 号码。要求只能输入数字,不能输入其他字符。解决方法:用KeyEvent的consume()方法销毁键盘事件,使其不能传递到组件 。销毁键盘事件要在键盘事件监听器的keyTyped方法中进行。见KeyExample2.javanumField.addK eyListener(newKeyAdapter(){ publicvoidkeyTyped(KeyEvente) { charch=e.getKeyChar(); if(ch<''0''||ch>''9'')e.consum e(); }});鼠标事件鼠标事件监听器MouseListener有五个方法:voidmousePressed(Mou seEvente):对应于鼠标按键按下事件voidmouseReleased(MouseEvente):对应于鼠标按键释 放事件voidmouseClicked(MouseEvente):结合上述两个方法,直接报告鼠标点击事件,用于不须区分按下 或释放的情况。voidmouseEntered(MouseEvente):对应于鼠标移动进入组件voidmouseEx ited(MouseEvente):对应于鼠标移出组件鼠标事件类MouseEvent的常用方法有:intgetButto n():得到发生动作的按键(BUTTON1,BUTTON2,BUTTON3)。intgetClickCount():得到点 击次数,主要用于双击事件。PointgetPoint()(或intgetX(),intgetY()):得到事件发生时鼠标的 相对位置。intgetModifiers():得到鼠标按键和键盘组合键的状态。鼠标与键盘组合使用:(见MouseExamp le.java)在鼠标事件中判断SHIFT,CONTROL,ALT的状态可以使用MouseEvent的isShiftDown, isControlDown,isAltDown方法。一般鼠标事件的处理功能:执行以下操作,程序就退出:按住Shift键在 testButton左边50像素之内双击鼠标左键说明因为是双击事件,所以最后由鼠标点击事件触发,对应于mouseClicked 方法。见MouseExample.javapublicvoidmouseClicked(MouseEvente){ if(e.getButton()==MouseEvent.BUTTON1&& //鼠标左键 e.getClickCount( )==2&& //双击 e.getX()<50&& //在testButton左边50像素 e.isShiftD own()) //按下键盘Shift键 { System.exit(0); }}多个鼠标按键状态的判断功能:执行 以下操作,程序就退出:按住鼠标左键和右键按住键盘Ctrl键将鼠标从testButton移出说明因为事件由鼠标移出触发,所 以对应于mouseExited方法。见MouseExample.javapublicvoidmouseExited(Mou seEvente) //鼠标移出testButton事件{ intmodifiers=e.getModifiers (); //得到鼠标当前状态 intexitMask=MouseEvent.BUTTON3_MASK| //鼠标右键 MouseEvent.CTRL_MASK| //按下键盘Ctrl键 MouseEvent.BUTTON1_MASK; / /鼠标左键 if((modifiers&exitMask)==exitMask) { System.exit(0); }}设置鼠标图标功能:当鼠标移动到testButton上时,变为手形。当鼠标移出testButton后,变为箭头形状。 说明:有两种方法可以完成此功能1、直接调用testButton的setCursor方法设置按钮的鼠标图标。2、需要同时在mo useEntered和mouseExited方法中设置窗口的鼠标图标。3、鼠标的形状见Cursor类的文档。方法2、见Mous eExample.javapublicvoidmouseEntered(MouseEvente){ setCursor( Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));}publicvoidmo useExited(MouseEvente){ setCursor(Cursor.getPredefinedCursor(Cu rsor.DEFAULT_CURSOR));}方法1、见MouseExample.javatestButton.setCur sor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));鼠标移动事件鼠标移动事 件监听器MouseMotionListener有两个方法:voidmouseDragged(MouseEvente):对应于 鼠标的拖动,即鼠标在组件上按下,然后移动位置,可以移动出组件之外。voidmouseMoved(MouseEvente):对 应于鼠标的移动,即没有按钮按下,且鼠标只在组件内部移动位置。鼠标移动事件监听器的入口参数与MouseListener相同,也是M ouseEvent类型。鼠标移动事件的处理:mouseDragged事件通常用于组件内部的某些物体形状、位置等改变。mous eMoved事件通常用于组件内部鼠标光标的改变。在鼠标移动事件监听器中,可以使用MouseEvent的各种方法来获得鼠标的当前状态。(见MouseMoveExample.java)定时器事件定时器可以实现每隔一段时间触发一个事件:实现定时器使用javax.swing.Timer类。同时,还有一个java.util.Timer类,注意类名的区分。Timer类的主要方法:Timer(intdelay,ActionListenerlistener):构造函数voidstart():启动定时器voidstop():停止定时器见TimerExample.javaTimert=newTimer(1000,newActionListener() { publicvoidactionPerformed(ActionEvente) { infoLabel.setText(String.valueOf(counter++)); } });t.start();事件处理总结事件处理机制:事件源自动调用其事件监听器列表中的对象的方法。Java事件处理编程创建事件监听器类,在相应的方法中编写事件处理代码;声明一个事件监听器对象;将事件监听器对象添加到事件源的监听器列表。主要事件包括以下类型:组件产生的语义事件:按钮事件、窗口事件、……键盘事件鼠标事件:鼠标点击事件、鼠标移动事件定时器事件 |
|