细说制作VCL 组件

制作组件,是Delphi应用中最激动人心也是最有趣的内容之一,程序设计者制作组件的目的之一,是把大量的重复劳动用组件的方法定制起来,加快软件开发的效率。当我们向Delphi添加一个新的软件包时,实际上就是使用了一个新的类扩展了VCL ,这个新类从一个已有组件相关的类中派生出来,并向继承它的类添加了新的功能。
   VCL(Visual Component Library)构件,是Delphi的核心,制作这样的构件,主要采取这样几个步骤:

   1〉选择合适的基类进行继承
   构件的基类要根据需要选择,例如:
   TComponent  是完全空白的基类;
   TControl    是可视类的基类;
   TWinControl 是窗体类的基类;
   TGraphControl  是图形类的基类。
   等等。

   2〉加入构件的属性、方法和事件
   属性方法和事件,大部分可以来自于基类的继承,但也可以新定义。可以用覆盖基类的方法,实现新的功能。新定义的方法,也可以设置成抽象的、动态的或虚拟的。
   事件也可以从基类继承,也可以自己定义事件,这种事件,可以由Windows消息触发(如点击鼠标),也可以自己定义由内部状态的变化来触发。

   3〉注册构件
   如果希望构件是可视化的,就需要注册,方法是:

   Components -> Install Components

   下面先举一个简单的例子。   
   一、制作第一个组件
   首先制作一个组件,了解一下组件制作的方法,目标是一个下拉列表框,显示所有的系统字体:    
   首先要清空原来的Form。
   然后
   Component(组件)---New Component--启动Component Wizard
   或File--New--Other--Component(黄色齿轮的图标)也可以启动Component Wizard。
   Component Wizard需要如下信息:
   Ancestor type:我们想继承的父类名称(这里为TComboBox);
                  注意一下,一般同名的基类,Q开头的是CLX构件,
                  另一个是VCL构件。                  
   Class Name:正在建立的组建类名称(这里为TMd4FontCombo);
   Palette Page:组件放置的页面(这里建立的一个新的页面Md4);
   Unit File Name:放置源代码的文件名(这里为Md4FontBox)
   最后为当前搜索路径,请使用默认值。
   Ok   (另一个Install是立刻在组建包中安装组件)
   这就得到了一个简单的Pascal源文件:

------------------------------------------------------------------
unit Md4FontCombo;

interface

uses
 Windows, Messages, SysUtils, Classes, Controls, StdCtrls;

type
 TMd4FontCombo = class(TComboBox)
 private
   { Private declarations }
 protected
   { Protected declarations }
 public
   { Public declarations }
 published
   { Published declarations }
 end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents(‘Md4‘, [TMd4FontCombo]);
end;

end.

---------------------------------------------------------------
   这个文件的一个关键元素是类定义:

   TMd4FontCombo = class(TComboBox)

   它说明了父类开始。
   和一般单元相比,它多了一个Register过程,这里默认定义了一个用于注册组件的过程Register:

   RegisterComponents(‘Md4‘, [TMd4FontCombo]);

   说明了把TMd4FontCombo注册到Md4页。
   需注意的是Register过程中的首字符应该大写,这主要是为了和C++ Builder 兼容。还要注意的是,当建立组件的时候应该使用一个命名规则,大多数Delphi开发人员,都使用两到三个字母标记,作为他们开发的组件前缀,比如这里用Md4。
   还需要注意一下Uses的变化:

   uses
      Windows, Messages, SysUtils, Classes, 
      forms,Controls, StdCtrls;

   这里多了一个forms,因为后面要用到Screen,如果这里没有声明Forms,将会编译报错。
   在interface作如下声明:

 public
   { Public declarations }
   //下面两行为自己添加的构造函数
   Constructor Create(Aowner:TComponent);override;
   procedure CreateWnd;override;
 published
   { Published declarations }

   {下面两行自己添加,为设置组件的属性,没有设置的将从父类继承过来默认值}

   Property Style default csDropDownList;
   Property Items stored false;

   在implementation区域写上具体的程序:

Constructor TMd4FontCombo.Create(Aowner:TComponent);
begin
    inherited Create (Aowner);
    style:=csDropDownList;
end;

procedure TMd4FontCombo.CreateWnd;
begin
 inherited CreateWnd;
 
 {把系统字体添加进组合框,注意uses中要加上Forms,否则Screen由于不被声明而出错}

 Items.Assign (Screen.Fonts);
end;

end.

   这里需要指明的是,表面上看,为了在组合框里面添加所有的系统字体,只要在重载Create对象方法中添加语句:
  
   Items:=Screen.Fonts;

   就可以了,实际上这是行不通的。这是因为在组件完全建立起来以前,我们并不能访问组合框的Items属性。
   所以,我们在CreateWnd过程中才给组合框赋新的字符串。
   还要注意的是,除了在Create对象方法中赋予组件的 style属性一个新值以外,还要用default关键字通过设置一个值来重新定义属性:

   Property Style default csDropDownList;

   这两步操作是必须的,因为向属性声明添加default关键字,不会对属性的初始值产生直接的影响。包含缺省值的属性不用包含在窗体定义中(包括文本描述),default 关键字将向流代码说明,组件初始化代码将设置该属性的值。
   另一个重新定义的属性Items被设置成根本就不保存在DFM文件中的属性:

   Property Items stored false;

   因为程序启动时将从新装入该值,保存是没有意义的。
   下面是完整的源程序:

---------------------------------------------------------
unit QMd4FontCombo;

interface

uses
 Windows, Messages, SysUtils, Classes, forms,Controls, StdCtrls;

type
 TMd4FontCombo = class(TComboBox)
 private
   { Private declarations }
 protected
   { Protected declarations }
 public
   { Public declarations }
   //下面两行为自己添加的构造函数
   Constructor Create(Aowner:TComponent);override;
   procedure CreateWnd;override;
 published
   { Published declarations }
   //下面两行为自己添加
   Property Style default csDropDownList;
   Property Items stored false;
 end;

procedure Register;

implementation


procedure Register;
begin
 RegisterComponents(‘Md4‘, [TMd4FontCombo]);
end;

Constructor TMd4FontCombo.Create(Aowner:TComponent);
begin
    inherited Create (Aowner);
    style:=csDropDownList;
end;

procedure TMd4FontCombo.CreateWnd;
begin
 inherited CreateWnd;
 //注意uses中要加上Forms,否则Screen不被声明
 Items.Assign (Screen.Fonts);
end;

end.

--------------------------------------------------------

   二、建立组件包

   Component--- install Component

   在对话框中第一项Unit file Name,是组件单元.pas文件的名字。其他只要按缺省OK,就可以了。
   这是我们可以看到,在控件选项卡多了一个Md4,里面多了一个控件,这就是我们制作的控件TMd4FontCombo。

   三、给组件以新的位图
   在没有给组件位图的时候,组件默认的是以其父类的位图为其代表的,你也可以给组件一个新的位图。
   方法如下:

   Tools---Image editor 调出位图编辑器
   New-- Component Resource File (.dcr),dcr(Delphi Component Resource)是带有不同扩展名的RES文件。
   在弹出的窗口中,右键---New--Bitmap--24*24--OK
   它默认的给了一个项目名称Bitmap1,现在你必须改成和当前正在构造的控件类相同(前面要加T),同时全部大写,这里为:

   TMD4FONTCOMBO

   这是Delphi的强制要求。
   双击可以绘图,保存的名字也要与项目匹配,这里为:

   MD4FONTCOMBO.DCR

   这样,在install Component就可以看到新的图标了,如果不行,程序中可以在plementation后面加上编译开关,强行加入这个图标文件:
 
   {$R Md4FontCombo.dcr}  

   四、更复杂的例子
   下面我们定义一个组件,从TGraphicControl为父类继承来一个SampleShape,来画一些标准的图形。请仔细阅读这个程序,并自己建立一个类似的组件。
   首先要清空原来的Form。
   然后
   Component(组件)---New Component--启动Component Wizard
             或File--New--Other--Component(黄色齿轮的图标)
   Component Wizard需要如下信息:
   Ancestor type:我们想继承的父类名称(这里为TGraphicControl);
                  注意一下,一般同名的基类,Q开头的是CLX构件,
                  另一个是VCL构件。                  
   Class Name:正在建立的组建类名称(这里为TSampleShape);
   这就建造了一个基本的框架:
-------------------------------------------------------------------
unit SampleShape;

interface

uses
 Windows, Messages, SysUtils, Classes, Controls;

type
 TSampleShape = class(TGraphicControl)
 private
   { Private declarations }
 protected
   { Protected declarations }
 public
   { Public declarations }
 published
   { Published declarations }
 end;

procedure Register;

implementation

procedure Register;
begin
 RegisterComponents(‘Samples‘, [TSampleShape]);
end;

end.

-----------------------------------------------------------------
   写程序,注意一下把Graphics加入到Uses中去。
----------------------------------------------------------------

unit SampleShape;

interface

uses
 Windows, Messages, SysUtils, Classes, Controls,Graphics;

type
  //声明FShape的属性用枚举,这样,在属性栏里希望有枚举的表述
  //这里只是声明了一个枚举的类型TSampleShapeType

   TSampleShapeType=(sstRectangle,sstSquare,sstRoundRect,
                 sstRoundSquare,sstEllipse,sstcircle);

  //TSampleShape是由TGraphicControl派生出的
 TSampleShape = class(TGraphicControl)


  private
   { Private declarations }

   //声明一个属性时,声明私有域保护属性值,在下面描述读写属性值的方法
   //拥有的每一个对象必须有对象域的声明,该域在部件存在时总指向Owned对象。
   //通常,部件在constructor中创建它,在destructor中撤消它。
   //Owned对象的域总是定义为私有的,如果要使用户或其它部件访问该域,通常要提供访问属性。

   FShape:TsampleShapeType;
   procedure SetShape(value:TSampleShapeType);

   // 使用Canvas的Pen和Brush给TPen和TBrush设置初值
   procedure SetPen(Value: TPen);
   procedure SetBrush(Value: TBrush);
   function GetBrush: TBrush;
   function GetPen: TPen;

 protected
   { Protected declarations }

   procedure Paint;override;

 public
   { Public declarations }

   //构造函数
    constructor Create(AOwner: TComponent); override;
    //析构函数
    destructor Destroy; Override;
 published
   { Published declarations }
   property DragCursor;
   property DragMode;
   property OnDragDrop;
   property OnDragOver;
   property OnEndDrag;
   property onMouseDown;
   property onMouseMove;
   property onMouseup;

   //设置缺省的组件大小 65个象素点
   property Height default 65;
   property Width default 65;

   //公布shape pen brush 使用户在使用组件时能改变Canvas的性质
   property Shape:TSampleShapeType read FShape write SetShape;
   property Pen: TPen read GetPen write SetPen;
   property Brush: TBrush read GetBrush write SetBrush;
 end;

//注册图形组件
procedure Register;

implementation

procedure Register;
begin
RegisterComponents(‘MD4‘, [TSampleShape]);
end;


//设置Shape属性用枚举类型TSampleShapeType

procedure TSampleShape.SetShape(value:TSampleShapeType);
begin
if FShape<>value then
 begin FShape:=value;
      Invalidate;
 end;
end;


//可以在构造函数中设置初值
constructor TSampleShape.Create(AOwner: TComponent);
begin
  Inherited Create(AOwner);
  width := 65;
  Height := 65;
end;


destructor TSampleShape.Destroy;
begin
 Inherited destroy;
end;


procedure TSampleShape.Paint;
begin
 with Canvas do
 begin
   case FShape of
   sstRectangle,sstSquare:
      Rectangle(0,0,Width,Height);
   sstRoundRect,sstRoundSquare:
       RoundRect(0,0,Width,Height,Width div 4,Height div 4);
   sstCircle,sstEllipse:
       Ellipse(0,0,Width,Height);
   end  ;
  end ;
end;

procedure TSampleShape.SetBrush(Value: TBrush);
begin
 Canvas.Brush.Assign(Value);
end;

procedure TSampleShape.SetPen(Value: TPen);
begin
 Canvas.Pen.Assign(Value);
end;

function TSampleShape.GetBrush: TBrush;
begin
 Result := Canvas.Brush;
end;

function TSampleShape.GetPen: TPen;
begin
 Result := Canvas.Pen;
end;

end.

--------------------------------------------------

   Component--- install Component

   在对话框中第一项Unit file Name,是组件单元.pas文件的名字。其他只要按缺省OK,就可以了。
   下面可以试验一下这个控件的性能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值