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 事件序列的最佳方法是在调试器中设置事件追踪。当每个与表单和控件相关联的事件发生时,事件追踪都将把它们记录下来,以便当时或过后查看,帮助您确定加入代码的最佳位置。
若要打开事件追踪
当事件追踪表中所列出的事件发生时,将记录在调试器输出窗口或指定文件中。
事件追踪对话框
注释 在此例中,将 MouseMove 和 Paint 事件从事件追踪表中移出,是因为这些事件发生频繁,如果包含了它们,将会干扰对事件序列中其他事件的查看。
有时一个用户的动作只触发一个事件(比如用户在控件上移动鼠标按钮),然而也会经常触发多个事件。
本节使用下面的表单作为示例,说明响应用户动作的事件其发生次序。
显示事件序列的表单示例
上面示例中,用户在表单上执行以下动作:
以上动作触发了每个对象的一个或多个系统事件。下表详细说明了响应每个用户动作所触发的事件。
通过在“命令”窗口中键入以下命令,用户可以运行表单:
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 |
用户在 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 |
用户双击 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 |
用户通过按下 TAB 键将输入焦点移向 Text2。
对象 | 事件 |
Text1 | KeyPress(9, 0) |
Text1 | Valid |
Text1 | LostFocus |
Text2 | When |
Text2 | GotFocus |
用户按下 CTRL+V 粘贴已复制的文本。
对象 | 事件 |
Text2 | InteractiveChange |
用户单击 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 事件的一般触发顺序。表中假定数据环境的 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 对于每个对象,从最外层的容器到最内层的对象
事件发生时,若没有与之相关联的代码,则不会发生任何操作。对于绝大多数事件,您都不必编写代码,您只需对少数几个关键的事件编程即可。 若要编写响应事件的代码,请使用“表单设计器”中的“属性”窗口。
一段代码应置于何处,是由事件发生的顺序决定的。请注意以下提示:
有关使用“表单设计”的详细内容,请参阅第九章“创建表单”。有关以编程方式创建类和添加事件代码的详细内容,请参阅第三章“面向对象程序设计”。