1、1,第16章 事件驱动程序设计,2,动 因,假如希望编写一个GUI程序,提示用户输入贷款总额、年利率和年数,然后点击Compute Loan按钮获取月偿还额和总偿还额。如何完成这个任务呢?必须使用事件驱动程序设计来编写代码以响应点击按钮事件。,LoanCalculator,Run,3,动 因,假设希望编写程序用动画实现一面旗上升,如图16.1(b-d)所示。如何完成这个任务呢?解决这个问题的方式有好几种。一种有效的方式就是在事件驱动程序设计中使用一个定时器,这也是本章的主题。,4,学习目标,描述事件、事件源和事件类(第16.2节)。 定义监听器类、向源对象注册监听器对象,然后编写代码来处理事件
2、(第16.3节)。 使用内部类定义监听器类(第16.4节)。 使用匿名内部类定义监听器类(第16.5节)。 探究创建和注册监听器的各种编码风格(第16.6节)。 点击按钮从文本域获取输入(第16.7节)。 编写程序处理WindowEvent(第16.8节)。 使用监听器接口适配器简化监听器类的代码(第16.9节)。 编写程序程序处理鼠标事件MouseEvent (第16.10节)。 编写程序程序处理键盘事件KeyEvent(第16.11节)。 使用javax.swing.Timer类控制动画 (第16.12节)。,5,面向过程和事件驱动程序设计,面向过程程序设计按程序顺序执行。 在事件驱动程序
3、设计中,当事件发生时执行代码。,6,重看程序清单 11.7 尝试事件驱动程序设计,这个例子在框架中显示一个按钮。当点击按钮时,在控制台显示一条消息。,HandleEvent,Run,7,事 件,事件(event)可以定义为程序发生了某些事情的信号。 外部用户动作可以触发事件,例如:移动鼠标、点击鼠标和键盘,操作系统也会触发事件,例如:定时器。,8,Event类,9,事件消息,事件对象包含与事件相关的一切属性。可以使用EventObject类中的实例方法getSource()获得事件的源对象。EventObject类的子类处理特定类型的事件,例如:按钮动作、窗口事件、组件事件、鼠标事件以及按键事
4、件。表15.1罗列外部用户动作、源对象和触发的事件类型。,10,可选择的用户动作,用户动作 源对象 触发的事件类型点击按钮 JButton ActionEvent 点击复选框 JCheckBox ItemEvent, ActionEvent 点击单选按钮 JRadioButton ItemEvent, ActionEvent 在文本域按回车键 JTextField ActionEvent 选定一个新项 JComboBox ItemEvent, ActionEvent 窗口打开、关闭等 Window WindowEvent 鼠标按住、释放等 Component MouseEvent 键盘释放、按
5、下等 Component KeyEvent,11,基于委托的模型,12,源组件的内部函数,13,基于委托的模型:举例,JButton jbt = new JButton(“OK“); ActionListener listener = new OKListener(); jbt.addActionListener(listener);,14,选定的事件处理器,事件类(处理器) 监听器接口 监听器方法(Handlers) ActionEvent ActionListener actionPerformed(ActionEvent) ItemEvent ItemListener itemState
6、Changed(ItemEvent) WindowEvent WindowListener windowClosing(WindowEvent)windowOpened(WindowEvent)windowIconified(WindowEvent)windowDeiconified(WindowEvent)windowClosed(WindowEvent)windowActivated(WindowEvent)windowDeactivated(WindowEvent) ContainerEvent ContainerListener componentAdded(ContainerEven
7、t)componentRemoved(ContainerEvent) MouseEvent MouseListener mousePressed(MouseEvent)mouseReleased(MouseEvent) mouseClicked(MouseEvent)mouseExited(MouseEvent) mouseEntered(MouseEvent) KeyEvent KeyListener keyPressed(KeyEvent)keyReleased(KeyEvent) keyTypeed(KeyEvent),15,java.awt.event.ActionEvent,16,举
8、例:ControlCircle第一版 (无监听器),现在,我们可以考虑编写一个程序,使用两个按钮控制一个圆的大小:,ControlCircle1,Run,17,举例: ControlCircle第二版 (带Enlarge的监听器),现在,让我们考虑编写一个使用两个按钮来控制圆的大小的程序。,ControlCircle2,Run,18,内部类监听器,监听器类是特意为创建一个GUI组件(例如:一个按钮)的监听器对象而设计的。监听器类不被其它应用程序所共享。因此,正确的做法是将它作为一个内部类定义在框架类中。,19,内部类,内部类:定义在另一个类内的类。 优点:在一些应用程序中,内部类可以使得程 序
9、更加简洁。 内部类可以引用定义在它嵌套的外部类中的数据和方法,所以,不需要将外部类对象的引用传递给内部类的构造方法。,ShowInnerClass,20,内部类(续),21,内部类(续),内部类可以使程序更加简单和简洁。 一个内部类支持它包含的外部类的工作,它被编译成一个名为OuterClassName$InnerClassName.class的类。例如:内部类InnerClass在类 OuterClass被编译为 OuterClass$InnerClass.class。,22,内部类(续),一个内部类可以声明为public、protected或private,遵从和应用与在类成员上一样的可见
10、性规则。 可以将内部类定义为static。一个static内部类可以使用外部类的名字访问。一个static类是不能访问外部类的非静态成员的。,23,匿名内部类,匿名内部类必须总是扩展自父类或实现接口,但是它不能有显式的extends或者implements子句。 匿名内部类必须实现父类或接口中所有的抽象方法。 匿名内部类总是使用它父类的无参数构造方法来创建一个实例。如果匿名内部类实现了接口,构造方法就是Object()。 匿名内部类被编译为一个名为OuterClassName$n.class的类。例如:如果外部类Test有两个匿名内部类,那么它们就被编译为Test$1.class和Test$2
11、.class。,24,匿名内部类(续),可以使用匿名内部类简化内部类监听器。匿名内部类是没有名字的内部类。它一步完成声明内部类和创建一个该类的实例。一个匿名内部类的声明如下所示:,new SuperClassName/InterfaceName() / Implement or override methods in superclass or interface/ Other methods if necessary ,AnonymousListenerDemo,Run,25,定义监听器类的另一种方式,定义监听器类有很多其它方式。例如:可以改写程序清单16-3,新程序只创建一个监听器,将这个
12、监听器注册给按钮,然后让监听器检测出事件源,即哪个按钮触发了这个事件。,DetectSourceDemo,Run,26,定义监听器类的另一种方式,你也可以定义一个自定制框架类来实现 ActionListener。,FrameAsListenerDemo,Run,27,问题:贷款计算器,LoanCalculator,Run,28,举例:处理窗口事件,TestWindowEvent,Run,目标:演示窗口事件的处理。Window类的任何一个子类都可能触发下面的窗口事件:打开窗口、正在关闭窗口、关闭窗口、激活窗口、变成非活动窗口、最小化窗口和还原窗口。这个程序构建一个框架,监听窗口事件,然后显示一条
13、消息表明当前发生的事件。,29,MouseEvent,30,处理鼠标事件,Java提供了两个处理鼠标事件的监听器接口 MouseListener和MouseMotionListener。 MouseListener接口可以监听像鼠标的按下、释放、输入、退出或点击的动作。 MouseMotionListener接口可以监听像拖动鼠标或移动鼠标的动作。,31,处理鼠标事件,32,举例:使用鼠标在面板上移动消息,目标:编写一个程序,在面板上显示一条消息。可以用鼠标移动这条消息。消息会随着鼠标的拖动而移动,消息总是显示在鼠标的指针处。,MoveMessageDemo,Run,33,keyPressed
14、(KeyEvent e)当按下一个键时被调用。 keyReleased(KeyEvent e) 当松开一个键时被调用。 keyTyped(KeyEvent e) 当按下一个键然后松开该键时被调用。,使用下面KeyListener接口中的处理器来处理键盘事件:,34,KeyEvent类,方法:getKeyChar() methodgetKeyCode() method 键值:Home VK_HOMEEnd VK_ENDPage Up VK_PGUPPage Down VK_PGDN等等.,35,KeyEvent类(续),36,举例:键盘事件 Demo,目标:显示用户输入的字符。用户也可以使用箭头键向上、向下、向左、向右移动字符。,KeyEventDemo,Run,37,Timer类,一些非GUI组件可以触发事件。类javax.swing.Timer就是一个按照预定频率触发ActionEvent事件的源组件。,Timer类可以用于控制动画。例如:可以利用它显示一条移动的消息。,AnimationDemo,Run,38,时钟动画,在第14章,绘制一个显示当前时间的StillClock。但是,时钟显示过后就不再走针了。如何才能使时钟都能显示新的当前时间呢?使时钟走针的关键是每秒都用新的当前时间来重新绘制这个时钟。可以使用定时器控制如何重新绘制时钟。,ClockAnimation,Run,