浅谈控件(组件)制作方法一,附带一delphi导出数据到Excel的组件实例

来自:http://blog.csdn.net/zhdwjie/article/details/1490741

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

从99年学习delphi开始,我就被它的快速开发迷上了,那时候刚接触编程,对可视化开发特别来劲,原因嘛,不外乎是比C更快的实现啦,这几年来,从delphi的C/S到三层B/S,大大小小也写过一些软件,自认为这delphi也就这么些功能吧,自从最近偶得一本Com本质论,研究了一下VCL源码,才发现它真的神通广大(我也不知道用什么词来形容),最近有些许突破,就在此于大家分享,有不对之处还请指点一二。

说白了,组件只包括二类成员: 属性和方法(我所说的方法包括了事件)

分属于四个部分:

private

protected

public

published

上面四部分的意思在一般的可视化开发书籍当中都会有介绍,这里只相对于delphi作简单概述。

private: 所有私有的成员都放在这里,只能被类自身的方法所访问,而不能被子类访问,对子类透明。也可说只能被单元本身的方法访问。

protected:除了可以被子类继承外,其余和private一样。不能被外界访问。

public: 公有的,在此间声明的属性和方法能被用户调用。

published: 出现在delphi开发环境属性栏中。

首先我们来做一个最简单的控件,不到五分钟,你就会明白delphi的组件面板上的组件是如何制作的了。

新建->New->Component 回车。

然后在Ancestor type:中选择你要继承的父类,这里我们选TComponent.表示继承TComponent的所有属性和方法。

Class Name:中输入将要制作的组件的类名。(我们输入TShowText)

Palette Page:组件将要安装到delphi的哪个面板上。(我们选择Samples,你也可以输入一个新的名字)

下面的就不用我说了吧。

点击OK按钮,delphi自动生成了一个基本的继承自TComponent的控件了,也可以这样理解,我们已经开发了一个与TComponent功能一样强大的控件,不过这不是我们需要的,下面我们继续。

下面说明一下组件本身私有变量的读写方法:

比如我们写了下面一小段:

private

FText : String;

....

/*私有变量不是允许被外界使用的,那么要如何才能对这个FText字符串变量进行操作呢?*/

我们还要在Published后面添加这么一段:

property Text: String read FText write FText;

这里的意思就是指,这个Text属性会出现在delphiSDK的属性栏中,用户修改属性栏中的Text实际上都是在修改FText这个字符串变量。read表示用户读取Text属性实际上读取FText,write当然就表示用户为Text赋值则存在FText字符串变量中啦。

如果在这时候保存,并在delphi中安装.那么我们这个最基本的组件就制作完了。(安装组件方法在最后有介绍)

哈哈,是不是很简单呢?只不过我们的这个组件没有实现什么具体用处罢了。

刚才这里我们介绍了属性,下面我们继续增加功能,来介绍一下方法的使用。

我们在Public后面添加如下:

procedure ShowText();

然后按Ctrl + Alt +C,系统自动为你添加了些方法的实现代码。

接下来我们在写:

procedure TShowText.ShowText();

begin

ShowMessage(FText);

end;

看到了,上面的ShowMessage显示的就是类私有变量的值,到这里大家应该明白了,只有在类本事的方法才能访问私有的变量。这里必须在uses 后面加上Dialogs单元,因为ShowMessage包含在Dialogs单元中,否则通不过。

当然,上面的事件只能在控件中使用,去不能在属性框中的事件栏中出现,为什么呢?因为这里声名的方法只是Public的,纯方法而已,并没有声明为事件。

通过上面的学习,大家是不是已经知道控件的属性和方法是如何写的和调了的了呢?

不过,一个真正意义上的控件是离不开事件的,而事件的调用必须通过消息来驱动,这将在我的下一篇中介绍。

一个功能强大的控件的属性和方法也不是这么容易的,还需要大家多实践,多应用。

下面附带了我写的一个DBGridToExcel控件,功能是把DBGrid中的数据导出到Excel中。大家可以学习一下,做为参考。为个控件中包括了使用属性,方法和我们将在下一篇中讲到的“事件”。

附1: 安装自制控件的方法:

(1).在Component菜单中,选择"Install Component...".

(2).在Unit File name 后面单击“...",选择"*.pas"控件的单元文件,再点击OK。在出现的窗口中单击"install",即安装完毕。

新装的控件即出现在你的面板中。

附2: TDBGridToExcel控件的全部源码,把它拷贝到记事本中,存为.pas文件即可。

unit DBGridToExcel;

{***********************************************************************}

{* *}

{* Export Grid To Word VCL Control for D5 & D6 *}

{* Copyright(C) xiangding 2003.10.1 All rights reserved *}

{* Bug Report: boyxd@163.net *}

{* Author : 小熊 *}

{* *}

{***********************************************************************}

{* *}

{* This is a Simple Version *}

{* *}

{***********************************************************************}

{* *}

{* Install: *}

{* Please Save as file GridToExcel.pas then open the file *}

{* Click the menu item [Component] --> [Install Component] *}

{* Click [Install] button in the Install Component dialog *}

{* after install ,you can find the control at component *}

{* page [sample] *}

{* *}

{***********************************************************************}

{* *}

{* 安装: *}

{* 把附件保存,然后用Delphi打开这个GridToExcel.Pas文件, *}

{* 选择Delphi菜单--〉Component-->Install Component, *}

{* 然后选择Install即可。安装之后,在控件面板的Samples页面上面, *}

{* 熟悉之后,你可以试着设置一些复杂的属性,其他的自己摸索吧, *}

{***********************************************************************}

interface

uses

Windows, StdCtrls, ComCtrls, Messages, DBGrids, Graphics, ExtCtrls,

Forms, DB, ComObj, Controls, SysUtils, Classes;

ResourceString

SPromptExport = \'请等待,正在导出数据……\';

SConnectExcel = \'正在启动Excel,请稍候……\';

SConnectExcelError= \'连接Excel失败,可能没有安装Excel,无法导出.\';

SCancel = \'取消(&C)\';

SError = \'错误\';

SConfirm = \'真的要终止数据的导出吗?\';

SCaption = \'确认\';

SGridError = \'没有指定数据集,请指定数据集控件!\';

type

TDBGridToExcel = class(TComponent)

private

ProgressForm: TForm;

FShowProgress: Boolean;

ExcelApp : Variant;

FTitle: String;

Quit: Boolean;

FOnProgress: TNotifyEvent;

FGrid: TDBGrid; {The Source Grid}

ProgressBar: TProgressBar;

Prompt: TLabel;

FAutoExit: Boolean;

FAutoSize: Boolean;

FDBGrid: TDBGrid;

procedure SetShowProgress(const Value: Boolean);

procedure CreateProgressForm;

procedure ButtonClick(Sender: TObject);

Function ConnectToExcel: Boolean;

procedure ExportDBGrid;

{ Private declarations }

protected

{ Protected declarations }

public

Constructor Create(AOwner: TComponent); override;

Destructor Destroy(); override;

Procedure ExportToExcel; {Export Grid To Excel}

{ Public declarations }

published

{ Published declarations }

property DBGrid: TDBGrid read FDBGrid write FDBGrid;

property Title: String read FTitle write FTitle;

property ShowProgress: Boolean read FShowProgress write SetShowProgress;

property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;

end;

procedure Register;

implementation

procedure Register;

begin

RegisterComponents(\'Samples\', [TDBGridToExcel]);

end;

{ TDBGridToExcel }

procedure TDBGridToExcel.ButtonClick(Sender: TObject);

begin

Quit := MessageBox(ProgressForm.Handle, pchar(SConfirm), pchar(SCaption),

MB_OKCANCEL + MB_ICONINFORMATION) = IDOK;

end;

function TDBGridToExcel.ConnectToExcel: Boolean;

begin

Result := true;

Try

ExcelApp := CreateOleObject(\'Excel.Application\');

ExcelApp.Visible := False;

if Title<>\'\' then ExcelApp.Caption := Title;

ExcelApp.WorkBooks.Add;

except

MessageBox(GetActiveWindow,PChar(SConnectExcelError),PChar(SError),Mb_OK+MB_IconError);

result := false;

end;

end;

constructor TDBGridToExcel.Create(AOwner: TComponent);

begin

inherited;

FShowProgress := True; {Default value was Show the Progress}

FAutoExit := False;

FAutoSize := True;

end;

procedure TDBGridToExcel.CreateProgressForm;

var

Panel : TPanel;

Button : TButton;

begin

if Assigned(ProgressForm) then exit; {Aready Create?}

ProgressForm := TForm.Create(Owner);

With ProgressForm do

begin

Font.Name := \'宋体\';

Font.Size := 10;

BorderStyle := bsNone;

Width := 280;

Height := 120;

BorderWidth := 1;

Color := clBackground;

Position := poOwnerFormCenter;

end;

Panel := TPanel.Create(ProgressForm);

with Panel do { Create Panel }

begin

Parent := ProgressForm;

Align := alClient;

BevelInner := bvNone;

BevelOuter := bvRaised;

Caption := \'\';

end;

Prompt := TLabel.Create(Panel);

with Prompt do { Create Label }

begin

Parent := Panel;

Left := 20;

Top := 25;

Caption := SConnectExcel;

end;

ProgressBar := TProgressBar.Create(panel);

with ProgressBar do { Create ProgressBar }

begin

Step := 1;

Parent := Panel;

Smooth := true;

Left := 20;

Top := 50;

Height := 18;

Width := 260;

end;

Button := TButton.Create(Panel);

with Button do { Create Cancel Button }

begin

Parent := Panel;

Left := 115;

Top := 80;

Caption := SCancel;

onClick := ButtonClick;

end;

ProgressForm.Show;

ProgressForm.Update;

end;

destructor TDBGridToExcel.Destroy;

begin

inherited;

end;

procedure TDBGridToExcel.ExportDBGrid;

var

Data : TDataSet;

ADBGrid: TDBGrid;

i, j : integer;

CurrentPoint : Pointer;

OldBeforeScroll, OldAfterScroll: TDataSetNotifyEvent;

begin

Screen.Cursor := crHourGlass;

try

try

TForm(Owner).Enabled := False;

ExcelApp.DisplayAlerts := false;

ExcelApp.ScreenUpdating := false;

Quit := false;

if ShowProgress then Prompt.Caption := SPromptExport;

ADBGrid := DBGrid;

Data := ADBGrid.DataSource.DataSet;

with ADBGrid do { Insert Table Header }

for i := 1 to Columns.Count do

if Columns[i - 1].Visible then

ExcelApp.Cells[1,i].Value :=Columns[i - 1].Title.Caption;

CurrentPoint := Data.GetBookmark; {Save Current Position}

OldBeforeScroll := Data.BeforeScroll; { Save Old Before Scroll Event handle }

OldAfterScroll := Data.AfterScroll; { Save Old After Scroll Event Handle }

Data.DisableControls; { Disable Control }

Data.BeforeScroll := nil;

Data.AfterScroll := nil;

if ShowProgress then ProgressBar.Max := Data.RecordCount;

i := 2;

Data.First;

while not Data.Eof do { Process All record }

begin

with ADBGrid do { Process one record }

for j := 1 to Columns.Count do

if Columns[j - 1].Visible then

ExcelApp.Cells[i,j].Value := Columns[j - 1].Field.DisplayText;

Inc(i);

Data.Next;

if Assigned(FOnProgress) then FOnProgress(Self);

if ShowProgress then { Update Progress UI }

begin

ProgressBar.StepIt;

Application.ProcessMessages;

if Quit then exit;

end;

end;

except

MessageBox(GetActiveWindow,PChar(SConnectExcelError),Pchar(SError),MB_OK+MB_IConERROR);

end;

ExcelApp.Visible := False;

TForm(Owner).Enabled := True;

Screen.Cursor := crDefault;

if ShowProgress then FreeAndNil(ProgressForm); { Free Progress Form }

ExcelApp.DisplayAlerts := True;

ExcelApp.ScreenUpdating := True;

finally

Data.BeforeScroll := OldBeforeScroll; { Restore Old Event Handle }

Data.AfterScroll := OldAfterScroll;

Data.GotoBookmark(CurrentPoint);

Data.FreeBookmark(CurrentPoint);

Data.EnableControls;

Screen.Cursor := crDefault;

end;

end;

procedure TDBGridToExcel.ExportToExcel;

begin

if DBGrid= nil then raise Exception.Create(SGridError); {No DataSource, then Error}

if ShowProgress then CreateProgressForm; {Whether or not Show the ProgressForm}

if not ConnectToExcel then { Exit when error occer }

begin

if ShowProgress then FreeAndNil(ProgressForm); {release form}

exit;

end;

ExportDBGrid; {begin Export Data}

end;

procedure TDBGridToExcel.SetShowProgress(const Value: Boolean);

begin

FShowProgress := Value;

end;

end.

以上为作者写的一个小控件,有兴趣的朋友可以来信一起学习。

作者Email: boyxd@163.net