第四章:深入了解事件模型

Visual FoxPro 提供了真正的无模式操作,使您不仅能够轻松地进行多个表单的自动协调,而且很容易同时运行一个表单的多个实例。Visual FoxPro 还提供事件处理机制,可以给用户提供一个更丰富的交互环境。

本章内容要点:

Visual FoxPro 中的事件

当系统响应用户的一些动作时,自动触发事件代码。例如,用户在控件上做出单击动作时,系统自动执行为 Click 事件编写的代码。事件代码也可被系统事件触发,例如计时器中的 Timer 事件。

核心事件

下面是 Visual FoxPro 核心事件集的列表,这些事件适用于大多数的控件。

核心事件集

事件 事件被激发后的动作
Init 创建对象。
Destroy 从内存中释放对象。
Click 用户使用主鼠标按钮单击对象。
DblClick 用户使用主鼠标按钮双击对象。
RightClick 用户使用辅鼠标按钮单击对象。
GotFocus 对象接收焦点,由用户动作引起,如按 Tab 键或单击,或者在代码中使用 SetFocus 方法程序
LostFocus 对象失去焦点,由用户动作引起,如按 Tab 键或单击,或者在代码中使用 SetFocus 方法程序使焦点移到新的对象上。
KeyPress 用户按下或释放键。
MouseDown 当鼠标指针停在一个对象上时,用户按下鼠标按钮。
MouseMove 用户在对象上移动鼠标。
MouseUp 当鼠标指针停在一个对象上时,用户释放鼠标按钮。

容器事件和对象事件

控件编写事件代码时,请注意以下两条基本规则:

当用户以任意一种方式(使用 Tab 键、单击鼠标、将鼠标指针移至控件上等)与对象交互时,对象事件被触发。每个对象只接收自己的事件。例如,尽管命令按钮位于表单上,当用户单击命令按钮时,不会触发表单的 Click 事件,只触发命令按钮的 Click 事件。

容器事件代码与控件事件代码相互独立

若没有与命令按钮相关联的 Click 事件代码,尽管有与表单相关联的 Click 事件代码,当用户单击按钮时,也不会执行与表单相关联的 Click 事件代码。

这条规则也适用于表格控件。表格包含列,列又包含标头和控件。当事件发生时,只有与事件相关联的最底层对象识别该事件,高层的容器不识别这个事件。下图演示当用户在表格上移动鼠标时,哪个对象处理这个 MouseMove 事件。

表格的 MouseMove 事件

这条规则也有一个例外。如果为选项按钮组或命令按钮组编写了某事件代码,而组中个别按钮没有与该事件相关联的代码,当这个按钮的事件发生时,将执行组事件代码。

例如,有一个选项按钮组,在它的 Click 事件中包含了相关的代码,而在选项按钮组的两个选项按钮中只有一个按钮拥有与 Click 事件相关联的代码。

按钮组的事件代码可以作为默认事件代码

当用户单击 Option1 时,与其相关联的 Click 事件代码被执行,不执行与按钮组相关联的 Click 事件代码。

因为没有与 Option2 相关联的 Click 事件代码,若用户单击 Option2,将执行选项按钮组的事件代码。

注释 当连续发生一系列事件时(比如 MouseDown 事件后面接着发生 MouseUp 事件),若起始事件与某个控件相关联,那么整个事件队列都将属于这个控件。

例如,在一个命令按钮上,按下鼠标左键并拖动鼠标指针离开命令按钮,尽管鼠标指针可能已在表单上,这个命令按钮的 MouseMove 事件还是不断产生。当在表单上而不是在命令按钮上释放鼠标左键时,发生的 MouseUp 事件是与命令按钮相关联,而不是与表单相关联。

类和控件事件

表单上的控件基于一个用户自定义类(同样地,这个类本身也可能基于其他用户自定义类),当一个事件发生时,Visual FoxPro 首先在该控件中查看是否有与此事件相关联的代码。若找到,则执行它;否则,Visual FoxPro 将在类层次中向上逐层检查。无论 Visual FoxPro 在类层次的哪个地方找到该事件代码,都执行它,而该层以上的代码不会被执行。

若没有与对象相关联的事件代码,Visual FoxPro 将检查父类。

您可以将代码加入到事件过程中,然后使用 DODEFAULT( ) 函数显式地调用控件的父类代码。

追踪事件序列

Visual FoxPro 具有扩展的事件模型,可根据用户的各种操作灵活地控制应用程序的组件。有些事件序列是固定的,如表单在创建或删除时发生的事件序列;有些事件是独立发生的;但大多数事件是用户与 Visual FoxPro 交互处理时伴随其他一系列事件发生的。

打开事件追踪

查看 Visual FoxPro 事件序列的最佳方法是在调试器中设置事件追踪。当每个与表单和控件相关联的事件发生时,事件追踪都将把它们记录下来,以便当时或过后查看,帮助您确定加入代码的最佳位置。

若要打开事件追踪

  1. “Visual Foxpro 调试器”窗口的“工具”菜单中,选择“事件跟踪”。

  2. 在“事件跟踪”对话框中,选择“开启事件跟踪”。

当事件追踪表中所列出的事件发生时,将记录在调试器输出窗口或指定文件中。

事件追踪对话框

注释 在此例中,将 MouseMove 和 Paint 事件从事件追踪表中移出,是因为这些事件发生频繁,如果包含了它们,将会干扰对事件序列中其他事件的查看。

监视事件发生

有时一个用户的动作只触发一个事件(比如用户在控件上移动鼠标按钮),然而也会经常触发多个事件。

本节使用下面的表单作为示例,说明响应用户动作的事件其发生次序。

显示事件序列的表单示例

上面示例中,用户在表单上执行以下动作:

  1. 运行该表单。

  2. 在 Text1 中键入文本。

  3. 选择此文本,并将其复制到剪贴板。

  4. 输入焦点移向 Text2。

  5. 将文本粘贴至 Text2。

  6. 单击 Command2,关闭表单。

以上动作触发了每个对象的一个或多个系统事件。下表详细说明了响应每个用户动作所触发的事件。

动作 1

通过在“命令”窗口中键入以下命令,用户可以运行表单:

DO FORM form1 NAME frmObject

Visual FoxPro 加载表单,初始化每个对象,然后初始化表单。这时表单被激活,第一个字段开始接收输入焦点。

对象 事件
DataEnvironment BeforeOpenTables
Form1 Load
DataEnvironment Init
Text1 Init
Text2 Init
Command1 Init
Command2 Init
Form1 Init
Form1 Activate
Form1 GotFocus
Text1 When
Text1 GotFocus

动作 2

用户在 Text1 中键入 Test,每次击键激发两个事件。KeyPress 事件接收 2 个参数:按下的键和 SHIFT、ALT 或 CTRL 键的状态。

对象 事件
Text1 KeyPress (84, 1) “T”
Text1 InteractiveChange
Text1 KeyPress (101, 0) “e”
Text1 InteractiveChange
Text1 KeyPress (115,0) “s”
Text1 InteractiveChange
Text1 KeyPress (116,0) “t”
Text1 InteractiveChange

动作 3

用户双击 Text1 选择文本,然后按下 CTRL+C 复制文本至剪贴板。Mouse 事件和 Click 事件伴随着 DblClick 事件MouseMove 事件MouseDown 事件接受四个参数:其一表示哪个按钮被按中,其余的表示Shift 状态及 X、Y 的位置。X、Y 是相对于表单的坐标位置并使用与表单相同的刻度模式(例如,像素)。 每个控件仅列出一个 MouseMove 事件。事实上,此事件可能触发 6 次或更多。

对象 事件
Form1 MouseMove(0, 0, 100, 35)
Text1 MouseMove(0,0,44,22)
Text1 MouseDown(1, 0, 44, 22)
Text1 MouseUp(1, 0, 44, 22)
Text1 Click
Text1 MouseDown(1, 0, 44, 22)
Text1 MouseUp(1, 0, 44, 22)
Text1 DblClick

动作 4

用户通过按下 TAB 键将输入焦点移向 Text2。

对象 事件
Text1 KeyPress(9, 0)
Text1 Valid
Text1 LostFocus
Text2 When
Text2 GotFocus

动作 5

用户按下 CTRL+V 粘贴已复制的文本。

对象 事件
Text2 InteractiveChange

动作 6

用户单击 Command2 关闭表单。

对象 事件
Form1 MouseMove
Command2 MouseMove
Text2 Valid
Command2 When
Text2 LostFocus
Command2 GotFocus
Command2 MouseDown(1, 0, 143, 128)
Command2 MouseUp(1, 0, 143, 128)
Command2 Click
Command2 Valid
Command2 When

在关闭表单和释放对象之后,将发生附加的事件,其次序正好与动作 1 中的事件相反。

对象 事件
Form1 Destroy
Command2 Destroy
Command1 Destroy
Text2 Destroy
Text1 Destroy
Form1 Unload
DataEnvironment AfterCloseTables
DataEnvironment Destroy

Visual FoxPro 事件顺序

下表显示了 Visual FoxPro 事件的一般触发顺序。表中假定数据环境AutoOpenTables 属性设置为“真”(.T.)。其他事件的发生是基于用户的交互行为和系统响应。

对象 事件
数据环境 BeforeOpenTables
表单集 Load
表单 Load
数据环境临时表 Init
数据环境 Init
对象 1 Init
表单 Init
表单集 Init
表单集 Activate
表单 Activate
对象 1 2 When
表单 GotFocus
对象 1 GotFocus
对象 1 Message
对象 1 Valid 3
对象 1 LostFocus
对象 2 3 When
对象 2 GotFocus
对象 2 Message
对象 2 Valid 4
对象 2 LostFocus
表单 QueryUnload
表单 Destroy
对象 5 Destroy
表单 Unload
表单集 Unload
数据环境 AfterCloseTables
数据环境 Destroy
数据环境临时表 Destroy

1 对于每个对象,从最内层的对象到最外层的容器
2 Tab 键次序中的第一个对象
3 下一个获得焦点的对象
4 当对象失去焦点时发生
5 对于每个对象,从最外层的容器到最内层的对象

为事件指定代码

事件发生时,若没有与之相关联的代码,则不会发生任何操作。对于绝大多数事件,您都不必编写代码,您只需对少数几个关键的事件编程即可。 若要编写响应事件的代码,请使用“表单设计器”中的“属性”窗口

一段代码应置于何处,是由事件发生的顺序决定的。请注意以下提示:

有关使用“表单设计”的详细内容,请参阅第九章“创建表单”。有关以编程方式创建类和添加事件代码的详细内容,请参阅第三章“面向对象程序设计”