1、旧AWT事件模型
该事件模型以基于授权代替基于继承并改善了旧事件模型。建议使用新的事件模型代替旧事件模型。事件模型是向后兼容的。
1.1 覆盖事件处理方法
使用旧AWT事件模型处理事件是相当简单的:当事件在构件中出现时,构件中的一个方法被调用。如果你想让构件响应事件,你可以简单地覆盖适当的方法。
常覆盖的构件方法
void setSize(int w,int h) //构件已经被调整大小
void setBouds(intx ,int y, int w, int h) //构件被调整大小并/或移动
void paint(Graphics g) //构件需要被画出
void update (Graphics g) //默认情况下,清楚并重绘
void addNotify() //创建同位体
不常覆盖的构件方法
void setLocation(intx ,int y) //将构件移动到x,y位置
void layout() //构件需要被布置
void validate() //如果非法,则布置构件
通常在增加改进之前,调用超类版本的方法对事件执行处理:
public addNotify(){
super.addNotify();
}
1.2 被传播的事件
上面在发生事件的构件中被处理,仅仅涉及到它们所发生的构件。
另一类事件被称为被传播的事件,无论被传播的事件t么时候发生在构件中,构件的 handleEvent (Event)方法被调用。构件的 handleEvent (Event)方法可以选择是向其容器传播事件还是完全在其本身中处理事件。
注意被传播的事件和上面列出的事件之间的差别。
- 被传播的事件一般是通过构件的handleEvent方法来处理的,一个java.awt.Event被传递给这个方法。
- 被传播的事件可以传播给构件的容器﹔假如这样的话,容器的 handleEvent 方法被调用,并且java . awt .Event被向前传递。
- 因为被传播的事件涉及一个 java.awt.Event,所以它们一般是引用AWT事件。在本章的剩余部分,我们仅仅讨论和这种事件相关联的部分。
1.3 事件类型的常量
每个java . awt.Event 都有一个对应的id域,该id域的值指示已经发生的事件的类型。通常,构件的 handleEvent方法做的第一件事是检测事件的id域来判断事件的类型。
public voolean handleEvent(Event event) {
if(event.id == Event.MOUSE_DOWN){
return true;
}
}
java.awt.Event类型常数:
static int ACTION_EVENT //已过时。 此事件表示用户希望执行某些操作。
static int ALT_MASK //已过时。 此标志表示事件发生时Alt键已关闭。
Object arg// 已过时。 事件的任意参数。
static int BACK_SPACE// 已过时。 BackSpace键。
static int CAPS_LOCK //已过时。 Caps Lock键,非ASCII动作键。
int clickCount //已过时。 对于 MOUSE_DOWN事件,此字段指示连续点击次数。
static int CTRL_MASK //已过时。 此标志表示事件发生时Control键已关闭。
static int DELETE //已过时。 删除键。
static int DOWN //已过时。 向下箭头键,非ASCII动作键。
static int END //已过时。 结束键,非ASCII动作键。
static int ENTER// 已过时。 Enter键。
static int ESCAPE// 已过时。 逃生键。
Event evt// 已过时。 下一个活动。
static int F1 //已过时。 F1功能键,非ASCII动作键。
static int F10// 已过时。 F10功能键,非ASCII动作键。
static int F11 //已过时。 F11功能键,非ASCII动作键。
static int F12// 已过时。 F12功能键,非ASCII动作键。
static int F2 //已过时。 F2功能键,非ASCII动作键。
static int F3// 已过时。 F3功能键,非ASCII动作键。
static int F4 //已过时。 F4功能键,非ASCII动作键。
static int F5 //已过时。 F5功能键,非ASCII动作键。
static int F6 //已过时。 F6功能键,非ASCII动作键。
static int F7 //已过时。 F7功能键,非ASCII动作键。
static int F8 //已过时。 F8功能键,非ASCII动作键。
static int F9// 已过时。 F9功能键,非ASCII动作键。
static int GOT_FOCUS //已过时。 一个组件获得了关注。
static int HOME //已过时。 Home键,非ASCII动作键。
int id //已过时。 指示事件的事件类型以及与事件相关的其他 Event变量。
static int INSERT //已过时。 Insert键,非ASCII动作键。
int key// 已过时。 在键盘事件中按下的键的键代码。
static int KEY_ACTION //已过时。 用户按下了非ASCII 动作键。
static int KEY_ACTION_RELEASE //已过时。 用户已发布非ASCII 动作键。
static int KEY_PRESS //已过时。 用户按下了普通键。
static int KEY_RELEASE// 已过时。 用户已释放正常密钥。
static int LEFT //已过时。 左箭头键,非ASCII动作键。
static int LIST_DESELECT //已过时。 已取消选择列表中的项目。
static int LIST_SELECT //已过时。 已选择列表中的项目。
static int LOAD_FILE //已过时。 文件加载事件。
static int LOST_FOCUS //已过时。 一个组件失去了焦点。
static int META_MASK //已过时。 此标志表示事件发生时Meta键已关闭。
int modifiers //已过时。 修饰键的状态。
static int MOUSE_DOWN //已过时。 用户按下了鼠标按钮。
static int MOUSE_DRAG //已过时。 用户已按下按钮移动鼠标。
static int MOUSE_ENTER// 已过时。 鼠标已进入组件。
static int MOUSE_EXIT //已过时。 鼠标已退出组件。
static int MOUSE_MOVE //已过时。 鼠标移动时没有按下任何按钮。
static int MOUSE_UP //已过时。 用户已释放鼠标按钮。
static int NUM_LOCK //已过时。 Num Lock键,非ASCII动作键。
static int PAUSE //已过时。 Pause键,非ASCII动作键。
static int PGDN //已过时。 Page Down键,非ASCII动作键。
static int PGUP //已过时。 Page Up键,非ASCII动作键。
static int PRINT_SCREEN //已过时。 Print Screen键,非ASCII动作键。
static int RIGHT //已过时。 右箭头键,非ASCII动作键。
static int SAVE_FILE //已过时。 文件保存事件。
static int SCROLL_ABSOLUTE //已过时。 用户已将气泡(拇指)移动到滚动条中,移动到“绝对”位置,而不是从最后位置偏移。
static int SCROLL_BEGIN //已过时。 滚动开始事件。
static int SCROLL_END //已过时。 滚动结束事件。
static int SCROLL_LINE_DOWN //已过时。 用户已激活滚动条的 线下区域。
static int SCROLL_LINE_UP //已过时。 用户已经激活的滚动条的 排队区域。
static int SCROLL_LOCK //已过时。 Scroll Lock键,非ASCII动作键。
static int SCROLL_PAGE_DOWN //已过时。 用户激活滚动条的 向下翻页区域。
static int SCROLL_PAGE_UP //已过时。 用户已经激活了滚动条 上的 page up区域。
static int SHIFT_MASK //已过时。 此标志表示事件发生时Shift键已关闭。
static int TAB //已过时。 Tab键。
Object target //已过时。 目标组件。
static int UP //已过时。 向上箭头键,非ASCII动作键。
long when //已过时。 时间戳。
static int WINDOW_DEICONIFY //已过时。 用户已要求窗口管理器对窗口进行去图标化。
static int WINDOW_DESTROY //已过时。 用户已要求窗口管理器终止窗口。
static int WINDOW_EXPOSE //已过时。 用户已要求窗口管理器公开窗口。
static int WINDOW_ICONIFY //已过时。 用户已要求窗口管理器将窗口图标化。
static int WINDOW_MOVED //已过时。 用户已要求窗口管理器移动窗口。
int x //已过时。 事件的 x坐标。
int y 已过时。 事件的 y坐标。
1.4 事件的向外传播
事件传播从事件发生的构件开始,一直可以传播到最外层的容器。但是,一些构件可以终止事件沿着容器链的传播,只要其handleEvent方法完全完成处理事件并返回true。
1.5 覆盖被传播的事件的处理
处理被传播的事件的方法的返回值是一个布尔值,该值指示事件是否已被处理。如果返回的值为true,则表示事件已经被处理,而且不需要传播给构件的容器。如果返回的值为false的话,则表示事件没有被完全处理,而且应发送给构件的容器。
处理 | handleEvent的返回值 |
---|---|
向其容器传播事件 | 返回false |
不向其容器传播事件 | 返回true |
由超类处理和决定是否传播事件 | 返回super.handleEvent(event) |
事件处理指导方针:
条件 | 方法 |
---|---|
覆盖handleEvent() | 调用super.handleEvent(event)并让超类决定是否传播事件 |
覆盖上面的方法中的一个 | 返回辅助方法的超类实现 |
不应做的事情是从一个辅助方法中返回super. handleEvent (Event)。作为一个规则,当覆盖辅助方法时,最好是将事件直接传播给容器。
2、事件修饰常数
除了id域外,在每个java.awt.Event中还包含一个modifiers域,该域的作用是提供事件的附加信息。例如,你可以知道什么键或哪个鼠标按钮触发了事件。在 Event 类中,定义了一些常数用来提供这些信息。
包含在上面的java.awt.Event类型常数中。
3、鼠标按钮事件
applet是Container的一个扩展。
import java.applet.Applet;
import java.awt.*;
public class demo08 extends Applet {
@Override
public void init() {
setLayout(new BorderLayout());
add(new MouseSensorCanvas(),"Center");
}
class MouseSensorCanvas extends Canvas{
@Override
public boolean mouseDown(Event evt, int x, int y) {
System.out.println("mouseDown");
return true;
}
}
}
3、关于鼠标和按钮
不同操作平台使用不同的鼠标。
Macintosh系统一般使用的是单按钮鼠标,pc机一般使用双或三按钮鼠标,而SPARC系统则是使用三鼠标,java在处理他们时是采用事先假定所有的鼠标都有的一个按钮的方式。
4、监控鼠标事件
事件的传递的实现。代码查阅《java2图形卷1:AWT》相关章节
5、检测双击事件
public demo extends Canvas {
public boolean mouseDown(Event event, int x, int y) {
if(event.clickCount == 2){}
}
}
6、动作事件
动作事件可以由下面的类产生:
- Button
- Checbox
- Choice
- List
- MenuItem
- TextFiled
例如:
class demo extends Frame {
public boolean action(Event event, Object what){}
}
action方法中参数what的值
Button //表示按钮标签文本的字符串
Checkbox //Boolean值,如果checkbox被选中则返回的值为true,反之为false
Choice //表示在选择框中显示的文本的字符串
List //表示被双击的项目的字符串
MenuItem //表示被选择的菜单项的字符串
TextField//表示文本框中文本的String
7、标识构件
标准AWT检测某些构件(特别是按钮〉标签,来判断和事件相关的构件。例如显示三个按钮并使用按钮的标签判断哪个按钮触发了动作事件:
Button one = new Button("one");
Button two = new Button("two");
public boolean action(Event event, Object what){
if(what.equal("one")){}
}
8、基于继承的事件模型的缺点
基于继承的模式需要扩展一个构件,以便处理事件。
8.1 事件的传播
旧事件模式需要你通过从覆盖的事件处理方法中返回的 boolean值决定事件是否应被传播给它的容器。HandleEvent ()和相关的辅助方法(如mouseDown ()、mouseUp ()等等)返回…个 boolean值,以指示事件是否应被传播给构件的容器。如果返回值是tre,则表明事件被完全处理,所以事件不被传播。如果返回值为false,则表示事件没有被完全处理,需要传播。
import java.applet.Applet;
import java.awt.*;
public class demo08 extends Applet {
@Override
public void init() {
setLayout(new BorderLayout());
add(new MouseSensorCanvas(),"Center");
}
class MouseSensorCanvas extends Canvas{
@Override
public boolean handleEvent(Event evt) {
if(evt.id == Event.MOUSE_UP) {
System.out.println("mouseup");
return true; //处理了事件
}
return super.handleEvent(evt);//没有处理,返回到上层的方法中,分派可以发生,所以鼠标按下的时候也是打印mousedown。但如果如果返回false那么,所有事件打印的都是mouseup。
}
@Override
public boolean mouseDown(Event evt, int x, int y) {
System.out.println("mouseDown");
return true;
}
}
}
传播看上去好象是合理的,但是,传播和构件层之间的交互作用经常会导致难以察觉的错误。例如,在程序中,我们不用调用mouseDown方法,因为我们已经覆盖了handleEvent ()。Component . handleEvent ()将事件分派到辅助方法(如mouseDown ()),并且因为我们已经覆盖了Component . handleEvent (),使分派不再进行。调整是由handleEvent ()返回super . handleEvent (event),所以分派可以发生。
8.2 继承的要求
要求事件处理通过继承被实现,可以导致扩展过剩,因为机能上相同的构件要求不同的事件处理算法。可能“过剩”是夸大其词,但是,这是对继承的误用,要求你扩展一个类以改变同类型的对象的某个特性(属性或方法)— java.awt.Container在这方面是不理想的,因为要求你扩展它以改变其空白区。Component同样也要求你覆盖hendleEvent ()(或一个辅助方法)来处理事件。当要处理的特征可能会频繁变化时,这个问题将非常复杂,对于事件处理就是这样的。
8.4 传送事件的责任
- 对于基于继承的事件处理,管理事件的责任由产生事件的构件承担。
- 此外,问题中的构件可以选择向哪里传递事件:事件可以被传递到超类或到构件所在的容器中。对于基于授权事件模式,事件监听者的责任是说明它们本身感兴趣几个和某一构件关联的事件,事件通过AWT的机制自动地发送给监听者。
- 承担传送事件责任的应该是事件的监听者,而不是产生事件的对象;如果监听者对按钮的激活感兴趣,监听者应该注册对某按钮动作事件感兴趣——传送事件到监听者的责任不应由按钮承担。
- 如果传送事件的责任被留给产生事件的构件处理,则构件必须在构件被开发时就知道谁对它的事件感兴趣,但这是相当受到限制的。
- 当传送事件的责任由监听者°承担时,构件不知道谁正在监听其事件,所以构件从不需要为传送事件给监听者而扩展。
- 当构件为传送事件负责时,它紧紧地与要接收事件的类相耦合。当监听者有责任注册感兴趣的事件时,构件被从监听它的事件的对象中分离出来。这种分离可产生更多的模块化代码,可以从底层对象模块中分离出用户界面类。
8.5 handleEvent()转换语句
- 关于基于继承模式的另一个缺点是,覆盖的 handleEvent ()中的转换语句,对于简单的applet可以工作得很好,但在复杂环境中表现得极差。
- 用转换语句转换对象的类型(蕴涵的或具体的),几乎是所有不完善的面向对象设计的原因。代替转换语句的是多形性,多形性用于让编译器(而不是开发者)决定对给定的对象类型调用什么函数。
- 通常,当转换语句转换对象类型存在于面向对象代码中时,它将被重分解,这样常量表示的对象类型被转换进类层次。转换语句则被改写为简单地调用对象上的方法,对象类型一般是位于(或接近)类层次的顶端。对于1.1版本事件模式,这是正确的。在基于授权的事件模型中不在Event类中用整型常数指明事件类型,而是提供一个事件类的层次,如 AWTEvent 、Ac-tionEvent 、ComponentEvent 、 KeyEvent 、MouseEvent等等。