通过实例看VCL组件开发全过程(二) (转)

通过实例看VCL组件开发全过程(二) (转)[@more@]

(接上文)

组件的代码由于假设你已经熟悉Delphi开发(它和一般开发没什么不同),我们就直接贴出来并加上适当的注释:

 XML:namespace prefix = o ns = "urn:schemas-microsoft-com:Office:office" />

unit Clock;

 

interface

 

uses

  SysUtils, Classes, Controls, StdCtrls,ExtCtrls;

 

type

  TState=(StClock,StRunClock,StBackClock);//定义枚举类表示控件的3种状态:时钟、跑表、倒计时钟

 

  TClock = class(TCustomLabel)

  private

  fState:TState;

  fTimer:TTimer;//为什么使用这个组件作为我们组件的私有成员就不用说了吧

  RCD:array[1..8] of integer;//跑表中的各个数位。

  fBeginTime:string;//到计时时的开始时钟,之所以没用TTime类型是为了在后面演示属性编辑器

  fWakeTime:string;//闹钟时间,出于和上面同样的理由

  fAllowWake:boolean;//是否开启闹钟功能

  fOnWakeUp:TNotifyEvent;//为了使组件更加完美,我们允许组件用户能够响应闹钟到来时的时件

  fOnTimeUp:TNotifyEvent;//同上能够响应倒计时种完成时的事件,我们将发布这两个事件

  function GetActive:boolean;//控制Timer是否工作以控制3种状态的钟是否工作

  procedure SetActive(Value:boolean);

  procedure SetState(Value:TState);

  procedure SetBeginTime(Value:string);

  procedure SetWakeTime(Value:string);

  protected

  procedure WalkClock(sender:Tobject);//作为时钟时走种的事件

  procedure RunClock(sender:TObject); //跑表

  procedure BackClock(sender:TObject);//倒计时

  public

  constructor Create(AOwner:TComponent);override;//完成一些初始化工作

  procedure ReSetRunClock; //跑表和倒计时都需要一个复位方法给组件使用者调用

  procedure ReSetBackClock;

  published

  property State:TState read fState write SetState default StClock;//默认为时钟状态

  property Active:boolean read GetActive write SetActive;//控制3种状态的钟是否工作

  property BeginTime:string read fBeginTime write SetBeginTime;

  property WakeTime:string read fWakeTime write SetWakeTime;

  property AllowWake:boolean read fAllowWake write fAllowWake;

  property OnWakeUp:TNotifyEvent read fOnWakeUp write fOnWakeUp;

  property OnTimeUp:TNotifyEvent read fOnTimeUp write fOnTimeUp;

  //最后我们再发布一些被TCustomLabel所隐藏而我们又需要的属性

  property Align;

  property Alignment;

  property Color;

  property Font;

  property ParentColor;

  property ParentFont;

  property ParentShowHint;

  property PopupMenu;

  property ShowHint;

  property Visible;

  property Transparent;

  property OnClick;

  end;

 

procedure Register;

 

implementation

 

procedure Register;

begin

  RegisterComponents('ClockAndTime', [TClock]);

end;

 

{ TClock }

 

constructor TClock.Create(AOwner: TComponent);

begin

  inherited Create(AOwner);

  //设置默认值

  fTimer:=TTimer.Create(self);

  //将它属于我们的组件,这样便不用编写析构函数,而可以自动在释放本组件时释放Timer

  Active:=false;

  AllowWake:=false;

  State:=StClock;

  BeginTime:='00:00:00';

  WakeTime:='00:00:00';

end;

 

function TClock.GetActive: boolean;

begin

 result:=fTimer.Enabled;

end;

 

procedure TClock.SetActive(Value: boolean);

begin

 fTimer.Enabled:=Value;

end;

 

procedure TClock.SetState(Value: TState);

var

 i:integer;

begin

 case Value of

  StClock:

  begin

  Active:=false;

  fTimer.Interval:=1000;

  fTimer.OnTimer:=WalkClock;

  Active:=true;

  end;

  StRunClock://由于Time类型不好处理微秒操作,我们只有手工模仿这个操作,代码会稍微烦琐

  begin

  Active:=false;

  for i:=1 to 8 do RCD[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:

   begin

  Active:=false;

  Caption:=BeginTime;

  fTimer.Interval:=1000;

  fTimer.OnTimer:=BackClock;

  end;

 end;

 fState:=Value;

end;

 

procedure TClock.SetBeginTime(Value: string);

begin

  try

  StrToTime(Value);

  fBeginTime:=Value;

  if State=StBackClock then

  begin

  Active:=false;

  Caption:=Value;

  end;

  except

  on Exception do

  begin

  fBeginTime:='00:00:00';

  if State=StBackClock then Caption:='00:00:00';

  end;

  end;

end;

 

procedure TClock.SetWakeTime(Value: string);

begin

 try

  StrToTime(Value);

  fWakeTime:=Value;

  except

  on Exception do

  begin

  fWakeTime:='00:00:00';

  end;

  end;

end;

 

procedure TClock.WalkClock(sender: TObject);

begin

 Caption:=TimeToStr(Time);

 if AllowWake and (StrToTime(Caption)=StrToTime(WakeTime)) then

 begin

  Beep;//蜂鸣器

  if Assigned(fOnWakeUp) then

  fOnWakeUp(self);

 end;

end;

 

procedure TClock.RunClock(sender: TObject);

begin

 RCD[1]:=RCD[1]+1;

 if RCD[1]=10 then begin RCD[2]:=RCD[2]+1;RCD[1]:=0; end;

 if RCD[2]=10 then begin RCD[3]:=RCD[3]+1;RCD[2]:=0; end;

 if RCD[3]=10 then begin RCD[4]:=RCD[4]+1;RCD[3]:=0; end;

 if RCD[4]=6 then begin RCD[5]:=RCD[5]+1;RCD[4]:=0; end;

 if RCD[5]=10 then begin RCD[6]:=RCD[6]+1;RCD[5]:=0; end;

 if RCD[6]=6 then begin RCD[7]:=RCD[7]+1;RCD[6]:=0; end;

 if RCD[7]=10 then begin RCD[8]:=RCD[8]+1;RCD[7]:=0; end;

 if RCD[8]=10 then RCD[8]:=0; //我们的跑表最多可计99个小时;

 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]);

end;

 

procedure TClock.BackClock(sender: TObject);//可以在一天之类的时间倒计时

begin

 if StrToTime(Caption)<>StrToTime('00:00:00') then

  Caption:=TimeToStr(StrToTime(Caption)-0.00001)

 else

 begin

  Active:=false;

  Beep;

  if Assigned(fOnTimeUp) then

  fOnTimeUp(self);

 end;

end;

 

procedure TClock.ReSetBackClock;

var

 i:integer;

begin

 if State=StRunClock then

 begin

  Active:=false;

  for i:=1 to 8 do RCD[i]:=0;

  Caption:='00:00:00:00';

 end;

end;

 

procedure TClock.ReSetRunClock;

begin

 if State=StBackClock then

 begin

  Active:=false;

  Caption:=BeginTime;

 end;

end;

 

end.

 

为了测试我们的组件,现在你就可以安装这个组件包并建立一个应用测试它了,点击组件包窗体中的install即可(注意:一但你安装了组件包,当你想对组件修改时,在修改了原代码以后只用点击组件窗体的compile就可以了更新组件了),这时delphi的组件页的最后多出了我们定义的页,其中有了我们的组件!

然而这个组件到目前为止仍然不够完善,还不能正式发布给用户,在下一篇中我们将解决两个重要的问题:1、给我们的组件添加一个默认的图标。2、将这个组件杂乱的属性归类。

(未完待续)


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-959369/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-959369/

ListView 排序 Stringgrid内使用回车键代替Tab键 TListBox内显示分栏 TListBox每一行显示交互的颜色 TMemo内光标位置根据鼠标移动 TMemo自动卷动 TRichEdit卷到特定位置 TRxRichEdit内插入图像 TStringGrid中插入、删除一行 TStringGrid保存和装载 TTreeview控件显示粗体节点 TWebBrowser中调用“查找”对话框 为Listview栏添加双击事件 为工具栏的TToolButton设置新的索引 仅通过Classname创建和管理任意窗体 从RichEdit取Rtf格式 从TListBox中拖放项目到TRichEdit 从一个TRichedit复制格式Rtf文本到其它 使用CustomSort方法排序TListView 使用DBGrid字段队列同步列标题队列 使用Interfaces和TInterfaceList 使用TRichEdit存储大于64K数据 使用代码移动StringGrid的行和列 使用圆形角显示控件 使用类名显示窗体 保存 装载TCheckListbox值 保存和装载TListView 保存和装载TTreeView 允许TDBGrid栏调整大小但防止移动 克隆控件 克隆窗体 列出控件的所有属性和事件 创建可编辑ListBox 删除Listbox的所有选定项目 删除stringlist中重复项目 删除TStringGrid中的列 动画窗体 取ComboBox List句柄 取TListview内所有选定项目 取TShellListView中选定文件的路径 取列举值的名称 在combobox中实现autocomplete 在DBGrid中使用回车键改变到下一个段 在listbox内列出所有目录、文件和驱动器 在Listbox内显示水平滚动条 在memo中实现UNDO 在RichEdit内搜索文本并选择它 在StringGrid内使用Combobox作为编辑器 在StringGrid单元中画不同颜色 在TComboBox中显示栏 在TComboBox内绘制位图 在TDateTimePicker内显示星期几 在TFileListBox内显示多列 在TListBox中创建彩色项目 在TListBox内拖拽 在TListbox内绘制位图 在TListview内执行进制搜索 在TListView内拖拽多个项目 在TListView列中创建进度条 在TMemo内查看和编辑MS-DOS文本 在TPageControl拖拽Tabs 在TPrintDialog上放置定制控件 在TRichEdit内使用上标和下标 在TRichEdit内使用超链接 在TRichEdit内文本使用不同的下划线样式 在TRichedit内设置段落行距 在TStringGrid内删除一行 在TStringGrid实现OnColumnClick事件 在自己的控件显示信息 复制Listbox项目到剪贴板 失效TTreeview的tooltips 定制TDateTimePicker的格式 居中控件 屏蔽在EditBox内按回车键的都都声 强制在TEdit内输入 排序StringGrid 搜索和替换RichEdit中文本 搜索和选定TListBox的项目 改变TDBGrid的DefaultRowHeight 改变TRichEdit内选定文本的背景颜色 改变TStringGrid内选定单元的颜色 改变标准对话框 改变状态栏字体样式 改变窗体上所有控件的属性 改变进度条颜色 根据StringGrid列内容自动调整大小 根据列排序TStringGrid 检查Stringgrid中指定单元示范选定 检查TMemo能否取消操作 检查TreeView是否完全展开或折叠 检查TStringGrid是否有滚动条 添加接口对象到list 清空StringGrid的所有单元 移动listbox项目 移动TListView项目 移动TRichEdit内光标到指定位置 聚焦TDBGrid某些单元 自动打开TDateTimePicker 自定义Memo边界 获取TRichEdit中鼠标指针下面的字 访问TRadioGroup的控件 调整TComboBox下拉列表的宽度 换Editbox的首字符为大写 换TEdit中每个词的首字母为大写 输出TStringGrid到TListView 运行时创建TButtons队列 运行时创建控件 运行时创建菜单项 运行时替换控件 返回TTreeView内字符串路径 防止在TEdit内剪贴、复制、粘贴 防止用户调整TListView栏大小 限制TEdit的输入 隐藏TListView滚动条 隐藏最小化MDI子窗口 颜色Combo Box 验证TEdit中输入的是数字
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值