delphi组件开发

Delphi开发报表打印的ASP组件         ASP在对数据库操作方面提供了很好的内嵌对象。但是,其他方面的功能有所欠缺,如:报表打印。特别是国内的复杂的报表,用ASP很难实现。       不过,ASP支持插件,这就可以根据需要开发ASP插件,笔者用Delphi5.0开发了ASP打印组件。下面笔者将分步来开发一个通用的报表打印的ASP组件。       第一步:新建一个Activex Library,命名为Pri 阅读详情
⑴ Delphi怎样处理HELP请求
Delphi基于关键词查询HELP请求。就是说,当用户在窗体设计窗口的已选部件上按F1键时,Delpdi将部件的名字转换成一个关键词,然后调用Windows Help引擎查找那个关键词的帮助主题。关键词是Windows Help系统的标准部分。实际上 ,WinHelp使用Help中的关键词产生Search对话框中的列表。因为用于上下文敏感搜索中的关键词不是实际供用户读的,所以要输入关键词的替代词。
例如,一个查找名为TSomething的部件的详细信息的用户可能打开WinHelp的Search对话框并输入TSomething。但不会使用用于窗体设计窗口的上下文查找的替代形式class-TSomething。因此,这个特殊的关键词Class-TSomething对用户是不可见的,以免弄乱了搜索列表。
  ⑵ 将Help插入Delphi
Delphi提供了创建和插入Windows Help文件的工具,包括Windows Help编译器HC.EXE。为自定义部件建立Help文件的机制与建立任何Help文件没什么不同,但需要遵循一些约定以与库中其它Help兼容。
  保持兼容性的方法如下:
  ● 建立Help文件
● 增加特殊的注脚
● 建立关键词文件
● 插入Help索引
 
当你为自定义部件建立完Help,有下列几个文件:
● 编译过的Help(.HLP)文件
● Help关键词(.KWF)文件
● 一个或多个Help源文件(.RTF)
● Help工程文件(.HLJ)
 
编译过的Help文件和关键词文件应当与库单元在同一目录。
  ① 建立Help文件
你可以使用任何的工具创建Windows Help文件。Delphi的多文件搜索引擎,可以包含任何数目的Help文件的要素。在编译的Help文件之外,你应当拥有RTF源文件,这样才能生成关键词文件。
  为使自定义部件的Help同库中其它部件一起工作,要遵循下列约定:
  ● 每个部件有占一页的帮助
部件帮助页应当给出部件目的的简单描述,然后列出最终用户可用的属性、事件和方法的描述。应用开发者通过在窗体上选择部件并按F1访问这一页。
  部件帮助页应当有一个用于关键词搜索的“K”脚注,脚注中包含部件名。例如,TMemo的关键词脚注读作"TMemo Component"
● 部件增加和修改的每一个属性,事件和方法应当有一页帮助
  属性、事件或方法的帮助页应当指出该项用于哪个部件,显示声明语法和描述它的使用方法。
  属性、事件或方法的帮助页应当有一个用于关键词搜索的“K”脚注,该脚注中包含该项的名字和种类。例如,属性Top的关键词脚注为“Top property”。
  Help文件的每一页也需要用于多文件索引搜索的特殊脚注。
  ② 增加特殊脚注
Delphi需要特殊的搜索关键词以区别用于部件的帮助页和其它项目。你应当为每一项提供标准的关键词搜索项。但你也需要用于Delphi的特殊脚注。
  要为来自Object Inspector窗口或代码编辑器F1的搜索增加关键词,就得为Help文件帮助页增加"B"脚注。
  “B”脚注与用于标准WinHelp关键词搜索的“K”脚注很相象,但它们只用于Delphi搜索引擎。下表列出怎样为每种部件帮助页建立“B”脚注:
 
表19.7 部件帮助页搜索注脚
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
帮助页类型 "B"脚注内容 示 例
   ──────────────────────────────────
主部件页 'class_'+部件类型名 class_TMemd
一般属性或事件页 'prop_'+属性名 prop_WordWrap
'event_'+事件名 event_OnChange
部件特有的属性 'prop_'+部件类型名 prop_TMemoWordWrap
或事件页 +属性名
'event_'+部件类型名 event_TMemoOnChange
+事件名
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
 
  区别一般帮助页和部件特有的帮助页是很重要的。一般帮助页应用于所有部件上的特定属性和事件。例如Left属性是所有部件中的标识。因此,它用字符串Prop-Left进行搜索。而Borde-style依赖于所属的部件,因此,BorderStyle属性拥有自己的帮助页。例如,TEdit有BorderStyle属性的帮助页,搜索字符串为Prop_TEditBorderStyle。
  ③ 建立关键词文件
  建立和编译了Help文件,并且增加了脚注之后,还要生成独立的关键词文件,这样Delphi才能将它们插入主题搜索的索引。
  从Help资源文件RTF创建关键词文件的方法如下:
● 在DOS提示行下,进入包含RTF文件的目录
● 运行关键词文件产生程序——KWGEN.EXE,后跟Help工程文件,如KWGEN SPECIAL.HPJ。当KWGEN运行完毕后,就有了与Help工程文件相同的关键词文件,但以.KWF为扩展名
● 将关键词文件放在编译完的库单元和Help文件相同的目录
当你在Component Palette上安装部件时,希望关键词插入Delphi Help系统的搜索索引。
 
④ 插入Help索引
以自定义部件建立关键词文件后,要将关键词插入Delphi的Help索引。
  将关键词文件插入Detphi Help索引的方法如下:
● 将关键词文件放在与编译完的库单元和Heph文件相同的目录中
● 运行HELPINST程序
 
HELPINST运行完后,Delphi的Help索引文件(.HDX)包含自定义部件帮助页的关键词。
⑶ 存储和装入属性
Delphi将窗体及其拥有的部件存储在窗体文件(.DFM)中,DFM文件用二进制表示窗体的属性和它的部件。当Delphi用户将自定义部件加入窗体中时,自定义部件应当具有存储它们的属性的能力。同样,当被调入Delphi或应用程序时,部件必须能从DFM文件中恢复它们。
  在大多数时候,不需要做任何使部件读写DFM文件的事。存储和装入都是继承的祖先部件的行为的一部分。然而在某些情况下,你可能想改变部件存储和装入时初始化的方法。因此,应当理解下述的机制:
● 存储和装入机制
● 描述缺省值
● 决定存储什么
● 装入后的初始化
 
① 存储和装入机制
当应用开发者设计窗体时,Delphi将窗体的描述存储在DFM文件中。当用户运行程序时,它读取这些描述。
  窗体的描述包含了一系列的窗体属性和窗体中部件的相似描述。每一个部件,包括窗体本身,负责存储和装入自身的描述。
  在缺省情况下,当存储时,部件将所有public和published属性的不同于缺省值的值以声明的顺序写入。当装入时,部件首先构造自己,并将所有属性设为缺省值;然后,读存储的、非缺省的属性值。
  这种缺省机制,满足了大多数部件的需要,而又不需部件编写者的任何工作。然而自己定义存储和装入过程以适合自定义部件需要的方法也有几种。
  ② 描述缺省值。
  Delphi部件只存储那些属性值不同于缺省值的属性。如果你不描述,Delphi假设属性没有缺省值,这意味着部件总是存储属性。
  一个属性的值没被构造函数设置,则被假设为零值。为了描述一个缺省值,在属性声明后面加default指令和新的缺省值。
  你也能在重声明属性时描述缺省值。实际上,重声明属性的一个原因是指定不同的缺省值。只描述缺省值,那么在对象创建时并不会自动地给属性赋值,还需要在部件的Create方法中赋所需的值。
  下面的代码用Align属性演示了描述缺省值的过程.
 
type
TStatusBar=class(TPanel)
public
constructor Create(Aowner: TComponent); override; { 覆盖以设置新值 }
published
property Align default alBottom; { 重新声明缺省值 }
end;
 
constructor TStatusBar.Create(Aowner: TComponent);
begin
inherited Create(Aowner); { 执行继承的初始化过程 }
Align := alBottom; { 为Align赋新的缺省值 }
end;
 
③ 决定存储什么
用户也可以控制Delphi是否存储部件的每一个属性。缺省情况下,在对象的published部分声明的所有属性都被存储。然而,可以选择不存储所给的属性,或者设计一个函数在运行时决定是否存储属性。
  控制Delphi是否存储属性的方法是在属性声明后面加stored指令,后跟True或False,或者是布尔方法名。你可以给任何属性的声明或重声明加stored表达式。下面的代码显示了部件声明三种新属性。一个属性是总是要存储,一个是不存,第三个则决定于布尔方法的值:
 
type
TSampleCompiment = class(TComponent)
protected
function storeIt: Boolean;
public { 正常情况下在不存 }
property Important: Integer stored True; { 总是存储 }
published { 正常情况下保存 }
property UnImportant: Integer stored False; { 不存 }
property Sometimes: Integer stored StoreIt; { 存储依赖于函数值 }
end;
 
④ 载入后的初始化
在部件从存储的描述中读取所有的属性后,它调用名为Loaded的虚方法,这提供了按需要执行任何初始化的机会。调用Loaded是在窗体和它的控制显示之前,因此,不需要担心初始化会带来屏幕闪烁。
  在部件载入属性时初始化它,要覆盖Loaded方法。
  在Loaded方法中,要做的第一件事是调用继承的Loaded方法。这使得在你的部件执行初始化之前,任何继承的属性都已初始化。
  下面的代码来自于TDatabase部件。在装入后,TDatabase试图重建在它存储时已打开的连接,并描述在连接发生异常时如何处理。
 
  procedure TDatabase.Loaded
begin
inherited Loaded; { 总是先调用继承的方法 }
Modified; { 设置内部标志 }
try
if FStreamedConnected then Open; { 重建联接 }
except
if csDesigning in ComponentState then { 在设计时 }
Application.HandleException(self) { 让Delphi处理异常 }
else raise; { 否 则 }
end;
end;
 
 
19.3 Delphi部件编程实例
 
19.3.1 创建数据库相关的日历控制-TDBCalendar
 
  当处理数据库联接时,将控制和数据直接相联是很重要的。就是说,应用程序可以建立控制与数据库之间的链。Delphi包括了数据相关的标签、编辑框、列表框和栅格。用户可以使自己的控制与数据相关。
  数据相关有若干等级。最简单的是只读数据相关或数据浏览,以及反映数据库当前状态的能力。比较复杂的是数据相关的编辑,也即用户可以在控制上操作数据库中的数据。
  在本部分中将示例最简单的情况,即创建联接数据库的单个字段的只读控制。本例中将使用Component Palette的Samples页中的TCalendar部件。
创建数据相关的日历控制包括下列几步:
● 创建和注册部件
● 使控制只读
● 增加数据联接(Data Link)
● 响应数据改变
 
19.3.1. 1创建和注册部件
 
每个部件的创建都从相同的方式开始,在本例中将遵循下列过程:
● 将部件库单元命名为DBCal
● 从TCalendar继承一个新部件,名为TDBCalendar
● 在Component Palette的Samples页中注册TDBCalendar
 
下面就是创建的代码:
 
unit DBCal;
 
interface
 
uses SysUtils, WinTypes, WinProc, Messages, Classes, Graphics, Controls,
Forms, Grids, Calendar;
type
TDBCalendar=class(TCalendar)
end;
 
procedure Register;
 
implementation
 
procedure Register;
begin
RegisterComponents(Samples,[TDBabendar]);
end;
 
end.
 
19.3.1.2 使控制只读
 
因为这个数据日历以只读方式响应数据,所以用户不能在控制中改变数据并指望它们反映到数据库中。
使日历只读包含下列两步:
● 增加只读属性
● 允许所需的更新
 
1. 增加只读属性
给日历控制增加只读选项是直接过程。通过增加属性,可以提供在设计时使控制只读的方法,当属性值被设为True,将使控制中所有元素不可被选。
⑴ 增加属性声明和保存值的private域:
 
type
TDBCalendar=class(TClendar)
private
FReadOnly: Boolean;
public
constructor Create (Aowner: TComponent); override;
published
property ReadOnly: Boolean read FReadOnly write FReadOnly default True;
end;
 
constructor TDBCalendar.Create(Aowner: TComponent);
begin
inherited Create(AOwner);
FReadOnly := True;
end;
 
⑵ 覆盖SelectCell方法,使得当控制是只读时,不允许选择:
 
function TDBCalendar.SelectCell(ACol, Arow: Longint): Boolean;
begin
if FReadOnly then
Result := False
else
Result := inherited SelectCell(Acol,ARow);
end;
 
还要在TDBcalendar的声明中声明SelectCell。
如果现在将Calendar加入窗体,会发现部件完全忽略鼠标和击键事件,而且当改变日期时,也不能改变选择的位置。下面将使控制响应更新。
2. 允许所需的更新
只读日历使用SelectCell方法实现各种改变,包括设置Row和Col的值。当日期改变时,UpdateCalendar方法设置Row和Col的值,但因为SelectCell不允许你改变,即使日期改变了,选择仍留在原处。
可以给日历增加一个Boolean标志,当标志为True时允许改变:
 
type
TDBCalendar=class(TCalendar)
private
Fupdating: Boolean;
protected
function SelectCell(Acol, Arow: Longint); Boolean; override;
public
procedure UpdateCalendar; override;
end;
 
function TDBCalendar.SelectCell(ACol, ARow: Longint): Boolean;
begin
if (not FUpdating) and FReadOnly then
Result := False { 如果更新则允许选择 }
else
Result := inherited SelectCell(ACol, ARow); { 否则调用继承的方法 }
end;
 
procedure UpdateCalendar;
begin
FUpdating := True; { 将标志设为允许更新 }
try
inherited UpdateCalendar; { 象通常一样更新 }
finally
FUpdating := False; { 总是清除标志 }
end;
end;
 
  现在日历仍旧不允许用户修改,但当改变日期属性时能正确反映改变;目前已有了一个真正只读控制,下一步是增加数据浏览能力。
 
  3. 增加数据联接
  控制和数据库的联接是由一个名为DataLink的对象处理。Delphi提供了几种类型的Datalink。将控制与数据库单个域相联的DataLink对象是TFieldDatalink。Delphi也提供了与整个表相联的DataLink。
  一个数据相关控制拥有DataLink对象,就是说,控制负责创建和析构DataLink。
  要建立作为拥有对象的Datalink,要执行下列三步:
  ● 声明对象域
  ● 声明访问属性
  ● 初始化DataLink
 
  ⑴ 声明对象域
  每个部件要为其拥有对象声明一个对象域。因此,日历对象DataLink 声明TFieldDataLink类型的域。
  日历部件中DataLink的声明如下:
 
type
TDBCalendar = class(TSampleCalendar)
private
FDataLink: TFieldDataLink;
end;
 
  ⑵ 声明访问属性
  每一个数据相关控制有一个DataSource属性,该属性描述应用程序给控制提供数据的数据源。而且,访问单个域的数据库还需要一个DataField 属性描述数据源中的域。
  下面是DataSource和DataField的声明和它们的实现方法:
 
type
TDBCalendar = class(TSampleCalendar)
private { 属性的实现方法是 }
function GetDataField: string; { 返回数据库字段的名字 }
function GetDataSource: TDataSource; { 返回数据源(Data source)的引用 }
procedure SetDataField(const Value: string); { 给数据库字段名赋值 }
procedure SetDataSource(Value: TDataSource); { 给数据源赋值 }
published { 使属性在设计时可用 }
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write SetDataSource;
end;
 
……
 
function TDBCalendar.GetDataField: string;
begin
Result := FDataLink.FieldName;
end;
 
function TDBCalendar.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
 
procedure TDBCalendar.SetDataField(const Value: string);
begin
FDataLink.FieldName := Value;
end;
 
procedure TDBCalendar.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
end;
 
  现在,就建立了日历和DataLink的链,此外还有一个更重要的步骤。你必须在日历构建时创建DataLink对象,在日历析构时,撤消DataLink对象。
  ⑶ 初始化DataLink
  在数据相关控制在其存在的期间要不停地访问DataLink对象,因此,必须在其构建函数中创建DataLink创建并且在析构时,撤消DataLink对象,因此要覆盖日历的Create和Destroy方法。
 
type
TDBCalendar=class(TCalendar)
public
constructor Create(Aowna: TComponent); override;
destructor Destroy; override;
end;
 
constructor TDBCalendar Create (Aowner: TComponent);
begin
inherited Create(AOwner);
FReadOnly := True;
FDataLink := TFieldDataLink.Create;
end;
 
destructor TDBCalendar Destroy;
begin
FDataLink.Free;
inherited Destroy;
end;
 
现在,部件已拥有完整的DataLink,但部件还不知从相联的域中读取什么数据。
 
19.3.1.4 响应数据变化
 
  一旦控制拥有了数据联接(DataLink)和描述数据源和数据域的属性。就需在数据记录改变时响应域中数据的变化。
  DataLink对象都有个名为OnDataChange的事件。当数据源指示数据发生变化时,DataLink对象调用任何OnDataChange所联接的事件处理过程。
  要在数据改变时更新数据,就需要给DataLink对象的OnDataChange事件增加事件处理过程。
  下面声明了DataChange方法,并将其赋给DataLink对象的OnDataChange事件:
 
type
TDBCalendar=class(TCalendar)
private
procedure Datachange(Sender: TObject);
end;
 
constructor TDBCalendar Create(AOwner:TComponent);
begin
inherited Create(AOwner);
FReadOnly := True;
FDataLink := TFieldDataLink.Create;
FDataLink.OnDataChange := DataChange;
end;
 
destructor TDBcalendar.Destroy;
begin
FDataLink.OnDataChange := nil;
FDataLink.Free;
inherited Destroy
end;
 
procedure TDBCalendar.DataChange(Sender: TObject);
begin
if FDataLink.Filed=nil then
CalendarDate := 0;
else
CalendarDate := FDataLink.Field.AsDate;
end;
;
(四)
创建图形部件 
图形控制是一类简单的部件。因为纯图形部件从不需要得到键盘焦点,所以它没有也不要窗口句柄。包含图形控制的应用程序用户仍然可以用鼠标操作控制,但没有键盘界面。
  在本例中提供的图形部件是TShape。Shape部件位于Component Palette的Additional页。本例中的Shape部件有所不同,因此称其为TSampleShape。
  创建图形部件需要下列三个步骤:
  ● 创建和注册部件
  ● 公布(publishing)继承的属性
● 增加图形功能
 
19.3.2.1 创建和注册部件
 
每个部件的创建都从相同的方式开始,在本例中如下:
● 建立名为Shapes的部件单元
● 从TGraphicControl 继承,将新部件称为TSampleShape
● 在Component Palette的Samples页上注册TSampleShape
 
unit Shapes
 
intertace
 
use SysUtils, WinTypes, WinProcs, Messages, Classes,
Graphics,Controls,Forms;
 
type
TSampleShape=class(TGraphicControl)
end;
 
implementation
 
procedure Register;
begin
RegisterComponents('Samples',[TSampleShape]);
end;
 
end.
 
19.3.2.2 公布继承的属性
 
一旦决定了部件类型,就能决定在父类的protected部分声明哪些属性和事件能为用户可见。TGraphicControl已经公布了所有作为图形控制的属性,因此,只需公布响应鼠标和拖放事件的属性。
 
  type
TSampleShape=class(TGraphicControl)
published
property DragCursor;
property DragMode;
property OnDragDrop;
property OnDragOver;
property ONEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseup;
end;
 
这样,该Shape控制具有通过鼠标和拖放与用户交互的能力。
 
19.3.2.3 .增加图形能力
 
一旦你声明了图形部件并公布了继承的属性,就可以给部件增加图形功能。这时需要知道两点:
  ● 决定画什么
  ● 怎样画部件图形
 
  在Shape控制的例子中,需要增加一些能使用户在设计时改变形状的属性。
 
1. 决定画什么
  图形部件通常都具有改变外观的能力,图形控制的外观取决于其某些属性的结合,例如Gauge控制具有决定其形状、方向和是否图形化地显示其过程的能力。同样,Shape控制也应有决定显示各种形状的能力.
给予Shape控制这种能力,增加名为Shape的属性。这需要下列三步:
● 声明属性类型
● 声明属性
● 编写实现方法
 
  ⑴ 声明属性类型
  当声明一个用户自定义类型的属性时,必须首先声明属性类型。最普通地用于属性的自定义类型是枚举类型。
  对Shape控制来说,需要声明一个该控制能画形状的枚举,下面是枚举类型的声明:
 
type
TSampleShapeType=(sstRectangle, sstSquare, sstRoundRect,
sstRoundSquare, sstEllipse, sstCircle);
TSampleShape = class(TGraphicControl)
end;
 
这样,就可以用该类型来声明属性。
⑵ 声明属性
当声明一个属性时,通常需要声明私有域来保存属性值,然后描述读写属性值的方法。
对于Shape控制,将声明一个域保存当前形状,然后声明一个属性通过方法调用来读写域值。
 
type
TSampleShape=class(TGrahpicControl)
private
FShape: TSampleShapeType;
procedure SetShape(value: TSampleShapeType);
published
property Shape: TSampleShapeType read FShape write SetShape;
end;
 
现在,只剩下SetShape的实现部分了。
⑶ 编写实现方法
下面是SetShape的实现:
 
procedure TSampleShape.SetShape(value: TSampleShapeType);
begin
if FShape<>value then
begin
FShape := value;
Invalidate(True); { 强制新形状的重画 }
end;
end;
 
2. 覆盖constructor和destructor
为了改变缺省属性值和初始化部件拥有的对象,需要覆盖继承的constructor和destructor方法。
图形控制的缺省大小是相同的,因此需要改变Width和Height属性。
本例中Shape控制的大小的初始设置为边长65个象素点。
⑴ 在部件声明中增加覆盖constructor
 
type
TSampleShape=class(TGraphicControl)
public
constructor Create(Aowner: TComponent); override;
end;
 
⑵ 用新的缺省值重新声明属性Height和width
 
type
TSampleShape=class(TGrahicControl)
published
property Height default 65;
property Width default 65;
end;
 
⑶ 在库单元的实现部分编写新的constructor
 
constructor TSampleShape.Create(Aowner: TComponent);
begin
inherited Create(AOwner);
width := 65;
Height := 65;
end;
 
3. 公布Pen和Brush
在缺省情况下,一个Canvas具有一个细的、黑笔和实心的白刷,为了使用户在使用Shape控制时能改变Canvas的这些性质,必须能在设计时提供这些对象;然后在画时使用这些对象,这样附属的Pen或Brush被称为Owned对象。
管理Owned对象需要下列三步:
● 声明对象域
● 声明访问属性
● 初始化Owned对象
 
⑴ 声明Owned对象域
拥有的每一个对象必须有对象域的声明,该域在部件存在时总指向Owned对象。通常,部件在constructor中创建它,在destructor中撤消它。
Owned对象的域总是定义为私有的,如果要使用户或其它部件访问该域,通常要提供访问属性。
下面的代码声明了Pen和Brush的对象域:
 
type
TSampleShape=class(TGraphicControl)
private
FPen: TPen;
FBrush: TBrush;
end;
 
⑵ 声明访问属性
可以通过声明与Owned对象相同类型的属性来提供对Owned对象的访问能力。这给使用部件的开发者提供在设计时或运行时访问对象的途径。
下面给Shape控制提供了访问Pen和Brush的方法
 
type
TSampleShape=class(TGraphicControl)
private
procedure SetBrush(Value: TBrush);
procedure SetPen(Value: TPen);
published
property Brush: TBrush read FBrush write SetBrush;
property Pen: TPen read FPen write SetPen;
end;
 
然后在库单元的implementation部分写SetBrush和SetPen方法:
 
procedure TSampleShape.SetBrush(Value: TBrush);
begin
FBrush.Assign(Value);
end;
 
procedure TSampleShape.SetPen(Value: TPen);
begin
FPen.Assign(Value);
end;
 
⑶ 初始化Owned对象
部件中增加了的新对象,必须在部件constructor中建立,这样用户才能在运行时与对象交互。相应地,部件的destructor必须在撤消自身之前撤消Owned对象。
因为Shape控制中加入了Pen和Brush对象,因此,要在constructor中初始化它们,在destructor中撤消它们。
① 在Shape控制的constructor中创建Pen和Brush
 
constructor TSampleShape.Create(Aowner: TComponent);
begin
inherited Create(AOwner);
Width := 65;
Height := 65;
FPen := TPen.Create;
FBrush := TBrush.Create;
end;
 
② 在部件对象的声明中覆盖destructor
 
type
TSampleShape=class(TGraphicControl)
public
construstor.Create(Aowner: TComponent); override;
destructor.destroy; override;
end;
 
③ 在库单元中的实现部分编写新的destructor
 
destructor TSampleShape.destroy;
begin
FPen.Free;
FBrush.Free;
inherited destroy;
end;
 
④ 设置Owned对象的属性
处理Pen和Brush对象的最后一步是处理Pen和Brush发生改变时对Shape控制的重画问题。Pen和Brush对象都有OnChange事件,因此能够在Shape控制中声明OnChange事件指向的事件处理过程。
下面给Shape控制增加了该方法并更新了部件的constructor以使Pen和Brush事件指向新方法:
 
type
TSampleShape = class(TGraphicControl)
published
procdeure StyleChanged(Sender: TObject);
end;
 
implemintation
 
constructor TSampleShape.Create(AOwner:TComponent);
begin
inherited Create(AOwner);
Width := 65;
Height := 65;
Fpen := TPen.Create;
FPen.OnChange := StyleChanged;
Fbrush := TBrush.Create;
FBrush.OnChange := StyleChanged;
end;
 
procedure TSampleShape.StyleChanged(Sender: TObject);
begin
Invalidate(true);
end;
 
当变化发生时,部件重画以响应Pen或Brush的改变。
 
4. 怎样画部件图形
图形控制基本要素是在屏幕上画图形的方法。抽象类TGraphicControl定义了名为Paint的虚方法,可以覆盖该方法来画所要的图形。
Shape控制的paint方法需要做:
● 使用用户选择的Pen和Brush
● 使用所选的形状
● 调整座标。这样,方形和圆可以使用相同的Width和Height
 
覆盖paint方法需要两步:
● 在部件声明中增加Paint方法的声明
● 在implementation部分写Paint方法的实现
 
下面是Paint方法的声明:
 
type
TSampleShape = class(TGraphicControl)
protected
procedure Paint; override;
end;
 
然后,编写Paint的实现:
 
procedure TSampleShape.Paint;
begin
with Canvas do
begin
Pen := FPen;
Brush := FBrush;
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; 
无论任何控制需要更新图形时,Paint就被调用。当控制第一次出现,或者当控制前面的窗口消失时,Windows会通知控制画自己。也可以通过调用Invalidate方法强制重画,就象StyleChanged方法所做的那样。
Delphi XE组件开发技术 1. 组件设计基础: 1.编写组件步骤: 1) 确定一个祖先类。 TObject:直接从TObject继承下来的类不是组件。有些以此为基类的对象在设计期不需要使用,如TIniFile TComponent:这是非可视组件的起点,它的特点是在设计时能够以流的方式在IDE上存取 TGraphicControl:创建一个不需要窗口句柄、但要在屏幕上显示的组件时,用这个类作为祖先类 TWinControl:所有需要窗口句柄的组件,都应以该类为基类。该类提供了Windows组件的一般属性和事件 TCu. 阅读详情

相关推荐

Delphi实现的文本阅读器:组件与编程技巧详解

本文还有配套的精品资源,点击获取 简介:本文详细阐述了如何利用Delphi语言及其VCL控件库开发一个功能丰富的文本阅读器应用程序。涵盖界面设计、文件操作、文本显示、搜索、导航、书签、设置、错误处理、多文档界面和代码优化等方面。Delphi的高效编译器和丰富的组件库能够帮助开发者快速构建出性能优越的文本阅读器。 1. Delphi语言和VCL控件库介绍 Delp...

weixin_36277197的博客 1411

delphi开发控件

delphi开发控件delphi开发控件delphi开发控件delphi开发控件

Delphi 5 Linux 开发试用组件包 - SuipackTrial

Delphi 5 IDE 是一个集成开发环境,它在1990年代末为开发快速应用程序开发(RAD)设定了标准。RAD 方法论强调速度和效率,允许开发者通过可视化工具快速设计界面,并迅速生成代码,从而缩短了软件的开发周期。Delphi 使用的是一种强类型的 Pascal 语言变种,名为 Object Pascal,它在易用性和功能强大方面为程序员提供了平衡。SuipackTrial 是 Delphi 开发者社群中广泛使用的组件包之一,它提供了多种可视化组件,旨在提高开发效率和增强应用程序的用户界面。

weixin_42298254的博客 1081

Delphi 控件开发步骤

delphi 控件开发步骤Delphi控件开发步骤1.使用Delphi IDE的 Component -> New Component 菜单2.按照向导逐步完成3.控件工程文件4.控件安装面板图标的实现5.关于无源码控件发布 Delphi控件开发步骤 本步骤基于delphi berlin版本。 1.使用Delphi IDE的 Component -> New Component 菜单 ......

sensor_WU 博客 3447

delphi组件开发2

(一)Delphi除了支持使用可视化部件所见即所得地建立应用程序外,还支持为开发应用而设计自己的部件。  在本章中将阐述如何为Delphi应用程序编写部件。这一章将达到两个目的:  ● 教你如何自定义部件  ● 使你的部件成为Delphi环境的有机组合部分 19.1 Delphi部件原理 19.1.1 什么是部件   部件是Delphi应用程序的程序构件。尽管大多数部件代表用户界面的可见元素,但部

工作是我的生活 我为工作而陶醉 2685

创建component的方法集锦

转自http://delphi.about.com/library/weekly/aa122899b.htm Delphi Developers Guide. Online book straight from Borland. Featuring chapters: Overview of component creation, Object-oriented programming...

dench2001的博客 385

Delphi 6开发ASP上传组件详解

  文件上传是WEB开发中经常要用到的功能,但ASP本身和内置的组件都不支持文件上传功能。网上流传的一些第三方组件虽然能够解决这个问题,但大多是要收费的,更别说Open Source了。本文将详细剖析WEB文件上传的原理,以及一步步指导读者如何用Delphi6开发一个ASP上传组件。1 Html文件分析  首先我们来看一个html文件源码,文件名是test.htm,功能是提供用户上传的界面:

kinglang的专栏 1241

delphi 自定义控件_Delphi中的自定义组件开发

delphi 自定义控件 Components are essential elements of the Delphi environment. One of the most important features of Delphi is that we can use Delphi to create our own components. 组件Delphi环境的基本元素。 Delph...

cumao2792的博客 800

DELPHI为ASP开发文件上载组件

2001年04月17日 16:06:00 用DELPHI为ASP开发文件上载组件 深圳王发军 返回 ASP(Active Server Page)是微软公司的产品,由于它编程很容易上手,能快速开发功能强大的动态网站,现在很多网站(特别是Intranet/Extranet内部网)采用了NT+IIS+ASP的模式,使得ASP成为目前较为流行的网站开发脚本语言。在WEB服务中,文件上载服务是

秦梦瑶的专栏 422

Delphi高效开发组件套件实战

Delphi作为历史悠久且持续进化的快速应用开发(RAD)平台,凭借其高效的编译器、直观的可视化设计界面和强大的跨平台支持,至今仍在企业级应用开发中占据重要地位。其核心优势在于通过高度集成的IDE(集成开发环境)大幅缩短开发周期,提升代码可维护性与UI设计效率。本章将系统介绍Delphi开发环境的基础架构,包括IDE的主界面布局、菜单系统、代码编辑器、窗体设计器、对象观察器(Object Inspector)与项目管理器(Project Manager)等关键组件

weixin_30838971的博客 801

Delphi开发USB HID设备通信组件实战

USB HID(Human Interface Device)设备是指遵循HID协议标准的输入设备,如键盘、鼠标、游戏手柄等。其核心在于通过标准化的数据报告格式,实现设备与主机之间的高效通信。HID设备通过设备描述符和报告描述符向主机描述其功能与数据结构。其中,报告描述符尤为重要,它定义了设备发送或接收数据的格式与语义。在操作系统层面,HID设备插入后,系统通过HID类驱动自动识别并加载相应的驱动程序,用户无需手动安装驱动即可使用。

weixin_42453228的博客 870

Delphi制作数据感知控件之浮想联翩

 Delphi制作数据感知控件之浮想联翩王维康 编写知识点本文共有6个关于控件的知识点:1、基本控件的制作;2、感知属性的添加;3、关联控件的销毁处理;4、事件方法的赋值; 5、属性页的制作;  6、组件包设计思想 关于制作感知控件的文章有不少,但涉及的内容大都比较单一,读者只能依照文章的陈述按部就班地操作,无法很好的理解控件的制作机制。本文试图通过讲解一个控件的制

hezhanying的专栏 1042

Delphi 组件开发实现类 编辑框

效果如下图: 实现代码: unit Edit1; interface uses   SysUtils, Windows,Classes, Controls, StdCtrls,Graphics,Messages; type   TEdit1 = class(TEdit)   private     FAlignment: TAlignment;

crkres9527 1446

Delphi对话框与窗口组件开发指南

本文还有配套的精品资源,点击获取 简介:Delphi编程中,对话框和窗口是构建用户界面的关键元素。本指南将通过"dxPack108.zip_对话框与窗口_Delphi_"压缩包,深入探讨Delphi中的对话框和窗口组件,包括模态和非模态对话框、自定义窗口创建、XP风格组件集成等知识点。压缩包中的源代码和示例应用程序将帮助开发者掌握如何使用这些组件,提升UI设计和实现技能,从...

weixin_36204513的博客 1301

Delphi开发者必备:Ehlib6组件库全面介绍与实践指南

Delphi是Borland公司推出的一款高效、面向对象的可视化编程工具,它拥有强大的组件库和直观的编程语言——Object Pascal。自1995年首次发布以来,Delphi迅速成为企业级应用和桌面软件开发的首选工具之一,它的简洁语法和丰富的组件库,使得开发者能够快速搭建起稳定且具有高性能的应用程序。Delphi的版本不断演进,从最初的Delphi 1到现在被Embarcadero Technologies公司继续发展的RAD Studio系列。

weixin_29069575的博客 978

跨平台Delphi UI开发——FMSoft uniGUI组件

Delphi作为一款历史悠久的集成开发环境,以其强大的VCL框架和FireMonkey (FMX) 框架,一直深受开发者喜爱。在Delphi 10.2 Tokyo及之后的版本中,引入了FMSoft的uniGUI组件库,它为Delphi提供了在多平台下开发富客户端应用程序的能力。FMSoft uniGUI的组件库是构建富客户端应用程序的核心,它拥有广泛的标准组件和高级控件。uniGUI组件库的设计理念强调了组件的复用性、可扩展性和平台无关性。

weixin_34598113的博客 1750
上一篇: elphi 组件撰写常问问题
下一篇: delphi组件开发2
Dcdu
博客等级 码龄21年 44粉丝 33原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值