您好,欢迎访问三七文档
当前位置:首页 > 建筑/环境 > 工程监理 > 通过实例看VCL组件开发全过程
通过实例看VCL组件开发全过程这篇文章算是对我前段时间学习的一个学习总结,以及对自己学习过程的一个回顾。本文通过一个简单的例子来尽可能的展示VCL组件开发的各个方面,本文针对即将学习组件开发的初学者,如果你已经熟悉组件开发或认为本文内容过于基础简单,那么本文对你毫无用处。阅读本文,假设你已经熟悉delphi的普通程序设计以及vcl的结构层次,还有一些重要的关键字:published、property等。(注:本文内容建立在delphi5.0及以上版本)在这篇文章中我们将建立一个和时间有关的组件,这个组件通过设置它的不同状态有以下基本功能:1、显示系统的当前时间(包括设置闹钟)。2、跑表。3、倒计时。这是一个简单的例子,然而我们将在这个例子中尽可能多的用到delphi在组件开发中的多种特性,你可以通过以下列举出的本文涉及特性有选择的阅读:·组件和组件包·组件的属性类别·组件的属性编辑器·组件编辑器一、组件和组件包,以及一些你应该知道的文件类型:组件和组件包的关系就如同普通工程中unit和工程文件的关系一样,通常你所安装的组件都是以组件包的形式发布的,一个组件包中可以有很多个组件,在组件开发中,组件包就是项目的工程文件.为了开始开发我们的组件(我们把他叫做TClock)并将它包括在我们自己的组件包(ClockPackage)中,我们选择Fileànewàother在弹出的窗口中的New页选择Package新建一个组件包,得到一个组件包窗口,查看这个组件包的原文件(.dpk),得到以下代码:packageClockPackage;{$R*.res}{$ALIGN8}{$ASSERTIONSON}…….…….{$DESCRIPTION'OurClockPack'}{$IMPLICITBUILDOFF}requiresrtl;end.这个文件其实就是组件开发中的工程文件,requires关键字指示了组件包所需组件包的列表,随着向组件包中加入组件(类似于单元文件),你还会看到contains关键字,指示了组件包所包含的组件,你可以通过组件包窗口中的add和remove按纽来添加新的组件和删除已有的组件。另外这个代码中所包含的大量的编译器开关大多都可以在组件包窗体上的Options中设置。这里需要补充说明的是组件包的3种重要属性(都在Options中):DesigntimeOnly、RuntimeOnly、Designtimeandruntime(这3个词的意思有英语基础的朋友应该都知道吧),对于大多数的组件包我们只要选择最后一个就可以了,然而有些组件包设计为只运行时(这样你用这套组件开发的程序不能脱离组件而单独运行,组件包也不能被安装),有些组件包被设计为只设计时(这将在后文有更详细的说明)。了解了组件和组件包,我们对组件开发中可能出现的一些你没有见过的文件做一些说明:dpk文件既组件包的原代码;bpl文件,组件包编译后的结果,在没有发布dpk的情况下可以通过bpl来安装组件包到delphi(ProjectàOptionsàPackagesàadd);pas在这里就是组件包中组件的原代码了;dcu为pas编译后的结果,在你选择将组件包含进组件包时(contains关键字),你可以选择发布原代码或是不发布(dcu文件);dcp如果你将组件作为运行时组件,连接器将使用该文件。二、开始开发组件:了解了上面的知识后,我们就可以开始开发组件了!在组件窗体中单击add,选择NewComponent页,在第一个组合框中选择我们的组件将要继承自哪个类(通常新的组件是通过继承已有的组件来开发的),由于这个组件的主要作用是要显示时间、跑表、倒计时种的文字信息,所以我们选择继承自TCustomLabel(由于我们并不需要Tlabel的全部功能,我们选择了能够隐藏Tlabel属性并有选择的发布它的属性的TcustomLabel类)。接下来为我们的新组件取一个名字Tclock,然后指定我们想把组件安装到哪一个页中,这里我们自己键入一个ClockAndTime页,这将出现在RegisterComponents过程中(后面会详细说明),选择好文件保存的路径后(最好把它和组件dpk包放在同一目录)确认。这是组件包窗体中的contains下已经多了我们刚才建立的组件的文件,双击它开始编写代码。在代码中我们需要注意在interface部分的一个新的过程:procedureRegister;(注意:delphi规定Register的R必须大写,这是一个保留字),这个过程是作为每一个组件所必须有的,它完成组件的注册,包括组件本身以及如属性编辑器等多种组件特性的注册):procedureRegister;beginRegisterComponents('ClockAndTime',[TClock]);//这个过程注册组件本身,注意到前面定义的ClockAndTime页了吗?//这里在后面还会出现一些新的过程,包括注册组件的属性类别等等。end;在下一篇中我们将给出这个组件的全部原代码。(未完待续)(接上文)组件的代码由于假设你已经熟悉delphi开发(它和一般开发没什么不同),我们就直接贴出来并加上适当的注释:unitClock;interfaceusesSysUtils,Classes,Controls,StdCtrls,ExtCtrls;typeTState=(StClock,StRunClock,StBackClock);//定义枚举类表示控件的3种状态:时钟、跑表、倒计时钟TClock=class(TCustomLabel)privatefState:TState;fTimer:TTimer;//为什么使用这个组件作为我们组件的私有成员就不用说了吧RCD:array[1..8]ofinteger;//跑表中的各个数位。fBeginTime:string;//到计时时的开始时钟,之所以没用TTime类型是为了在后面演示属性编辑器fWakeTime:string;//闹钟时间,出于和上面同样的理由fAllowWake:boolean;//是否开启闹钟功能fOnWakeUp:TNotifyEvent;//为了使组件更加完美,我们允许组件用户能够响应闹钟到来时的时件fOnTimeUp:TNotifyEvent;//同上能够响应倒计时种完成时的事件,我们将发布这两个事件functionGetActive:boolean;//控制Timer是否工作以控制3种状态的钟是否工作procedureSetActive(Value:boolean);procedureSetState(Value:TState);procedureSetBeginTime(Value:string);procedureSetWakeTime(Value:string);protectedprocedureWalkClock(sender:TObject);//作为时钟时走种的事件procedureRunClock(sender:TObject);//跑表procedureBackClock(sender:TObject);//倒计时publicconstructorCreate(AOwner:TComponent);override;//完成一些初始化工作procedureReSetRunClock;//跑表和倒计时都需要一个复位方法给组件使用者调用procedureReSetBackClock;publishedpropertyState:TStatereadfStatewriteSetStatedefaultStClock;//默认为时钟状态propertyActive:booleanreadGetActivewriteSetActive;//控制3种状态的钟是否工作propertyBeginTime:stringreadfBeginTimewriteSetBeginTime;propertyWakeTime:stringreadfWakeTimewriteSetWakeTime;propertyAllowWake:booleanreadfAllowWakewritefAllowWake;propertyOnWakeUp:TNotifyEventreadfOnWakeUpwritefOnWakeUp;propertyOnTimeUp:TNotifyEventreadfOnTimeUpwritefOnTimeUp;//最后我们再发布一些被TCustomLabel所隐藏而我们又需要的属性propertyAlign;propertyAlignment;propertyColor;propertyFont;propertyParentColor;propertyParentFont;propertyParentShowHint;propertyPopupMenu;propertyShowHint;propertyVisible;propertyTransparent;propertyOnClick;end;procedureRegister;implementationprocedureRegister;beginRegisterComponents('ClockAndTime',[TClock]);end;{TClock}constructorTClock.Create(AOwner:TComponent);begininheritedCreate(AOwner);//设置默认值fTimer:=TTimer.Create(self);//将它属于我们的组件,这样便不用编写析构函数,而可以自动在释放本组件时释放TimerActive:=false;AllowWake:=false;State:=StClock;BeginTime:='00:00:00';WakeTime:='00:00:00';end;functionTClock.GetActive:boolean;beginresult:=fTimer.Enabled;end;procedureTClock.SetActive(Value:boolean);beginfTimer.Enabled:=Value;end;procedureTClock.SetState(Value:TState);vari:integer;begincaseValueofStClock:beginActive:=false;fTimer.Interval:=1000;fTimer.OnTimer:=WalkClock;Active:=true;end;StRunClock://由于Time类型不好处理微秒操作,我们只有手工模仿这个操作,代码会稍微烦琐beginActive:=false;fori:=1to8doRCD[i]:=0;Caption:=IntToStr(RCD[8])+IntToStr(RCD[7])+':'+IntToStr(RCD[6])+IntToStr(RCD[5])+':'+IntToStr(RCD[4]);Caption:=Caption+IntToStr(RCD[3])+':'+IntToStr(RCD[2])+IntToStr(RCD[1]);fTimer.Interval:=10;//经过测试,这个秒表的效果很好,然而这只是一个技术上的演示,//实际上这么频繁(1/100秒)的不断执行RunClock会使CPU的占用一直达到100%//这并不是一个好注意。事实上要想在跑表中显示微秒级别并做到合理的占用CPU//这需要更加灵活和复杂的编程fTimer.OnTimer:=RunClock;end;StBackClock:beginActive:=false;Caption:=BeginTime;fTimer.Interval:=1000;fTimer.OnTimer:=BackClock;end;end;fState:=Value;end
本文标题:通过实例看VCL组件开发全过程
链接地址:https://www.777doc.com/doc-5268615 .html