天天看點

淺談控件(元件)制作方法一(附帶一delphi導出資料到Excel的元件執行個體)(原創)

從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功能一樣強大的控件,不過這不是我們需要的,下面我們繼續。

下面說明一下元件本身私有變量的讀寫方法:

  比如我們寫了下面一小段:

    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: [email protected]                                *}

{*            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)

    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 declarations }

    Constructor Create(AOwner: TComponent); override;

    Destructor Destroy(); override;

    Procedure ExportToExcel;   {Export Grid To Excel}

    { Public declarations }

    { 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

  RegisterComponents('Samples', [TDBGridToExcel]);

{ TDBGridToExcel }

procedure TDBGridToExcel.ButtonClick(Sender: TObject);

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

    MB_OKCANCEL + MB_ICONINFORMATION) = IDOK;

function TDBGridToExcel.ConnectToExcel: Boolean;

  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;

constructor TDBGridToExcel.Create(AOwner: TComponent);

  inherited;

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

  FAutoExit := False;

  FAutoSize := True;

procedure TDBGridToExcel.CreateProgressForm;

var

  Panel  : TPanel;

  Button : TButton;

  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;

  Panel := TPanel.Create(ProgressForm);

  with Panel do { Create Panel }

    Parent := ProgressForm;

    Align := alClient;

    BevelInner := bvNone;

    BevelOuter := bvRaised;

    Caption := '';

  Prompt := TLabel.Create(Panel);

  with Prompt do { Create Label }

    Parent := Panel;

    Left := 20;

    Top := 25;

    Caption := SConnectExcel;

  ProgressBar := TProgressBar.Create(panel);

  with ProgressBar do { Create ProgressBar }

    Step := 1;

    Smooth := true;

    Top := 50;

    Height := 18;

    Width := 260;

  Button := TButton.Create(Panel);

  with Button do { Create Cancel Button }

    Left := 115;

    Top := 80;

    Caption := SCancel;

    onClick := ButtonClick;

  ProgressForm.Show;

  ProgressForm.Update;

destructor TDBGridToExcel.Destroy;

procedure TDBGridToExcel.ExportDBGrid;

  Data   : TDataSet;

  ADBGrid: TDBGrid;

  i, j   : integer;

  CurrentPoint : Pointer;

  OldBeforeScroll, OldAfterScroll: TDataSetNotifyEvent;

  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;

    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;

procedure TDBGridToExcel.ExportToExcel;

  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 }

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

    exit;

  ExportDBGrid;  {begin Export Data}