Delphi中Sender对象的知识
Sender是一个TObject类型的参数,它告诉Delphi哪个控件接收这个事件并调用相应的处理过程。你可以编写一个单一的事件处理句柄,通过Sender参数和IF…THEN…语句或者CASE语句配合,来处理多个构件。发生事件的构件或控件的值已经赋给了Sender参数,该参数的用途之一就在于:可以使用保留字IS来测试Sender,以便找到调用这个事件处理句柄的构件或控件的类型。例如,将表单中编辑框和标签的Click事件的处理句柄都指向表单的xxx过程,编辑框和标签对Click事件有不同的反应:
procedure TForm1xxx(Sender:TObject);
begin
if(sender is Tedit) then
showmessage(′this is a editbox′);
if(sender is Tlabel) then
showmessage(′this is a label′);
end;
Sender参数的第二个用途是结合AS操作符进行类型转换,将若干个派生于某一父类的子类强制转换成该父类。例如表单中有一个TEdit类控件和一个TMemo控件,它们实际上都派生于TcustomEdit类,如果你要为二者的某一事件提供同样处理,可以将二者事件句柄都指向自定义的过程yyy:
Procedure TForm1.yyy(Sender:TObject);
begin
(sender as TcustomEdit).text:=′This is some demo text′;
end;
在过程中,AS操作符将TEdit类和TMemo类均强制转换成TcustomEdit类,再对TcustomEdit类的属性赋值。注意这种转换必须符合Delphi中类的层次关系。
使用Sender参数可以通过单一过程段处理多类控件,真正体现了Delphi面向对象的重用性。
-----------------------
Delphi之Sender
Sender其实就是函数的一个参数,你看看VCL中触发事件的代码,就会发现Sender往往代表了 “事件的触发者”,或者说“这个外挂的事件处理函数的调用者”,目的是为了让事件处理函数有一个参考尤其是当一个事件处理函数挂接到多个实例时。
//看个例子
procedure THappy.MakeLove;
var
bCancel :Boolean;
bNeedBath :Boolean;
bHappy :Boolean;
begin
bCancel := False;
bNeedBath := True;
if assigned(FOnBeforeMakeLove) then
FOnBeforeMakeLove(Self, bNeedBath, bCancel);
if bCancel then Exit;
if bNeedBath then GotoBath;
bHappy := DoMakeLove(Self.Boy, Self.Girl);
if assigned(FOnAfterMakeLove) then
FOnAfterMakeLove(Self, bHappy);
end;
procedure XXXBeforeMakeLove(Sender :TObject; var ANeedBath, ACancel :Boolean);
begin
if Sender is THappy then begin
if (THappy(Sender).Boy <> me) or (THappy(Sender).Girl.Age < 16)
or (THappy(Sender).Girl.Age > 25) then
begin
ACancel := True;
end;
ANeedBath := OfCourseTrue;
end;
end;
procedure XXXAfterMakeLove(Sender :TObject; const AHappy :Boolean);
begin
if AHappy then
begin
ShowMessage('爽歪歪...');
end
else begin
ShowMessage('555...');
end;
end;
-------
这个东西感觉还是比较抽象的。需要慢慢的细细体会。
从理论上讲Sender是一个四个字节的指针变量,里面存放的指针内容是(堆)栈中对象实体的首字节地址。我们在每次在设计APP的时候,会在Object Inspector里面双击事件属性来建立我们需要的代码,以完成预期的功能。当我们进行双击的时候,Delphi的IDE(Integreted Development Environment)会为我们自动建立与事件属性对应的过程,例如,当我们双击Form1变量的OnClick属性时,IDE会自动在TForm1类 的初始化部分创建如下的代码:
procedure TForm1.Form1Click(Sender:TObject);
同时在实现部分创建上述过程的框架,如下:
procedure TForm1.Form1Click(Sender:TObject);
begin
//初始情况下,这里并没有任何代码!
end;
然后我们在程序中可以调用这个建立好的方法,例如我们在窗体上的Button1的OnClick方法中执行如下代码:
...
Self.Form1Click(Button1);
...
同时,我们假设在Form1Click中代码如下:
...
if Sender=Button1 then
ShowMessage(TButton(Sender).Caption); //这里在判断条件为真的情况下使用强制转换
...
可以看到在代用Form1Click时,为其传递的Sender参数可以自己定义,因此严格来讲Sender参数并不代表真正触发此事件对应方法的对象,确切的说应该是用户指定的触发此事件对应方法的对象!
Sender表示触发当前事件代码的对象,而Self才表示当前方法指针指向的方法所属的对象
例如对于TForm的对象Form1,起OnClick事件中包含参数Sender,如下
procedure TForm1.FormClick(Sender:TObject);
这里的FormClick实际是Delphi的IDE在设计期为你在窗口类的初始化未命名部分自动建立的方法,但他的可见性是Pulished的,因此具有RTTI信息!!!!
在运行期间,当前的方法指针FClick指向的方法属性(即事件)OnClick所属于的对象为TForm1的实例Form1,因此Self代表的就是对 象Form1,而触发这个事件的对象不一定是Form1,有可能是Button1,所以Sender需要进行判断。你可以在Button1的 OnClick事件中调用如下代码:
Form1.OnClick(Button1);
这个时候在Form1的OnClick事件中对Sender进行判断就是Button1,而不是Form1了!
需要注意的是,由于Sender的类型为TObject,因此实际使用的时候最好进行类型转换!!!!使用As运算符!!!!
Delphi中Sender对象的知识的更多相关文章
- 关于delphi 中 Sender的学习
sender是 事件的触发者,我发现所有的组件的事件 基本上都是 传Sender. 示例效果图: 代码: 接着来,既然TButton是个类,且publish哪里有事件,我们也可以看看这个事件的原型.
- delphi 中判断对象是否具备某一属性
Uses TypInfo; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); ...
- Delphi中的Sender:TObject对象解析
Delphi中的Sender:TObject对象解析 procedure TForm1.Button1Click(Sender: TObject); begin end; 解析:Procedure是过 ...
- Delphi中的Sender:TObject对象解析转载
https://blog.csdn.net/jl_tiny/article/details/24376661 Delphi中的Sender:TObject对象解析 procedure TForm1.B ...
- 关于 Delphi 中的Sender和易混淆的概念(转)
/////////////////////////////////////////////////////// Delphi 中Sender对象的定义///////////////////////// ...
- Delphi中使用比较少的一些语法
本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ---Murphy 1,构造和析构函数: a,构造函数: 一般基于TComponent组件的派生类 ...
- 转:Delphi中使用比较少的一些语法
http://www.cnblogs.com/Murphieston/p/5577836.html 本文是为了加强记忆而写,这里写的大多数内容都是在编程的日常工作中使用频率不高的东西,但是又十分重要. ...
- Delphi引用C对象文件
C语言应用非常广泛,并在世界各地拥有大量的代码库.这些代码库与Delphi的可比性较小,因此如果我们无需转换为Delphi代码而可以直接使用这些库的部分代码就完美了.幸运的是,Delphi允许连接到C ...
- Delphi引用C对象文件(转)
源:http://blog.csdn.net/henreash/article/details/7357618 C语言应用非常广泛,并在世界各地拥有大量的代码库.这些代码库与Delphi的可比性较小, ...
随机推荐
- RMI入门HelloWorld
java RMI(Remote Method Invocation)是一种基于java远程调用技术,是对RPC的java实现,可以在不同主机上进行通信与方法调用.PRC通信原理如图: 方法调用从客户对 ...
- 路由追踪:traceroute/tcptraceroute
一.工作原理 traceroute:IP路由过程中对数据包TTL(Time to Live,存活时间)进行处理.当路由器收到一个IP包时,会修改IP包的TTL(及由此造成的头部检验和checksum变 ...
- AOSP 设置编译输出目录
export OUT_DIR=/media/caoxinyu/TomasYu/out 注意:export OUT_DIR= OUT_DIR 后面直接跟= ,不要有空格.否则报错.
- fastDFS 分布式文件系统应用
环境准备 使用的系统软件 名称 说明 centos 7.x libfatscommon FastDFS分离出的一些公用函数包 FastDFS FastDFS本体 fastdfs-nginx-modul ...
- node-redis使用记录
redis的高速存取性能让人印象深刻,虽然是分布式存储,但相比本地内存,性能毫不逊色. 之所以能做到这点,是由于redis的“单线程,多路复用IO”,同一时刻只有一个操作在进行. 而且多次建立从red ...
- Swift使用AVAudioPlayer来调节游戏的背景音乐大小
音乐文件的声音大小有时在做为游戏背景音乐时会过大,而如果我们只是简单应用SKAudioNode来加载音乐的话,是无法进行声音大小的调节的,因此我们必须使用更强大的AVAudioPlayer来进行声音大 ...
- [JSON].connectionValue()
语法: [JSON].connectionValue() 说明: 将对象的所有键值接连成新的字符串值 返回: [String] 示例: Set a = toJson() c = Array(1,2,3 ...
- 167. Add Two Numbers【LintCode by java】
Description You have two numbers represented by a linked list, where each node contains a single dig ...
- linux c语言 fork() 和 exec 函数的简介和用法
linux c语言 fork() 和 exec 函数的简介和用法 假如我们在编写1个c程序时想调用1个shell脚本或者执行1段 bash shell命令, 应该如何实现呢? 其实在<std ...
- 水管工游戏:dfs(递归)
添柴网这题好想不能评测,所以不确保代码的正确性 题目描述: 这小节有点难,看不太懂可以跳过哦.最近小哼又迷上一个叫做水管工的游戏.游戏的大致规则是这样的.一块矩形土地被分为N * M的单位正方形,现在 ...