事件处理(Java核心技术卷Ⅰ)
来源:互联网 发布:淘宝开店需要哪些软件 编辑:程序博客网 时间:2024/06/08 16:09
- 事件处理
- 1 事件处理基础
- 2 动作
- 3 鼠标事件
- 4 AWT事件继承层次
- 事件处理
7. 事件处理
7.1. 事件处理基础
- 任何支持GUI的操作环境都要不断地监视按键或者点击鼠标这样的事件。操作环境将这些事件报告给正在运行的应用程序。如果有事件产生,每个应用程序将决定如何对它们做出响应。程序员对相关的特定事件编写代码,并将这些代码放置在过程中,通过人们将它们成为事件过程(event process)。
- Java AWT所知的事件范围内,完全可以控制事件从事件源(event source)例如,按钮或滚动条,到事件监听器(event listener)的传递过程,并将任何对象指派给事件监听器。
- 像Java这样的面向对象语言,都将事件的相关信息封装在一个事件对象(event object)中。在Java中,所有的事件对象都最终派生于java.util.EventObject类。
- 不同的事件源可以产生不同类别的事件。例如,按钮可以发送一个AcitonEvent对象,而窗口可以发送WindowEvent对象。
AWT事件处理机制概要:
- 监听器对象是一个实现了特定监听器接口(listener interface)的类的实例。
- 事件源是一个能够注册监听器对象并发送事件对象的对象。
- 当事件发生时,事件源将事件对象传递给所有注册的监听器。
- 监听器对象将利用事件对象中的信息决定如何对事件作出响应。
/* 事件委托模型(event delegation model)实例 *///构造按钮->将按钮添加到面板上->构造监听器->添加动作监听器public class ButtonFrame extends JFrame{ private JPanel buttonPanel; private static final int DEFAULT_WIDTH=300; private static final int DEFAULT_HEIGHT=200; public ButtonFrame(){ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); JButton yellowButton=new JButton("yellow"); JButton redButton=new JButton("red"); JButton blueButton=new JButton("blue"); buttonPanel=new JPanel(); //把按钮添加到面板上 buttonPanel.add(blueButton); buttonPanel.add(redButton); buttonPanel.add(yellowButton); //添加面板到框架里 add(buttonPanel); //构造一个对象,并将对象设置为按钮监听器 ColorAction yellowAction=new ColorAction(Color.YELLOW); ColorAction blueAction=new ColorAction(Color.blue); ColorAction redAction=new ColorAction(Color.red); //为按钮添加监听器 yellowButton.addActionListener(yellowAction); blueButton.addActionListener(blueAction); redButton.addActionListener(redAction); } //内部类。才能访问buttonPanel变量 private class ColorAction implements ActionListener{ private Color backgroundColor; public ColorAction(Color c){ backgroundColor=c; } //实现ActionListener接口,监听器类必须有一个actionPerformed方法 public void actionPerformed(ActionEvent event){ buttonPanel.setBackground(backgroundColor); } }}
创建一个包含方法调用的监听器
假设有一个标签为load的按钮,它的事件处理只包含下面一个方法调用:frame.loadData();
可以使用匿名内部类
loadButton.addActionListener(new ActionListener(){ public void actionPerformed(ActionEvent event){ frame.loadData(); }});
改变观感
默认情况下,Swing程序使用Metal观感,可以采用两种方式改变观感。
- (没有成功)在Java安装的子目录jre/lib下有一个文件swing.properties.在这个文件中,将swing.defaultlaf设置为所希望的观感类名,如
swing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel
。注意,Metal观感位于javax.swing包中。其他的观感包位于com.sun.java包中,并且不是在每个Java实现中都提供。 - 动态地改变观感。这需要调用静态的UIManager.setLookAndFeel方法,并提供所想要的观感类名,然后再调用静态方法SwingUtilities.updateComponentTreeUI刷新全部的组件集。
/* 改变观感 */public class PlafFrame extends JFrame{ private JPanel buttonPanel; public PlafFrame(){ buttonPanel=new JPanel(); //获取所有安装的观感实现 UIManager.LookAndFeelInfo[] infos=UIManager.getInstalledLookAndFeels(); for(UIManager.LookAndFeelInfo info: infos){ makeButton(info.getName(), info.getClassName()); } add(buttonPanel); pack(); } void makeButton(String name,final String plafName){ JButton button=new JButton(name); buttonPanel.add(button); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { //调用静态方法,设置观感 UIManager.setLookAndFeel(plafName); //调用静态方法,刷新全部的组件集。这里需要向方法提供一个组件,并由此找到其他的所有组件 //外部对象的this引用必须将外部类名作为前缀 SwingUtilities.updateComponentTreeUI(PlafFrame.this); pack(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) { e.printStackTrace(); } } }); }}
适配器类
- 当用户试图关闭一个框架窗口时,JFrame对象就是WindowEvent的事件源。如果希望捕获这个事件,就必须有一个合适的监听器对象,将它添加到框架的窗口监听器列表中。
WindowListener listener=...;
frame.addWindowListener(listener);
- 窗口监听器必须是实现WindowListener接口的类的一个对象。在WindowListener接口中包含7个方法。当发生窗口事件时,框架将调用这些方法响应7个不同的事件。
- 在Java中,实现一个接口的任何类都必须实现其中所有的方法。在这里,意味着需要实现7个方法,然而只对名为windowClosing的方法感兴趣。可以在windowClosing方法增加对System.exit(0)的调用,其他6个方法不做任何事情。
- 书写6个没有任何操作的方法代码显然是一种乏味的工作。基于简化的目的,每个含有多个方法的AWT监听器接口都配有一个适配器(adapter)类,这个类实现了接口中所有的方法,但每个方法没有做任何事情。这意味着适配器类自动地满足了Java实现相关监听器接口的技术需求。可以通过扩展适配器类来制定对某些事件的相应动作,而不必实现接口中的每个方法(actionListener接口只有一个方法,因此没必要提供适配器类)。
/* 适配器使用实例 *///最清晰简练的方法frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ ... }});
7.2. 动作
Action接口
通常,激活一个命令可以有多种方式。Swing包提供了一种非常实用的机制来封装命令,并将它们连接到多个事件源,这就是Action接口。一个动作是一个封装下列内容的对象:命令的说明(一个文本字符串和一个可选图标) 和 执行命令所需要的参数。
Action是一个接口,而不是一个类。实现这个接口的所有类都必须实现7个方法。庆幸的是,有一个类实现了除actionPerformed方法之外的所有方法,它就是AbstractAction。这个类存储了所有名/值对,并管理着属性变更监听器。可以直接扩展AbstractAction类,并在扩展类中实现actionPerformed方法。
把动作和击键关联起来
- 要将动作对象添加到击键中,以便让用户敲击键盘命令来执行这项动作。为了将动作与击键关联起来,首先需要生成KeyStroke类对象。这个类封装了对键的说明。要想生成一个KeyStroke对象,不要调用构造器,而是调用KeyStroke类中的静态getKeyStroke方法:
KeyStroke ctrlKey=KeyStroke.getKeyStroke("ctrl B");
- 用户界面中包含许多按钮、菜单、滚动栏以及其他的组件。当用户敲击键盘时,这个动作会被发送给拥有焦点的组件。用户可以使用TAB键在组件之间移动焦点。当按下SPACE键时,就点击了拥有焦点的按钮。示例中不希望将击键发送给拥有焦点的组件。否则,每个按钮都需要知道如何处理CTRL+Y、CTRL+B、CTRL+R这些组合键。这是一个常见的问题,Swing设计者给出了一种很便捷的解决方案。每个JComponent有三个输入映射(input maps),每一个映射的KeyStroke对象都与动作关联。三个输入映射对应三个不同的条件。WHEN_FOCUSED:当这个组件拥有键盘焦点时激活。 WHEN_ANCESTOP_OF_FOCUSED_COMPONENT:当这个组件包含了拥有键盘焦点的组件时激活。WHEN_IN_FOCUSED_WINDOW:当这个组件被包含在一个拥有键盘焦点组件的窗口中时。可以使用getInputMap方法从组件中得到输入映射。
InputMap imap=panel.getInputMap(JComponent.WHEN_FOCUSED);
- InputMap不能直接地将KeyStroke对象映射到Action对象。而是先映射到任意对象上,然后由ActionMap类实现将对象映射到动作上的第2个映射。这样很容易实现来自不同输入映射的按键共享一个动作的目的。
- 习惯上,使用字符串none表示空动作。这样可以轻松地取消一个按键动作。
imap.put(KeyStroke.getKeyStroke("ctrl C"),"none");
总结:用同一个动作相应按钮、菜单项或按键
- 实现一个扩展于AbstractAction类的类。多个相关的动作可以使用同一个类。
- 构造一个动作类的对象。
- 使用动作对象创建按钮或菜单项。构造器将从动作对象中读取标签文本和图标。
- 为了能够通过按键触发动作,必须额外地执行几步操作。首先定位顶层窗口组件,如包含所有其他组件的面板。
- 然后得到顶层组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射。为需要的按键创建一个KeyStroke对象。创建一个描述动作字符串这样的动作键对象。将(按键,动作键)对添加到输入映射中。
- 最后,得到顶层组件的动作映射。将(动作键,动作对象)添加到映射中。
public class ActionFrame extends JFrame{ private JPanel buttonPanel; private static final int DEFAULT_WIDTH=300; private static final int DEFAULT_HEIGHT=200; public ActionFrame(){ setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT); buttonPanel=new JPanel(); Action yellowAction=new ColorAction("Yellow", new ImageIcon("yellow.gif"), Color.YELLOW); Action blueAction=new ColorAction("Blue", new ImageIcon("blue.gif"), Color.BLUE); Action redAction=new ColorAction("Red", new ImageIcon("red.gif"), Color.RED); //用Action对象构造按钮,把动作和按钮关联起来 buttonPanel.add(new JButton(yellowAction)); buttonPanel.add(new JButton(blueAction)); buttonPanel.add(new JButton(redAction)); add(buttonPanel); //得到顶层组件的WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射 InputMap imap=buttonPanel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); //将(按键,动作键)添加到输入映射中 imap.put(KeyStroke.getKeyStroke("ctrl Y"), "panel.yellow"); imap.put(KeyStroke.getKeyStroke("ctrl B"), "panel.bule"); imap.put(KeyStroke.getKeyStroke("ctrl R"), "panel.red"); //得到顶层组件的动作映射 ActionMap amap=buttonPanel.getActionMap(); //将(动作键,动作对象)添加到映射中 amap.put("panel.yellow", yellowAction); amap.put("panel.blue", blueAction); amap.put("panel.red", redAction); } public class ColorAction extends AbstractAction{ public ColorAction(String name,Icon icon,Color c){ //存储命令的名称、图标、简要说明和需要的颜色 putValue(Action.NAME, name); putValue(Action.SMALL_ICON, icon); putValue(Action.SHORT_DESCRIPTION, "Set panel color to "+name.toLowerCase());//显示在工具提示里 putValue("color", c); } public void actionPerformed(ActionEvent arg0) { Color c=(Color) getValue("color"); buttonPanel.setBackground(c); } }}
7.3. 鼠标事件
- 如果只希望用户能够点击按钮或菜单,就不需要显式地处理鼠标事件。鼠标操作将由用户界面中的各种组件内部处理。然而,如果希望用户使用鼠标画图,就需要捕获鼠标移动点击和拖动事件。
- 本部分设计一个简单的图形编辑器应用程序,它允许用户在画布上放置、移动和擦除方块。
- 当用户点击鼠标按钮时,将会调用3个监听器方法:鼠标第一次被按下时调用mousePressed;鼠标被释放时调用mouseReleased;最后调用mouseClicked。如果只对最终的点击事件感兴趣,就可以忽略前两个方法。用MouseEvent类对象作为参数,调用getX和getY方法可以获得鼠标被按下时鼠标指针所在的x和y坐标。要想区分单击、双击和三击,需要使用getClickCount方法。
public class MouseFrame extends JFrame{ public MouseFrame(){ add(new MouseComponent()); pack(); }}class MouseComponent extends JComponent{ private static final int SIDELENGTH=10; private ArrayList<Rectangle2D> squares; private Rectangle2D current; public MouseComponent(){ squares=new ArrayList<>(); current=null; addMouseListener(new MouseHandler()); addMouseMotionListener(new MouseMotionHandler()); } public void paintComponent(Graphics g){ Graphics2D g2=(Graphics2D)g; for(Rectangle2D r:squares){ g2.draw(r); } } public Rectangle2D find(Point2D p){ for(Rectangle2D r:squares){ if (r.contains(p)) return r; } return null; } public void add(Point2D p){ double x=p.getX(); double y=p.getY(); current=new Rectangle2D.Double(x-SIDELENGTH/2, y-SIDELENGTH/2, SIDELENGTH, SIDELENGTH); squares.add(current); repaint(); } public void remove(Rectangle2D r){ if(r==null) return; if(r==current) current=null; squares.remove(r); repaint(); } //两个独立的接口MouseListener和MouseMotionListener,有利于提高效率。 //当用户移动鼠标时,只关心鼠标点击的监听器就不会被多余的鼠标移动所困扰。 private class MouseHandler extends MouseAdapter{ public void mousePressed(MouseEvent e){ //getPoint方法返回事件源组件左上角的x y坐标 //判断该处是否已经绘制图形 current=find(e.getPoint()); if (current==null) add(e.getPoint()); } public void mouseClicked(MouseEvent e){ current=find(e.getPoint()); //双击鼠标,擦除方块 if(current!=null && e.getClickCount()>=2) remove(current); } } private class MouseMotionHandler implements MouseMotionListener{ //移动鼠标的同时按下鼠标,调用mouseMoved public void mouseMoved(MouseEvent e) { //光标在一个小方块之上时变成另外一种形状(十字) if(find(e.getPoint())==null) setCursor(Cursor.getDefaultCursor());//普通鼠标图标 else setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));//十字形图标 } //更新光标位置 public void mouseDragged(MouseEvent e) { if (current!=null) { int x=e.getX(); int y=e.getY(); //设置形状坐标和大小 current.setFrame(x-SIDELENGTH/2, y-SIDELENGTH/2, SIDELENGTH, SIDELENGTH); repaint(); } } }}
7.4. AWT事件继承层次
Java事件处理采用的是面向对象方法,所有的时间都是由java.util包中EventObject类扩展而来。EventObject类有一个子类AWTEvent,它是所有AWT事件类的父类。
语义事件和低级事件
AWT将事件分成低级(low-level)时间和语义(semantic)事件。语义事件是表示用户动作的事件,如点击按钮,因此,ActionEvent是一种语义事件。低级事件是形成那些事件的事件。在点击按钮时,包含了按下鼠标、连续移动鼠标、抬起鼠标事件。调节滚动条是一种语义事件,但拖动鼠标是低级事件。
下面是java.awt.event包中最常用的语义事件类:
- ActionEvent(对应按钮点击、菜单选择、选择列表项或在文本框中ENTER)
- AdjustmentEvent(调节滚动条)
- ItemEvent(从复选框或列表框中选择一项)
常用的低级事件类是:
- KeyEvent(一个键被按下或释放)
- MouseEvent(鼠标键被按下、释放、移动或拖动)
- MouseWheelEvent(鼠标滚轮被转动)
- FocusEvent(某个组件获得焦点或失去焦点)
- WindowEvent(窗口状态被改变)
AWT监听器接口、事件和事件源:
-getActionCommand
-getModifiers AbstractButton
JComboBox
JTextField
Timer AdjustmentListener adjustmentValueChanged AdjustmentEvent
-getAdjustable
-getAdjustmentType
-getValue JScrollbar ItemListener itemStateChanged ItemEvent
-getItem
-getItemSelectable
-getStateChange AbstractButton
JComboBox FocusListener focusGained
focusLost FocusEvent
-isTemporary Component KeyListener keyPressed
keyReleased
keyTyped KeyEvent
-getKeyChar
-getKeyCode
-getKeyModifiersText
-getKeyText
-isActionKey Component MouseListener mousePressed
mouseReleased
mouseEntered
mouseExited
mouseClicked MouseEvent
-getClickCount
-getX
-getY
-getPoint
-transaltePoint Component MouseMotionListener mouseDragged
mouseMoved MouseEvent Component MouseWheelListener mouseWheelMoved MouseWheelEvent
-getWheelRotation
-getScrollAmount Component WindowListener windowClosing
windowOpened
windowIconified
windowDeiconified
windowClosed
windowActivated
windowDeactiovated WindowEvent
-getWindow Window WindowFocusListener windowGainedFocus
windowLostFocus WindowEvent
-getOppositeWindow Window WindowStateListener windowStateChanged WindowEvent
-getOldState
-getNewState Window
- 事件处理(Java核心技术卷Ⅰ)
- java核心技术卷 之事件处理基础
- Java核心技术:卷1笔记[6] 事件处理
- java核心技术卷 之处理按钮点击事件
- #Java 核心技术卷一阅读笔记# 第十一章 事件处理
- Java核心技术(事件处理)
- java核心技术 事件处理
- 继承(Java核心技术卷Ⅰ)
- 图形程序设计(Java核心技术卷Ⅰ)
- 集合(Java核心技术卷Ⅰ)
- Java 核心技术卷Ⅰ笔记
- java核心技术笔记 事件处理
- Java程序设计概述及环境(Java核心技术卷Ⅰ)
- Java基本程序设计结构(Java核心技术卷Ⅰ)
- 对象与类(Java核心技术卷Ⅰ)
- 接口与内部类(Java核心技术卷Ⅰ)
- 2015 7 3 java核心技术卷一 7-10章 图形,事件处理,Swing组件和应用程序部署
- 读《Java核心技术:卷Ⅰ基础知识》有感
- (OK) pthread—epoll-loops-on-disconnection-of-a-client—server
- java虚拟机 jvm 出入java栈 栈空间内存分配
- json-lib.jar开发包及依赖包的下载地址
- 使用Hierarchy Viewer分析优化布局性能
- (OK) Linux epoll模型—socket epoll server client chat—pthread
- 事件处理(Java核心技术卷Ⅰ)
- IOS7 隐藏显示状态栏 (电池栏)
- Swift笔记 label 显示富文本或HTML
- 做一个快乐的程序员
- 山东省第一届ACM习题
- JDBC-数据库的连接和简单操作
- javascript 中的面向对像(一)
- 扣丁学堂笔记第18天HttpURLConnection与HttpClient
- JDBC-数据库事务回滚