淺談控制元件(元件)製作方法一(附帶一delphi匯出資料到Excel的元件例項)(原創) (轉)

worldblog發表於2007-08-17
淺談控制元件(元件)製作方法一(附帶一delphi匯出資料到Excel的元件例項)(原創) (轉)[@more@]

從99年學習開始,我就被它的開發迷上了,那時候剛接觸,對視覺化開發特別來勁,原因嘛,不外乎是比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的,純方法而已,並沒有宣告為事件。
透過上面的學習,大家是不是已經知道控制元件的屬性和方法是如何寫的和調了的了呢?
不過,一個真正意義上的控制元件是離不開事件的,而事件的呼叫必須透過訊息來,這將在我的下一篇中介紹。
 一個功能強大的控制元件的屬性和方法也不是這麼容易的,還需要大家多實踐,多應用。
下面附帶了我寫的一個GridTo控制元件,功能是把DBGrid中的資料匯出到Excel中。大家可以學習一下,做為參考。為個控制元件中包括了使用屬性,方法和我們將在下一篇中講到的“事件”。

附1: 安裝自制控制元件的方法:
  (1).在Component選單中,選擇"Install Component...".
  (2).在Unit File name 後面單擊“...",選擇"*.pas"控制元件的單元,再點選OK。在出現的視窗中單擊"install",即安裝完畢。
新裝的控制元件即出現在你的皮膚中。

附2: TDBGridToExcel控制元件的全部原始碼,把它複製到記事本中,存為.pas檔案即可。
unit DBGridToExcel;

{***********************************************************************}
{*  *}
{*  Export Grid To VCL Control for D5 & D6  *}
{*  Copyright(C) xiangding .10.1 All rights reserved  *}
{*  Report: to:boyxd@163">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] --&gt [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--&gtInstall Component,  *}
{*  然後選擇Install即可。安裝之後,在控制元件皮膚的Samples頁面上面,  *}
{*  熟悉之後,你可以試著設定一些複雜的屬性,其他的自己摸索吧,  *}
{***********************************************************************}
interface

uses
  , StdCtrls, ComCtrls, Messages, DBGrids, Graphics, ExtCtrls,
  Forms, DB, ComObj, Controls, SysUtils, Classes;

ReString
  SPromptExport  = '請等待,正在匯出資料……';
  nnectExcel  = '正在啟動Excel,請稍候……';
  SConnectExcelError= '連線Excel失敗,可能沒有安裝Excel,無法匯出.';
  SCancel  = '取消(&C)';
  SError  = '錯誤';
  SConfirm  = '真的要終止資料的匯出嗎?';
  SCaption  = '確認';
  SGrrror  = '沒有指定資料集,請指定資料集控制元件!';

type
  TDBGridToExcel = class(TComponent)
  private
  Progresorm: 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: T);
  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?}

  ProgressFo:= 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.

以上為作者寫的一個小控制元件,有興趣的朋友可以來信一起學習。
作者:
下一篇將主要講術元件事件的寫法和技巧。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-963122/,如需轉載,請註明出處,否則將追究法律責任。

相關文章