您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 第10章 高级组件设计
第10章高级组件设计第10章将示范一些高级技巧,使得可以创建种类更多的组件,并更好地控制组件的工作方式。高级组件设计包括如何动态装载资源以创建出色的图形化控件、怎样公开被拥有的组件——Delphi6所引入的新技术、创建对话框组件,持久化非公开特性,以及如何创建特性编辑器。公开被拥有的组件可以节省很多工作,而且可以比以前的Delphi版本更加易于创建由许多控件衍生出来的组件。10.1动态装载资源像TMediaPlayer(如图10.1所示)一样具有专业外观、富于吸引力的控件需要动态创建组件,并在创建组件时将图形资源装载到组件中。在第9章中,您已经学会如何使用ImageEditor来创建Delphi组件资源(dcr)文件。如果把24×24像素的位图命名为与类相同的名字,并将DCR文件存储为与组件单元文件相同的名字——当然,扩展名是不同的;这样,在把单元添加到包的时候,Delphi将自动地装载相应的DCR文件。这时,这些位图将显示在VCL面板代表对应组件的按钮上(细节可以参考9.7.1节“用ImageEditor创建组件资源文件”)。图10.1TMediaPlayer组件的外观非常专业,它使用了位图,在运行时从资源文件中动态装载(图中所示的speedis.avi与Delphi一同发布,位于demos\coolstuf文件夹下)通过将额外的光标、图标和位图添加到同一DCR文件中,Delphi会把这些资源文件编译到组件的.DCU文件中,并将其链接到.bpl库(请记住:BPL是一种特定的动态链接库)。将组件编译到包中之后,资源可以通过API过程访问,并使用组件方法来装载。通常具有资源装载方法的组件会包含代表资源的对象,如TSpeedButton的Glyph特性。在数据库应用程序中通常会遇到的可视化结构是包含四个按钮的可视化控件(如图10.2所示),按钮用于在左右两栏之间来回移动相应的项。如图10.2所示的控件相当有用,可以用于几个窗体或工程,具有明显的累积效应。本节将使用TButtonPanel组件来示范如何动态地装载源,在下一节讨论如何公开被拥有的组件。第10章高级组件设计239图10.2按钮导航组件。方向箭头表示移动方向注意:有一个谜语是这样的:您愿意现在得到一百万美元,还是第一天得一美分,以后每一天的钱是前一天的两倍,连续30天呢?答案当然是后一个。直到第20天到第30天之间时,才能看出累积的效果,最后的结果非常巨大,有10737418美元。使用组件来建立应用程序的效果与此类似。最初的效应并不明显,但累积到最后的结果是惊人的。图10.2中显示的组件使用了由TMediaPlayer组件得到的位图。在组件中使用资源的第一步是将其加入到Delphi组件资源文件,即DCR文件中。TButtonPanel组件的单元名是UButtonPanel.pas。因此,DCR文件是UButtonPanel.dcr,而且与组件单元位于相同的目录下。四个按钮可以用TSpeedButton组件来实现。TSpeedButton具有Glyph特性,可用于图像。Glyph可以是位图;如图10.2所示,共有四幅位图。10.1.1创建Delphi组件资源文件ImageEditor可用于为TButtonPanel组件创建位图资源。按下列步骤可创建DCR文件。1.从Delphi的Tools菜单中启动ImageEditor。2.在ImageEditor中,单击File,New,ComponentResourceFile菜单项以创建资源文件。3.选择Resource,New,Bitmap菜单项,并接受缺省的大小和颜色来创建四个位图(缺省的大小是32×32像素和16色VGA模式)。4.可以画出位图或复制并粘贴已有的位图(如果组件中包含可能受第三方版权保护的位图,在分发组件之前向公司的法律顾问查询一下)。如果想从mplayer.res文件中复制资源,可以在ImageEditor中打开该文件,然后复制并粘贴要使用的四幅图像(mplayer.res文件位于Delphi安装目录的Lib子文件夹中)。5.使用合适的名字重新命名每个位图(我们将用枚举列表和RTTI来索引和装载资源;因此可以参考图10.2,将位图从上到下依次命名为bpFirst,bpPrior,bpNext,bpLast。使用bp作为前缀是Delphi命名枚举元素的惯例——从构成枚举的单词的首字母中挑选两个作为前缀。枚举类型的名字是TButtonPosition)。6.昀后,把DCR文件保存为UButtonPanel.dcr,与组件位于同一目录。如果DCR文件与组件位于同一目录里,当把组件添加到包时,DCR文件将与组件一同添加,如图10.3所示。编译器将编译该单元,并将包和DCR资源文件链接到BPL库。资源文件包括在库中,可通过方法调用访问。第10章高级组件设计240图10.3包编辑器,其中是dclusr60.dpk包,包含了UButtonPanel单元的DCR和PAS文件10.1.2装载资源装载资源的较为方便的方法是将资源命名为与枚举列表中的序数值同名。继续讨论TButtonPanel,按钮的类型定义命名如下:type{$M+}TButtonPosition=(bpFirst,bpPrior,bpNext,bpLast);{$M-}可以注意到枚举元素的名字和前面小节中的资源名是相同的。$M是运行时类型信息所对应的编译器指令。如果将typinfo.pas单元添加到uses子句,可以从枚举序数值得到枚举值的字符串名,正好可用于读取相应的资源。unitUEnumerationDemo;interfaceusesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,StdCtrls,ExtCtrls;type{$M+}TButtonPosition=(bpFirst,bpPrior,bpNext,bpLast);{$M-}TForm1=class(TForm)Image1:TImage;Image2:TImage;Image3:TImage;Image4:TImage;Button1:TButton;procedureFormCreate(Sender:TObject);procedureButton1Click(Sender:TObject);private{Privatedeclarations}FImages:array[TButtonPosition]ofTImage;public{Publicdeclarations}end;varForm1:TForm1;implementation{$R*.DFM}{$RUButtonPanel.Res}usestypinfo;procedureTForm1.FormCreate(Sender:TObject);beginFImages[bpFirst]:=Image1;FImages[bpPrior]:=Image2;第10章高级组件设计241FImages[bpNext]:=Image3;FImages[bpLast]:=Image4;end;procedureTForm1.Button1Click(Sender:TObject);varI:TButtonPosition;BeginforI:=Low(TButtonPosition)toHigh(TButtonPosition)doFImages[I].Picture.Bitmap.LoadFromResourceName(HInstance,GetEnumName(TypeInfo(TButtonPosition),Ord(I)));end;end.单元在接口部分定义了枚举类型TButtonPosition,并在编译时对其添加了运行时类型信息。四幅图像可用做位图的仓库。类中定义了一个TImage的私有数组,并在FormCreate事件方法中进行了初始化,以指向四个图像组件。在实现部分,UButtonPosition.res文件通过$R编译器指令引入。ButtonClick事件方法迭代使用TButtonPosition枚举作为循环范围,并使用图像引用数组装载位图。一个TPicture对象包含在一个TImage对象中。而每个TPicture包含一个TBitmap对象,TBitmap对象具有LoadFromResourceName方法。HInstance是在System单元中定义的全局Windows句柄,可以分配到应用程序或库;而GetEnumName使用RTTI将枚举值转换为对应的字符串值。要记住:位图资源与枚举元素是同名的,这样对资源编程更为容易。10.2公开所拥有的组件由于组件的复杂性不断增长,更多组件定义为聚合关系。较早版本的Delphi要求定义特性编辑器以便在设计时访问所包含的对象;或至少需要进行必要的属性提升,才能在设计时对所拥有对象的数据和事件特性进行访问。考虑在上一节提到的TButtonPanel组件。在含有按钮的面板上对齐按钮,是创建按钮面板组件的一个直接途径。使用该技巧可以在设计时访问按钮的属性。下面列出的部分代码演示了这个技巧。注意:属性提升是一种有效的技术,可用于将所包含对象的属性提升到容器的接口部分——称为使接口扁平化,这样在设计时对所包含的组件提供访问接口就不必要了。typeTButtonPosition=(bpFirst,bpPrior,bpNext,bpLast);TButtonPanel=class(TPanel)privateFButtons:array[TButtonPosition]ofTSpeedButtons;protectedprocedureSetClickEvent(Index:TButtonPosition;constValue:TNotifyEvent);functionGetClickEvent(index:TButtonPosition):TNotifyEvent;publishedpropertyFirstOnClick:TNotifyEventindexbpFirstreadGetClickEventwriteSetClickEvent;propertyPriorOnClick:TNotifyEventindexbpPriorreadGetClickEventwriteSetClickEvent;//etc…第10章高级组件设计242end;列出的部分代码示范了属性提升。按钮是被包含的对象,但在以前的版本中无法为它们声明公开属性。因此不能在ObjectInspector中直接操纵这些对象。结果,所有在设计时需要被修改的被包含组件的特性都需要属性提升,因此会增加许多额外的方法。虽然生成这些提升的属性及其相关联的访问方法很简单,但是这些是必须编写的代码,让人感觉沉闷之极。Delphi6提供了组件所有权机制,减少了继续按上述方式创建组件的必要性。10.2.1声明公开的组件特性Delphi的当前版本能够正确地将所拥有的组件流化到.DFM文件,而且设计时可以在ObjectInspector中对其进行修改。回顾一下TButtonPanel组件,可以发现:将对象数据声明为私有的,经由代表对象的特性提供访问接口,仍然是个好习惯。但现在特性定义可能位于公开部分,而对象可以在设计时被修改,这是第3章中讨论TComponent类所引入的新的特征。下面的代码示范了基本正确的解决方案。unitUImagePanel;interfaceusesWindows,Messages,SysUtils,Classes,Graphics,Controls,Forms,Dialogs,ExtCtrls;typeTImagePanel=class(TPanel)privateFImage:TImage;publicconstructorCreate(AOwner:TComponent);override;publishe
本文标题:第10章 高级组件设计
链接地址:https://www.777doc.com/doc-5855993 .html