一个简单组件的制作过程——delphi教程
接下来要动手来做一个组件了,我想了一个计数器组件,功能方面是比较简单的,但这不是本章的重点,这一章的重点是说明一个组件的制作全过程。在其中可以学到很多组件制作的技巧,当然这些也是我从书上学得的。好了,开始制作吧:   这是一个可以计数的组件,为了简单,我以秒为单位,当开始时,他就从0开始增加,并显示出来,到3600时,它又回到0,如此循环。当然它也可以停止,暂停,继续。另外,他还有一个时间事件,即可以设定每隔多少时间来触发这个事件,这倒是一个好的功能,我们可以设半个小时触发事件,在事件处理函数中来一个声音,然后睡个觉,半个小时后,就由这个声音来提醒你起床了。   我们一开始不要新建组件单元,而是把它当成一个工程中的一个类来应用,这样更易于调试,于是我们新建一个工程,又新建一个空白单元用于放置这个类   一,确定父类:   接下来给这个类起名叫TTimeCount,那么它的父类应该是什么呢,它要能显示出来,得有一个容量来让他显示,TPanel是个不错的选择,我看了一下源码,发觉TPanel什么也没有做,只是把它的父类TCustomPanel的属性显化出来(这个等一下讲),TCustomPanel把好多的属性声明为Protected,为他的子类提供了选择,他的子类如果要使这些属性能在对象察看器中看到,可以在Published重新声明一下,如果不想,则不用去理会他。而我们的计数器组件正好不用那么多属性,正好合适。于是我决定用TCusomPanel为父类 类建立如下: TTimeCount=class(TCustomPanel)   private   protected   public   published end;   二,确定成员,方法和属性和事件   FCount; 只读私有成员,保存计数值 FActive:Boolean; /确定是否发生类的时间间隔事件 FInterval:TInterval; 这个可以设置时间事件触发间隔,本来用整型值会好一些,但会了学习起见,这里用了一个枚举形的,在Type中声明如下: TInterval=(TenM,TwentyM,ThirtyM,FortyM,FiftyM,SixtyM); 分别表示十分钟到六十分钟。 TimeLen,TimeNum:integer;这两个用在类的时间事件发生的确定上,与外界隔绝。 FTimeOut:TNotifyEvent;时间间隔事件的方法指针,通过调度方法实现他与外部的处理函数关联。   我们要它能以秒为单位来计数,则要涉及到时间的应用,所以就有了这个最重要的成员: FTimer:TTimer; 这个成员对象要在类构造函数中实例化它,并赋与他的属性值,还要在析构函数在释放它。 如下:   //构造函数,继承父类的构造函数,并初始化类中的成员。 constructor TTimeCount.Create(AOwner:TComponent); //创建时间控件并设置相关的参数   procedure CreateTimer;   begin       FTimer:=TTimer.Create(self);       FTimer.Enabled:=False;       FTimer.Interval:=1000;       FTimer.OnTimer:=FTimerTimer;   end; begin   inherited Create(AOwner);   CreateTimer; end; //析构函数,先释放时间控件,再继承父类的析构函数 destructor TTimeCount.Destroy; begin   FTimer.Free;   inherited Destroy; end; 构造函数中还要设置该组件的外观和默认值,这里把它删去,到源代码再贴出来。 其中 FTimerTimer;是很重要的函数,在该类中有声明: procedure FTimerTimer(Sender:Tobject);//时间控件的事件处理函数 在这个处理函数中,实现了计数值的递增并显示到容器中,此外,还在判断类的时间事件是否有足够条件触发了,如果有则调用DoTimeOut;过程,这个就是事件的调度函数啦: //事件调度函数,将外部的事件处理函数和该类的事件方法指针联系起来 procedure TTimeCount.DoTimeOut; begin   if Assigned(FTimeOut) then      FTimeOut(Self); end;   而属性则是根据私有成员来设定了: public property Count:Integer read FCount default 0; //计数值的只读属性,这个属性不能声明在Published中,因为它是只读的,只在程序运行时通过它来得到计数值。 published     property Interval:TInterval read FInterval write SetInterval Default TenM;     property Active:boolean read FActive write SetActive default false;     property OnTimeOut:TNotifyEvent read FTimeOut write FTimeOut;   此外还有几个自定义方法即 procedure pause; //暂停计数 procedure Resume;//从暂停的计数开始计数。 procedure stop;//停止 procedure start;//开始计数 都比较简单。   三,父类属性的显化:   TCustomPanel及其父类有好多的属性设为Protected,使其子类可以有更灵活的选择,是否把这些属性显示到对象察看器中,如果想,则到Published中重新声明这些属性就可以,我参考了一下TPanel的源码,并按需要选择了其中的一些属性声明到Published中,注意哦,事件也是属性,只要你把它显化出来,就可以设置处理事件了。   四.以下是计数组件的源码,相信有了上面的讲解,应该不会很难了:   unit CountUnit;   interface   uses   SysUtils,Classes,Graphics,Controls,ExtCtrls;   type //用于设置时间事件发生的间隔   TInterval=(TenM,TwentyM,ThirtyM,FortyM,FiftyM,SixtyM);     TTimeCount=class(TCustomPanel)   private     FTimer:TTimer;     FCount:integer;  //只读私有成员,计数值     FInterval:TInterval; //时间事件发生的间隔     FActive:Boolean; //决定是否发生间隔事件     TimeLen:Integer;//发生事件的时间长度,以秒为单位。     TimeNum:integer;//计数值,和TimeLen一起有用,以判断是否事件该发生了     FTimeOut:TNotifyEvent;//事件的方法指针     procedure SetInterval(I:TInterval);     procedure SetActive(A:boolean);     procedure FTimerTimer(Sender:Tobject);//时间控件的事件处理函数   protected     procedure DoTimeOut;dynamic; //调度方法,用于关联事件。   public     procedure pause; //暂停计数     procedure Resume;//从暂停的计数开始计数。     procedure stop;//停止     procedure start;//开始计数     constructor Create(AOwner:TComponent);override;     destructor  Destroy;override;     property Count:Integer read FCount; //计数值的只读属性   published     property Interval:TInterval read FInterval write SetInterval Default TenM;     property Active:boolean read FActive write SetActive default false;     property OnTimeOut:TNotifyEvent read FTimeOut write FTimeOut;     //显式祖先类的一些属性在对象察看器中     property BevelInner;     property BevelOuter;     property BevelWidth;     property Color;     property Font;     property PopupMenu;     property ShowHint;     property TabOrder;     property TabStop;     property Visible;     property OnClick;     property OnDblClick;     property OnMouseDown;     property OnMouseMove;     property OnMouseUp;   end;   implementation //构造函数,继承父类的构造函数,并初始化类中的成员。 constructor TTimeCount.Create(AOwner:TComponent); //创建时间控件并设置相关的参数   procedure CreateTimer;   begin       FTimer:=TTimer.Create(self);       FTimer.Enabled:=False;       FTimer.Interval:=1000;       FTimer.OnTimer:=FTimerTimer;   end; //以下是设置外观的   procedure setView;   begin     Width:=100;     Height:=50;     Color:=$000000;     Font.Color:=$FFFFFF;     Font.Size:=14;     Font.Style:=[fsBold,fsUnderline];;     BevelOuter := bvLowered      ;     Caption:=0;   end; begin   inherited Create(AOwner);   FCount:=0;   FInterval:=TenM;   FActive:=False;   TimeLen:=600;//十分钟,六百秒   TimeNum:=0;   CreateTimer;   setView; end; //析构函数,先释放时间控件,再继承父类的析构函数 destructor TTimeCount.Destroy; begin   FTimer.Free;   inherited Destroy; end; //设置时间事件发生间隔,财时要赋相应的间隔秒数 procedure TTimeCount.SetInterval(I:TInterval); begin   if FInterval<>I then   begin     FInterval:=I;     case FInterval of     TenM: TimeLen:=600;     TwentyM:TimeLen:=1200;     ThirtyM: TimeLen:=1800;     FortyM: TimeLen:=2400;     FiftyM:TimeLen:=3000;     SixtyM:TimeLen:=3600;     end;   end; end;   procedure TTimeCount.SetActive(A:boolean); begin   if FActive<>A then   begin       FActive:=A;       TimeNum:=0;   end; end;   procedure TTimeCount.pause; begin  if FTimer.Enabled then   FTimer.Enabled:=False; end;   procedure TTimeCount.Resume; begin   if not FTimer.Enabled then     FTimer.Enabled:=True; end;   procedure TTimeCount.stop; begin   FTimer.Enabled:=False;   FCount:=0;   TimeNum:=0;   caption:=0 end;   procedure TTimeCount.start; begin   if (not FTimer.Enabled)and(TimeNum=0) then      FTimer.Enabled:=True; end;   //最重要的时间函数,用于调用该类的事件触发高度函数。 //以及在容器中显示计数值 procedure TTimeCount.FTimerTimer(Sender:TObject); begin   inc(FCount);   if (FCount mod 3600)=0 then FCount:=0;   Caption:=InttoStr(FCount);//这个就是显示计数值   inc(TimeNum);   if (TimeNum=TimeLen)and(FActive) then   begin        DoTimeOut;        TimeNum:=0;   end; end; //事件调度函数,将外部的事件处理函数和该类的事件方法指针联系起来 procedure TTimeCount.DoTimeOut; begin   if Assigned(FTimeOut) then      FTimeOut(Self); end;   end.   五,组件注册安装与删除。   组件类编写完毕,接着就要测试了,这个从略,可以在刚才的工程中动态创建它,设置相应属性,指定时间事件,看看是否正确。上面是经过测试的。 到确定正确后,就要来看看装组件的步骤了:   首先,我们要把组件单元放在一个指定的文件夹中,以便以后管理,和IDE统一指定路径。 我在Delphi目录下新建了MyCom文件夹,用来存放组件单元 然后选: Component?>New Component;  启动Component Wizard 在Ancestor type(父类):中填TCustomPanel Class Name(你的组件类名)中填:TimeCount Palette Page,默认为Samples,我就用这个吧,当然也可以自己创建一个。 Unit File Name(组件类所在的单元名),就写TimeCount吧。 Search Path(搜索路径),必须把上面所建的文件夹路径包含进去,编译时才能能过。                       点击旁边的”…”按钮,出现一个对话框,里面的编辑框旁边又有一个”…“按钮,点击它出现浏览文件夹框,在其中选中上面建的文件夹的路径,点确定,再点OK,回去New Component;。                       这时再点下面的OK就行啦,出现代码如下: unit TimeCount;   interface   uses  messages, SysUtils,Classes,Graphics,Controls,ExtCtrls;   type   TTimeCount=class(TCustomPanel)   private   published   public   published      end;   procedure Register;   implementation   procedure Register; begin   RegisterComponents(Samples, [TTimeCount]);  //注册控件用的函数,自动帮你生成 end; end. 这时再把上面的组件类替换掉这个类就行啦(当然上面的注册函数可要保留呀)。然后保存到上面所建的文件夹中。   接着就要安装组件了,点Component->install Component 对话框中第一项Unit file Name,是组件单元.pas文件的路径名字。其他只要按缺省。            记得第三项的。。\delphi7\Lib\dclusr.dpk,这个就是存放组件的包名,等一下删除组件时用到的                    接下来点OK,就可以了,看看Samples是不是有了一个新组件啦。                       不过面板上的组件图标似乎不好看,应该给他一个新的图标了:  但之前应该把它先从面板删除,File->Open…打开dclusr.dpk. 选中其中的Contains下的TimeCount.pas,点上面的Remove。将其删除 然后再点Compile,重新将包编译一次。就行啦。Samples上的新组件就消失了。   接下来是做组件图标: 打开Image Eidtor,新建一个DCR文件,在其中建一个24×24的位图,画上你喜欢的图标,将位图的名字起为组件类名一样,而且用大写,即:TTIMECOUNT 将DCR文件起名为组件类所在单元名一样,而且大写,即:TIMECOUNT。 保存文件到单元所在的文件夹中, 最后依上面的方法再装一次,看是不是有一个漂亮的图标啦     六,讲完了,大家应该有一个清楚的概念了吧,其中涉及到了好多的技巧。在以后的篇章中将不再讲这些内容了,只把主要精力花在组件实现技术上。因为我们这个组件还是比较简单,没有涉及到多少高级的主题。但没有关系,跟着我慢慢地做下来,你们会了解组件制作的方方面面的。

推荐文章

WEB微信协议详注(待续)

        当初写微信机器人也是为了个红包,虽然红包拿到了,过程还是蛮有意思的,下面给下详细说明。         微信入口主要有两个(wx和wx2),wx老号   wx2新号,我微信是老号了,为了测试方便采用

推荐文章

反转整数-正确的方法

A common algorithm problem is to reverse a positive integer: turn 12345 into 54321. At first glance, this problem may seem pretty easy--turn the integer into a string, then an array, reverse the array

推荐文章

从SVN上下载的web项目包变成文件夹的解决办法

1、从SVN上下载的项目可能会变成这样,成为一个个的文件。很纠结     2、出现这个情况的大多数原因是由于冲突,   这个.classpath文件和.project文件发生冲突的原因造成的。  

推荐文章

bashrc文件中环境变量配置错误,导致linux无法正常使用的解决方案

其实解决问题的方法很简单:把你在bashrc文件中写错的东西注释掉或者改写正确即可。 可是此时图形界面登陆不了,vim用不了。怎么改? 解决方案:      步骤1:输入命令 export  PATH = /bin:/usr /l

推荐文章

手把手教你:安装svn出现could not write value to key的错误

原因:360等杀毒软件没有关闭 解决方法:关闭360安全卫士,各种杀毒软件,再进行安装

推荐文章

Eclipse中的Maven项目报Unbound classpath variable错误

    今天更新了最新版的Eclipse luna 4.4版本,svn更新了项目后,系统一直报错,经查看在Problems窗口中发现一堆错误,提示如下:     Unbound classpath variable: 'M2_REPO/aopalliance/aopalliance/1.

推荐文章

myeclipse 8.5 安装svn

link安装  安装subclipse, MyEclipse8.5 SVN插件  1、从官网下载site-1.6.9.zip文件,网址是:subclipse.tigris.org,  2、从中解压出features与 plugins文件夹,复制到E:MyEclipsemyPluginsvn里面,其

推荐文章

[Tips]在 MacOS 中将 mysql 添加到环境变量

1.打开终端: vim ~/.bash_profile 2.点击 'i' 进入输入模式,将光标移到文件结尾,添加mysql命令所在的路径: export PATH=$PATH:/usr/local/mysql/bin 3.点击 'esc' ,输入如下命令保存并退出: :w

推荐文章

Linux中vi的环境设置和其他常用设置

下面是我的vi的习惯设置和两点环境变量的设置,记录在此,方便查阅。 cd到家目录下,注意一定是在当前用户的家目录下,这样设置的vi环境只对该用户有效,当然,还可以有全局的vi设置,这样设置的环境就对每个用户都有效。 vi .vimrc set nu   显示行号 set tabstop=4   设置tab键的宽

推荐文章

ctags在无权限时的配置

在有些情况下,我们是没有权限在我们的电脑上面安装ctags的,但是我们也可以寻找一种简单的”安装“方式。 下面我就简单的介绍一下如何处理这种最后make install安装权限不够的问题, (1),下载一个源码包,解压。 (2),进入到解压以后的解压包里面。 (3),执行命令:./configure (4),执行命令:make (5

推荐文章

Eclipse使用:编译指定的文件

从svn下载下来的项目,项目中会含有.svn文件目录,这个是svn的服务文件,使用eclipse编译项目时会把src目录下的.svn文件复制到classes目录中,再更新classes目录就会报错,是由于svn地址指向错误导致的,若开发的是web项目,经常会整体更新WebRoot目录,就要经常手动的去删掉classes目录后才能正常更新而不会报

推荐文章

linux下SVN的使用

1.将SVN上你想要的文件checkout到你的本机电脑 命令行:svn  checkout   http://192.118.12.** 2.将你想要上传的文件夹上传到SVN上 命令行:svn add   path+文件名 3.上传 命令行:svn commit path+文件夹

推荐文章

安装交叉编译器

1.下载arm-linux-gcc-4.5.1.tgz.. 2.在usr/local目录下建立新文件 mkdir arm 然后把arm-linux-gcc-4.5.1.tgz.复制到此目录下然后解压   3.解压 arm-linux-gcc-4.5.1.tgz   #tar -zxvf arm-linux-gcc-4.5.1.tg

推荐文章

svn ***** already locked

svn提交class报告already clocked警告 解决办法:在要提交的类、包或者项目上点击右键,点击Refresh/Clearup,然后就可以完成提交。

推荐文章

Ubuntu 用/ect/profile文件配置JAVA环境变量

打开终端  :vim /etc/profile 添加的代码如下: 这段代码添加的位置在: if [ -d /etc/profile.d ]; then   for i in /etc/profile.d/*.sh; do     if [ -r $i ]; then  

推荐文章

Ubuntu下搭建java环境

在Ubuntu下搭建java环境主要分为两大步骤:(和window下是一样的) 1.安装jdk 2.配置环境变量 安装jdk: 下载安装 首先打开终端输入:java -version看当前的jdk版本,如果是系统自带的openjdk,先卸载,然后在执行以下。卸载命令:sudo apt-get purge openjdk* 1