vcl源码分析方法论

获取EditText上内容分行写入文件并读取 一、完成基本结构布局 二、根据id找到每个Button和EditText并设置按钮点击事件监听 三、使用editText1.getText().toString()语句获取到EditText内容并通过点击事件实现转换和运算 四、写一个文件辅助类,为后续将内容写入文件做准备 这里文件内容已基本写完,只需再完善主函数即可。 到这里已经是可以将EditText上内容写到文件里了,最后在利用点击事件读取出文件内容 如果想要获取多行EditText上内容并不覆盖写入文件里只.. 阅读详情

vcl源码分析方法论

最近一段时间似乎流行源码分析:)我也来谈谈在过去一段时间里对VCL源码的分析方法方面的一点体会,本文将不探讨VCL类库的构架和设计模式方面的东本,只是以我们常见的控件属性/方法的实现过程作简单的说明,希望对初学者有所帮助

VCL分析方法
例:TButton.Caption属性的由来
(本文仅以此献给DELPHI初学者)
   用过一段时间DELPHI的朋友,都会对VCL源码感兴趣。本人也常常在各大论坛见到一些网友研究讨论过关于VCL源码的贴子。不过,很多网友很努力的想看懂,可最后还是半途而废,因为他们总是理不出个头绪、看得云里雾里。笔者我也有看源码的习惯,没事的时候就点点鼠标右键,总是希望得到一些侥幸的收获和开发技巧。
   不过万事都得先有个基本前题,就像人上学的过程一样(这里指正常人)要按部就班的来,一般不可能小学一毕业就直接去念大学,除非他(她)是个天才或经过特别培训。所以各位GGJJDDMM,看VCL源码也是有个基本前题的,首先你得熟悉WIN32 API/SDK,如果你说不知道的话,可以参考书籍《Programming Windows》(中文名《WINDOWS 程序设计》)。其次是你应当对Object Pascal比较熟悉,或者你曾经对DELPHI的组件进行过扩展(做过组件开发),那么我相信你对Object Pascal已经熟悉。不熟也不要紧,DELPHI的在线帮助就有对Object Pascal的讲述,如果英文太差也不要紧,网上也有很多热心网友翻译过来的中文帮助和语言参考书。
呵呵,本人写技术文章就像在写散文:)
   言归正传,我们这篇文章的主题是对VCL源码的分析,分析当然有一个分析方法的问题,总不能随便打开一个源程序,逮着一个函数就分析一个函数吧:)所以我们也应该有选择,有目的的分析。
想想我们每天编码时都会遇到的属性有哪些?呵呵,NAME,CAPTION,VISIBLE,还有一些控件的TEXT(如EDIT1.TEXT)。那么我们就以控件的CAPTION来分析吧。
当然不是每个控件都有CAPTION属性的,我们这里就用TButton类的Caption属性进行分析。
   打开每天我们都会使用的DELPHI,在FORM窗体上放一个按钮,得到一个Button1的按钮控件,按F12打天源程序,有没有找到这段代码呢:
Button1: TButton;
对了,在TButton上点击鼠标右键,在弹出的上下文菜单中选择第一项Find Declaration,找到TButton类的定义,如下所示:
 TButton = class(TButtonControl)
 private
   FDefault: Boolean;
   FCancel: Boolean;
   FActive: Boolean;
   FModalResult: TModalResult;
   procedure SetDefault(Value: Boolean);
。。。。。。

   原来TButton继承于TButtonControl类,呵呵:)
在左边的对象窗口(Exploring Unit.pas窗口)中找到TButton的CAPTION属性,如下图:

   双击CAPTION属性,找到定义CAPTION属性的源码,大家可能发现什么都没有,只有一个   
   property Caption;
   呵呵,写过组件的朋友都知道,按理Caption属性应该有读/写文本的方法啊?在哪里去了呢,呵呵,这里没有出现,当然应该在它的父类里了(这里只是申明Caption出来的地方),我们顺着刚才的方法继续在TButtonControl,发现也没有,最终我们在TControl类里找到了这个CAPTION,至于为什么是protected成员,我就不多说了:
 protected
   procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); dynamic;
   procedure AdjustSize; dynamic;
   procedure AssignTo(Dest: TPersistent); override;
   procedure BeginAutoDrag; dynamic;
   function CanResize(var NewWidth, NewHeight: Integer): Boolean; virtual;
   function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; virtual;
   procedure Changed;
   procedure ChangeScale(M, D: Integer); dynamic;
。。。。。。
   property Caption: TCaption read GetText write SetText stored IsCaptionStored;
   看看GetText、SetText就是操作文本属性的函数了,我们找到GetText、SetText定义如下:
function GetText: TCaption;
procedure SetText(const Value: TCaption);
还有TCaption,它的定义居然是一个自定义类型:
TCaption = type string;
   说明GetText返回值和SetText的调用参数本来也就是一个string型的:)

   下面我们来看看GetText源码:
function TControl.GetText: TCaption;
var
 Len: Integer;
begin
 Len := GetTextLen;//得到文本长度
 SetString(Result, PChar(nil), Len);// 设置Result返回以Len指定的长度
 if Len <> 0 then GetTextBuf(Pointer(Result), Len + 1);//长度不为空,Result得到文本数据
end;

   如果不明白GetTextBuf的用法,看看如下的代码:
procedure TForm1.Button1Click(Sender: TObject);
var
 Buffer: PChar;
 Size: Byte;
begin
 Size := Edit1.GetTextLen;   //得到EDIT1的文本长
 Inc(Size);               
 GetMem(Buffer, Size);          //创建EDIT1文本长度大小的缓存空间
 Edit1.GetTextBuf(Buffer,Size);  //由缓存得到文本,Buffer里的值就是Edit1.Text
 Edit2.Text := StrPas(Buffer);   //Buffer转换为PASCAL字符类型数据
 FreeMem(Buffer, Size);      //释放内存
end;
以上程序的行为同以下程序相当:
procedure TForm1.Button1Click(Sender: TObject);
begin
 Edit2.Text := Edit1.Text;
end;

   回到GetText函数,其中GetTextLen的作用是得到文本长度,GetTextBuf得到文本数据。
   SetText就更简单了,定义如下:
procedure TControl.SetText(const Value: TCaption);
begin
 if GetText <> Value then SetTextBuf(PChar(Value));
end;
   意思是如果设定的Value与原来的不同,则重新设置缓存文本。

 

   为了更深入VCL底部,我们再看看GetTextLen如何实现的(其实SetTextBuf和GetTextLen的实现过程相似):
function TControl.GetTextLen: Integer;
begin
 Result := Perform(WM_GETTEXTLENGTH, 0, 0);//WM_派发的是WINDOWS标准消息
end;
   看到这里想必大家都明白了,如果还不明白(没用过Perform),我看再看看Perform,它到底做了什么:
function TControl.Perform(Msg: Cardinal; WParam, LParam: Longint): Longint;
var
 Message: TMessage;
Begin
{你的消息赋予TMessage }
 Message.Msg := Msg; ;
 Message.WParam := WParam;
 Message.LParam := LParam;
Message.Result := 0;//0表示返回不处理
 if Self <> nil then WindowProc(Message);//不为空,将消息交给TControl的窗口过程WindowProc处理
 Result := Message.Result;//返回结果
end;
   这里主要再看看WindowProc做了什么,TControl里面WindowProc是这样定义的:
property WindowProc: TWndMethod read FWindowProc write FWindowProc;
在TControl的Create函数中:
constructor TControl.Create(AOwner: TComponent);
begin
 inherited Create(AOwner);
 FWindowProc := WndProc;
。。。。。。
   可见我们还要找到TControl 的WndProc过程才能明白究竟,
WndProc过程定义如下:
procedure WndProc(var Message: TMessage); override;
   实现:
procedure TControl.WndProc(var Message: TMessage);
var
 Form: TCustomForm;
 KeyState: TKeyboardState; 
 WheelMsg: TCMMouseWheel;
begin
 if (csDesigning in ComponentState) then
 begin
   Form := GetParentForm(Self);
   if (Form <> nil) and (Form.Designer <> nil) and
     Form.Designer.IsDesignMsg(Self, Message) then Exit
 end;
 if (Message.Msg >= WM_KEYFIRST) and (Message.Msg <= WM_KEYLAST) then
 begin
   Form := GetParentForm(Self);
   if (Form <> nil) and Form.WantChildKey(Self, Message) then Exit;
 end
 else if (Message.Msg >= WM_MOUSEFIRST) and (Message.Msg <= WM_MOUSELAST) then
 begin
   if not (csDoubleClicks in ControlStyle) then
     case Message.Msg of
       WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, WM_MBUTTONDBLCLK:
         Dec(Message.Msg, WM_LBUTTONDBLCLK - WM_LBUTTONDOWN);
     end;
   case Message.Msg of
     WM_MOUSEMOVE: Application.HintMouseMessage(Self, Message);
     WM_LBUTTONDOWN, WM_LBUTTONDBLCLK:
       begin
         if FDragMode = dmAutomatic then
         begin
           BeginAutoDrag;
           Exit;
         end;
         Include(FControlState, csLButtonDown);
       end;
     WM_LBUTTONUP:
       Exclude(FControlState, csLButtonDown);
   else
     with Mouse do
       if WheelPresent and (RegWheelMessage <> 0) and
         (Message.Msg = RegWheelMessage) then
       begin
         GetKeyboardState(KeyState);
         with WheelMsg do
         begin
           Msg := Message.Msg;
           ShiftState := KeyboardStateToShiftState(KeyState);
           WheelDelta := Message.WParam;
           Pos := TSmallPoint(Message.LParam);
         end;
         MouseWheelHandler(TMessage(WheelMsg));
         Exit;
       end;
   end;
 end
 else if Message.Msg = CM_VISIBLECHANGED then
   with Message do
     SendDockNotification(Msg, WParam, LParam);
 Dispatch(Message);//派发消息
end;
   这里主要讲讲Dispatch方法,它根据传入的消息调用消息的句柄方法,如果在组件类和它的父类都没有找到消息的处理句柄,Dispatch方法便会调用Defaulthandler(默认的消息处理方法),如下:
procedure TObject.Dispatch(var Message);
asm
   PUSH    ESI
   MOV     SI,[EDX]
   OR      SI,SI
   JE      @@default
   CMP     SI,0C000H
   JAE     @@default
   PUSH    EAX
   MOV     EAX,[EAX]
   CALL    GetDynaMethod
   POP     EAX
   JE      @@default
   MOV     ECX,ESI
   POP     ESI
   JMP     ECX

@@default:
   POP     ESI
   MOV     ECX,[EAX]
   JMP     DWORD PTR [ECX] + VMTOFFSET TObject.DefaultHandler//调用默认的消息处理方法
end;
   而默认的消息处理如下,在SYSTEM.PAS单元里:
procedure TObject.DefaultHandler(var Message);
begin
end;
     由以上代码看好像是没有任何处理过程,跟踪Object.DefaultHandler的汇编执行动作call dword ptr[ecx-$10],即调用Object.DefaultHandle,看看做何处理:
{Object.DefaultHandle}
Ret
Lea eax,[eax+$00]
即一个返回处理!

从最表面的Button.caption,我们走到了编译器层,可见所有东西都能找到它固有的原点!以caption的分析为基础,我们可以继续分析name属性和其它一些方法/函数。
希望我这篇‘散文’能给大家理出点头绪:)

WIN32下DELPHI中的多线程【深入VCL源码】(一) 线程的基础知识      线程的组成。线程有两部分组成。     1、一个是线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。     2、另一个是线程堆栈,它用于维护线程在执行代码时需要的所有函数参数和局部变量。     进程从来不执行任何东西,它只是线程的容器。线程总是在某个进程环境中创建的,而且它的整个寿命期都在该进程中。这意味着线程在它的进程地址空间 阅读详情

相关推荐

Delphi VCL TMS组件包8.0.9.0完整源码深度解析

简介:Delphi VCL TMS Component Pack 8.0.9.0是一款支持从Delphi 7到XE9的全版本兼容组件库,提供完整的源代码,广泛应用于图形界面开发。该组件包扩展了VCL功能,涵盖数据绑定、图表、网格、报表、导航及UI元素等丰富控件,显著提升开发效率与应用性能。通过源码分析,开发者可深入理解组件设计原理、优化机制与可复用架构,学习高效编程实践,适用于企业级应用开发与技术能力进阶。

weixin_32005771的博客 588

VCL源码分析方法论

   最近一段时间似乎流行源码分析:)我也来谈谈在过去一段时间里对VCL源码的分析方法方面的一点体会,本文将不探讨VCL类库的构架和设计模式方面的东本,只是以我们常见的控件属性/方法的实现过程作简单的说明,希望对初学者有所帮助VCL分析方法例:TButton.Caption属性的由来(本文仅以此献给DELPHI初学者)   用过一段时间DELPHI的朋友,都会对VCL源码感兴趣。本人也常常在各大论

cg1120的Blog 1198

TMS VCL UI Pack V10.5.0.0 源码分析与组件使用指南

安全外壳协议(SSH)是一种网络安全协议,用于在不安全的网络中为计算机之间提供安全的加密通信。它常用于远程登录和其它网络服务。libssh2.a是libssh2项目的C语言库,提供了实现SSH协议相关功能的API。SSH协议的重要性在于其提供了两台计算机之间的安全通道,保障数据传输过程中的安全和隐私。使用SSH,用户可以安全地执行远程命令,传输文件,甚至执行X11转发和端口转发。

weixin_28721743的博客 805

由VCL中的代码理解VCL中的消息处理机制

 Delphi,一个非常优秀的开发工具,拥有强大的可视化开发环境、面向组件的快速开发模式、优秀的VCL类库、快速的代码编译器、强大的数据库和WEB开发能力、还有众多的第三方控件支持...(此处省略x千字,既然大家都知道了,不浪费口水了 ^_^)说到VCL的优秀就不能不提到其对Windows消息及API的较全面和完美的封装,正因为如此开发者在大多数情况下甚至不需理会Windows消息处理的细节,

drawwingmap的日记本 1563

Delphi财务管理系统源码分析与实践

账户管理模块:此模块是系统安全的基石,包括用户的注册、登录、个人信息管理以及权限控制等功能。凭证管理模块:凭证管理模块是财务管理系统的核心,主要功能有凭证的录入、审核、查询、统计分析等。报表生成模块:报表是财务信息的重要表现形式,此模块提供各类报表的设计、生成和打印功能。ADO(ActiveX Data Objects)是一种提供了编程数据库访问的中间层的技术。它允许开发者使用统一的方式,通过编程语言如Delphi来访问不同类型的数据库。

weixin_32306683的博客 673

Delphi 7编程技术大全源码深度解析

除了基本数据类型外,Object Pascal允许程序员定义自定义数据类型。这包括枚举类型、子界类型、集合类型以及记录类型。自定义数据类型可以更精确地描述问题域的数据特征,有助于提高程序的可读性和易维护性。例如,枚举类型允许程序员定义一组命名常量,这在表示具有固定数目选项的变量时非常有用。子界类型为基本数据类型定义了一个范围限制,确保变量值保持在特定区间。集合类型表示一个有限的元素集,这些元素属于同一数据类型。记录类型则允许程序员组合不同数据类型的字段,从而创建复杂的数据结构。type。

weixin_30798867的博客 458

x264源码解读(二)- VCL和NAL那些事

今天我们继续来说一下x264结构中非常重要的属性annexb。 小贴士:在阅读这些经典的c库代码的时候,这些,这些大牛们都是会按照一些规范来进行编码,无论是ffmpeg(后面打算再开一个专栏)还是x264,他们结构体的成员还是变量,命名方式习惯采用“数据类型_变量名”,比如b_annexb,代表boolean型,即annexb是一个开关(flag)。 annexb如果为true,代表一个NALU的开始3位或者4位是start_code,所谓start_code没有逻辑意义,只是代表一个NALU的起始,或

下士闻道的专栏 1629

Delphi皮肤引擎SkinEngine V3.4.7完整源码实战解析

在现代软件界面开发中,Delphi皮肤引擎(SkinEngine.v3.4.7)扮演着不可或缺的角色。它通过将界面元素与视觉风格分离,实现应用程序外观的高度定制化与动态切换。皮肤引擎的核心功能包括:界面样式绑定、资源加载管理、控件状态映射及跨平台渲染适配。其广泛支持Delphi 7至最新11.x版本,兼容VCL与FMX框架,为开发者提供统一的UI开发体验。

weixin_35006125的博客 1164

VCL源码理解

1.TWriter对象 WriteBuffer是TWriter对象定义的私有方法,它的作用是将Writer 对象内部缓冲区中的有效数据写入流中,并将FBufPos置为0。FlushBuffer对象就是用WriteBuffer方法刷新缓冲区。 procedure TWriter.WriteBuffer; begin   FStream.WriteBuffer(FBuffer^, FBufPo

hrdzkj的专栏 637

Delphi界面设计器源码深度解析与实战开发

不要滥用,应该定义语义明确的专用事件类型:typeprivateprotectedpublicend;beginend;好处:- 语义清晰 ✅- 支持输入输出参数(如)✅- IDE 友好,支持智能提示 ✅Delphi 的强大,从来不只是语法糖或控件多,而是整套RAD 生态的精密协同。从TObject的 RTTI 到TComponent的 Owner 管理,从的双指针结构到closure。

weixin_35749545的博客 658

VLC播放器的源代码

VLC开源播放器,支持各种常见多媒体的播放,支持IPTV领域的流媒体协议,支持DVB MHEG等标准,对多媒体领域的开发人员来说极有帮助。其中界面部分是QT编程,也适合学习QT。

VCL源码分析方法论 cg1120(原作)

最近一段时间似乎流行源码分析:)我也来谈谈在过去一段时间里对VCL源码的分析方法方面的一点体会,本文将不探讨VCL类库的构架和设计模式方面的东本,只是以我们常见的控件属性/方法的实现过程作简单的说明,希望对初学者有所帮助VCL分析方法例:TButton.Caption属性的由来(本文仅以此献给DELPHI初学者)   用过一段时间DELPHI的朋友,都会对VCL源码感兴趣。本人也常常在各大论坛见到

浪子的窝 1083

delphi 《深入核心——VCL架构剖析》配套源码

李维的 delphi 《深入核心——VCL架构剖析》配套的光盘源码。

VCL分析方法

最近一段时间似乎流行源码分析:)我也来谈谈在过去一段时间里对VCL源码的分析方法方面的一点体会,本文将不探讨VCL类库的构架和设计模式方面的东本,只是以我们常见的控件属性/方法的实现过程作简单的说明,希望对初学者有所帮助VCL分析方法例:TButton.Caption属性的由来(本文仅以此献给DELPHI初学者)    用过一段时间DELPHI的朋友,都会对VCL源码感兴趣。本人也常常在各大论

Qi_jianzhou的资料室 911

vlc播放器源代码

开源播放器vlc的源代码,完整版,最新。

VCL.DotNet源码

VCL.DotNet源码VCL.DotNet源码VCL.DotNet源码VCL.DotNet源码VCL.DotNet源码

VCL 中TList源码分析

TList 源码分析TPointerList = array[0..MaxListSize - 1] of Pointer;TList 的本质就是个无类型指针的数组TList = class(TObject) private FList: PPointerList; FCount: Integer; FCapacity: Integer; protected...

weixin_30755709的博客 117

CMU的local_planner学习笔记

ros::Subscriber subOdometry = nh.subscribe//当接收到/state_estimation话题消息更新时启动odometryHandler回调函数 (消息格式:nav_msgs::Odometry消息内容:关于机器人或车辆的位置和方向(姿态)信息)pcl::PointCloud::Ptr freePaths(new pcl::PointCloud());

qq_35971623的博客 3878

dapr源码分析--injector

在阅读dapr injector源码之前,需要知道k8s的动态准入控制原理,否则无法理解代码的功能。

cbmljs的博客 996

SkillClaw:让大模型 Agent skill在多用户生态中实现群体进化的框架

随着大模型应用步入深水区,基于 LLM 的智能体(Agent)正从单一的“沙盒玩具”转变为处理真实世界复杂任务的生产力工具。然而,现有的 Agent 系统通常面临一个致命瓶颈——部署即固化。为了解决这一问题,最近有一篇新论文**《SkillClaw: Let Skills Evolve Collectively with Agentic Evolver》**提出了一种多用户生态 Agent 群体进化框架。

kakaZhui的博客 264

数字信号处理(一):Xilinx Vivado DDS IP核设计实例(文末附源码)

前言 在数字信号处理时我们经常会用到数字变频,包数字下变频(DDC)和数字上变频(DUC),这其中会用到Xilinx公司的DDS IP核或者Altera公司的NCO IP核来产生本振频率,以现数字域信号频谱搬移。本文我们通过例化Xilinx公司的DDS IP核来产生混频器本振输入频率,并给出Modelsim仿真测试结果。 1、Xilinx DDS IP简介 Xilinx公司的DDS IP核使用AX...

FPGA_Designer 1万+
上一篇: 谁说Delphi没有哈希
下一篇: 取得Word 表格中的数据
iseekcode
博客等级 码龄18年 36粉丝 14原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值