New Term
Windows也可称为事件驱动(event-driven)环境,事件驱动的意思是指程序是由发生在Windows环境中的事件驱动,事件包括鼠标移动、鼠标点击和键盘击键。
从DOS或大型机编程环境中转移来过来的程序员可能对理解事件驱动这个概念有一点困难,一个Windows程序会不停地定时查询Windows事件,Windows中的时间包括激活菜单、点击按钮、移动窗口、重画窗口和激活窗口等。
Windows通过发送Windows消息来通知程序事件,Windows发送给应用程序的消息超过200多种,这些消息太多,幸运的是,在Delphi中并不需要了解所有这些消息,它们中只有几十个是常用的。
在VCL中,事件就是发生在用户需要知道的组件中的任何事情,每个组件都是设计用来响应一定的时间,通常这是指Windows事件,但它也可指其他事件。例如,按钮组件设计用来响应鼠标点击,这与预想的一样,但一个非可视化组件,诸如数据库组件,就能响应非Windows事件,比如用户达到表格结尾就是非Windows事件。
New Term
处理事件(Handling event),当响应组件事件时,就称之为处理事件。
处理事件是通过所谓的事件处理程序方法来实现,在前面的例子中都已经广泛的使用到了事件处理程序。
一般Windows程序大部分事件都是空闲的,总在等待一些事情发生。VCL使事件处理很容易,在Object Inspector窗口的Event标签下,列出了组件的所有事件,事件名称描述了它们所响应的事件,例如,处理鼠标点击事件就叫OnClick。
还是赶紧在实践中去理解这些概念吧。作为开始,先启动Delphi7,并新建一个Application,得到默认创建的Form1主窗口,接下来我们来设置这个窗口:
1、把Name属性改为PMEForm,把Caption属性设置为“PME Test Program”;
2、接下来为PMEForm窗口添加一个Memo组件,在组件选项卡的Standard标签下选择Memo按钮,并添加到PMEForm中;
3、将Memo组件的Name属性设置为Memo;
4、双击Memo组件的Lines属性,在弹出的字符串编辑器中键入“A test program using properties, methods, and events”,如下所示:
5、在窗体上再放置一个Standard标签上的Button组件,使按钮位于窗体上居中(居中可以用通过主菜单的【View | Alignment Palette】的Center按钮进行居中,如下图);
6、将此Button组件的Name属性改为Button,将此按钮的Caption属性设置为“Show/Hide”,此时窗体看起来如下:
可以用这个按钮来交替显示和隐藏Memo组件,现在需要编写一些代码,使得点击此按钮时能做一些事情,确认此按钮被选中,然后点击Object Inspector中的Event标签,然后双击OnClick事件的Value列,CodeEditor将出现,并显示出OnClick过程等待输入。
现在事件处理程序已经设置好了,接下来所要做的就是输入代码,我们仔细来看看此事件处理程序,就会发现它是一个过程,过程名为ButtonClick,它是TPMEForm类的一个成员,它含有一个指向TObject的Sender的指针参数,下面我们来输入代码:
procedure TPMEForm.ButtonClick(Sender: TObject); {$J+} //在在Delphi5中直接用const来定义静态局部变量, //在以后的Delphi版本中则可以使用const和{$J+}开关来办到。 const IsVisible: Boolean = False; begin IsVisible := not IsVisible; if IsVisible then Memo.Hide else Memo.Show; end;
这段代码首先声明了一种叫IsVisible的已定类型的常量。
New Term
已定类型常量(typed constant),就是一种“静态变量”,也是以const修饰,它实际上等同于C里的static修饰。该变量并不会随着过程的结束而销毁,而是一直保持着它的值。
以上代码的工作原理如下:
1、此静态变量的初始值为False,当第一次调用事件处理程序时,这个变量就被赋予Not False,也就是True;
2、每次调用此方法,IsVisible就变为前一次的相反值,之后在if/else中根据IsVisible的具体值,而实现Show或者Hide效果;
3、我们把此工程保存,窗体单元保存为PMEFormU.pas,工程文件保存为PME.dpr。
用布尔变量工作有点麻烦,而Memo组件有一个Visible属性,该属性可以让此组件是否可视,我们再次编辑ButtonClick事件处理程序,修改为:
procedure TPMEForm.ButtonClick(Sender: TObject); begin if Memo.Visible then Memo.Hide else Memo.Show; end;
同样可以实现相同的效果,在同一个例子中,可以用属性、方法和事件。
ButtonClick方法中有一个指向TObject的指针叫做Sender的参数,每个事件处理程序起码有一个Sender参数,例如onMouseDown事件处理程序如下:
procedure TPMEForm.ButtonMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end;
Sender是一个指向组件的指针,它用来把有关消息发送给消息处理程序,在这个例子中,Sender参数是多余的,因为Show/Hide按钮就是发送器,Sender的存在能够使多个组件用相同的时间处理程序。
为了说明这一点,我们再在上面的例子的基础上改进:
1、将原来的“Show/Hide”按钮的Name属性和Caption属性都设置为Show;
2、在窗体上再创建一个按钮,使它在Show按钮的右边,并排列整齐;
3、将此新按钮的Name属性和Caption属性都设置为Hide;
4、点击Show按钮,然后点击Object Inspector中的Event标签,我们发现OnClick事件现在已经变为ShowClick了,如下:
5、我们再次修改这个ShowClick名字为ButtonClick(事件处理程序的初始名是缺省名,可以把它改为任何喜欢的名字),如下:
6、点击Hide按钮,并在Object Inspector中找出OnClick事件,在其Value列中选择下拉箭头按钮,点击箭头按钮,并从下拉清单中选择ButtonClick,如下:
7、双击ButtonClick值,就会弹出Code Editor,并且光标就在ButtonClick代码中,修改代码如下:
procedure TPMEForm.ButtonClick(Sender: TObject); begin if Sender = Hide then Memo.Hide else Memo.Show; end;
此时窗体看起来如下,编译并运行程序,点击每个按钮,功能和预想的一样。
这里所做的只是建立一个简单的事件处理方法,它能处理两个按钮的OnClick事件,用Sender参数来决定哪个按钮发送OnClick事件,然后根据需要,要么隐藏要么显示所需的Memo组件。当然也可以单独为Show和Hide按钮分别建立OnClick处理程序,但用这种方法,其代码将紧凑,此外还能更好的说明Sender参数的用法。
注意
这里用Sender变量和Name属性进行比较,因为这两者都是指针,比较的目的就是要看一看两个变量所包含的地址是否一样。
当为一个具体组件建立一个事件处理程序后 ,就可以把这个相同的处理程序连接到窗体上任何组件的OnClick事件,这就可以使多重组件使用同一个事件处理程序。
事件规则
- 根据需要可以相应任何组件的事件
- 不一定要响应某个组件所定义的所有事件。
- 事件是由事件处理方法来处理,此方法称为事件处理程序。
- 多个组件可以共享同一个事件处理程序。
- 由Delphi产生的事件处理程序名是缺省名,它可以被程序员改动。
- 确认只能在Object Inspector中才能改变事件处理程序名。
- 事件处理程序的Sender参数是用来决定哪个组件产生了此事件。
- 双击Object Inspector中的事件处理程序名,将显示Code Editor,并且进入包含事件处理程序的代码段。
- 每个事件处理程序都包含正确处理这个事件所需的参数。
以上代码均在Delphi7中测试通过,示例代码下载:VCL组件之事件.rar