全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:4096
推到 Plurk!
推到 Facebook!

Delphi 元件設計初步(一)

 
danny
版主


發表:100
回覆:522
積分:595
註冊:2002-03-11

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-05-03 13:18:23 IP:210.200.xxx.xxx 未訂閱
對 VCL 寫作有興趣的人參考一下 因為我不會將 html 檔貼上來(或是有人能幫我嗎 ?), 請各位移駕一下http://www25.brinkster.com/hltsai/Articles/VclWrite/VclWrite.htm
    <body ="mso-ascii-font-family: Comic Sans MS; mso-hansi-font-family: Comic Sans MS">「的基礎 
code6421 的中選擇要繼承的父階元件我們選內輸入我們要建立的元件名稱這裡順便一提元件的撰寫慣例是用開頭後接的元件組名自定其後才是此元件的名稱詳細定義請參考寫碼標準和「元件型態字首這麼做的原因是不允許重覆如果大家都亂編的話重覆的機率就很高了但我們只是示範如何寫元件就省略元件組名了但新增元件和有何關係我這樣說好了元件物件是類別的實作這樣說比較容易理解了吧!



設好了以後可以在 Unit file name 中選擇存檔的路徑及名稱, 按 OK 後出現如下內容就可以開始寫元件了, 但我先說明各區段的意義一下:
unit AutoClose;    interface    uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;    type
  TAutoClose = class(TComponent)
  private
    { Private declarations }
    私有區段.
    本段只有本元件可看見, 包含變數, function, procedure, property 
    所使用的function, procedure系統自動放於此元件的欄位定義在此如 Text
  protected
    { Protected declarations }
    保護區段.
    只有繼承此元件的[子元件]方可看見及使用, 若不
要將某property開放出來, 只要不在子元件的published 區段不宣告即可隱藏, 
這有點像是散裝模型套件, 零件, 顏料, 膠水都有了, 只等子元件組裝加工, 
一般像 TCustomXXX 此類元件都是(可以繼承, 但在元件盤上是看不到的)
    在此區段宣告可以讓繼承此元件的子元件決定那些要公開那些要隱藏, 因為
VCL如果已經公開 就無法再隱藏, 例如: TEdit繼承自TCustomEdit 幾乎只是宣
告那些要公開而已.
  public
    { Public declarations }
    公開區段.
    只有在 Run Time 時才可以存取本區段, 不會在 
Object Inspector (就是 Design Time時左邊那個視窗)出現, 本區段一般作物
件的方法(method). 虛擬方法(virtual method)可分為虛擬(virtual)及動態
(dynamic)二種, 虛擬的效率快但佔用較多資源, 我想可能用在和資料庫有關的
地方比較多, 動態和虛擬相反, 效率慢但佔用較少資源, 但現在的電腦速度都很
快的時候, 應該 VCL 大部份都採用動態方法, 虛擬方法可以達到 [多形]的效
果, 可讓後代繼承者用 Override 改寫虛 擬(cirtual)及動態(dynamic)二種的
效率差異主要是在VMT(Virtual Method Table) 的不 同, 使用虛擬方法其後代
不論是否有用override改寫, 其父代各個虛擬方法的進入點(佔4Byte)會在子代
的VMT中出現(這也是為何會比較佔用資源的原因, 如果有繼承到五代, 第五代就
記錄了五個進點), 而動態方法如果沒有用override改寫, VMT不會出現此方法的
進入點, 系統必須向上往父階查詢有沒有此動態方法(當然要一些時間) 
  published
    { Published declarations }
    公開設定區段(開放區段)
    本區段會出現在 Object Inspector 中, 可讓 User 在 Design Time 時設定, 大概長得如
    下這樣:
    property Text: string read FText write SetText default '' stored True;
    如果只有 read 沒有 write 則不會出現在Object 
Inspector中, 只能在Run Time使用(如同是在 public 區段中一樣)且此
property 是 read only, default Boolean 是如果設定值剛好是此值則不會存
於.DFM(是Windows Resource File 格式)中可以減少執行檔的大小,default 後
可以放傳回   Boolean 值且不傳值的 function, 例如: IsStoreColor stored 
設為 True (系統內定) 會將此property 值存於 .DFM中, False 不會存檔, 
default 及 stored 可不用此區段會提供RTTI資訊, 讓系統使用(有關RTTI用另
一章節討論)
    read (讀取資料) 及 write (設定資料) 後可接 Field 變數, 如: FText 
或 不帶參數procedure 或 function 為了解決 procedure 及 function不能傳
參數的問題, Delphi提供一個叫 Index 的指令可以達到 procedure 及
function 共用的目的, 宣告方式如下(程式碼在implementation部份):
 
    property Text3: String Index 3 read GetText write SetText3;
    property Text2: String Index 2 read GetText write SetText2;
    property Text: String Index 1 read GetText write SetText;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Samples', [TAutoClose]);
end;    end.
如果您看不懂以上的說明那也很正常, 這並不會影響後面的進度, 好啦 ! 開 始寫作了.
因為我們要設定時間自動可以Close Form, 第一個想到的是用 TTimer 來 作, 那就試試看吧!
unit AutoClose;    interface    uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, extctrls;    type
  TAutoClose = class(TComponent)
  private
    { Private declarations }
    FTimer: TTimer;  
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    { Published declarations }
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Samples', [TAutoClose]);
end;    end.
首先在 private 中宣告一個Field(欄位)叫 FTimer: Timer, 但 Delphi 竟 然不認識 TTimer, 在 TTimer 上按 F1 查到是放在 extctrls 單元中, 我們就 手動加入吧 !
再來宣告產生及毀滅本元件的程式, 在 public 中宣告:
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
以上名稱當然可以改, 但是我不建議改它, 因為這會讓 C++ (就是BCB) 無法 使用本元件, 因為 C++ 的記憶體管理和Delphi不同.
好啦! 現在按 [Ctrl] + [Shift] + [C] 讓Delphi幫我們產生相關程序, 再手動 加工成為如下程式:
private
... 省略 ...
procedure NewTimer(Sender: TObject);
... 省略 ...    constructor TAutoClose.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);      FTimer := TTimer.Create(Self); 
  FTimer.Enabled := False;
  FTimer.OnTimer := NewTimer;
end;    destructor TAutoClose.Destroy;
begin
  FreeAndNil(FTimer);
  inherited Destroy;
end;
由於 Timer 是我們自己要用的物件, 所以要自己產生自己消滅, 加上產生 Timer 程式碼及時間到了以後要做什麼事的procedure (內容先不急得),
我們可以宣告二個 property Enabled(啟動AutoClose) 及 Interval (時 間) 讓User 自己設定處理, 在 published 中宣告如下:
property Enabled: Boolean read GetEnabled write SetEnabled;
property Interval: Cardinal read GetInterval write SetInterval;
一樣按 [Ctrl] + [Shift] + [C] 讓Delphi幫我們產生相關程序, 再改成如 下這樣:
function TAutoClose.GetEnabled: Boolean;
begin
  Result := FTimer.Enabled;
end;    function TAutoClose.GetInterval: Cardinal;
begin
  Result := FTimer.Interval;
end;    procedure TAutoClose.SetEnabled(const Value: Boolean);
begin
  FTimer.Enabled := Value;
end;    procedure TAutoClose.SetInterval(const Value: Cardinal);
begin
  FTimer.Interval := Value;
end;    procedure TAutoClose.NewTimer(Sender: TObject);
begin
  Enabled := False;
  ShowMessage('Hello My First Component');       
end;
這樣基本上元件就寫好了, 因為 Delphi VCL 是以 Package(.BPL)型式存在 的, 所以需有一個 Package 容納我們寫的元件。接著 File ->New,如圖3:

選 Package 再選 OK:

出現如下視窗 按 Mouse 右鍵選 Save:

選擇要存 Package 的檔名及位置, 建議存在 Projects\BPL 下 , 決定好後 選存檔:

回到(圖 5) 畫面, 按一下 Add,出現如圖 7 的視窗:

選[Browse] 將 AutoClose.pas 加入, 再選 OK。

然後選 Install 安裝元件到元件盤中。
好啦! 到元件盤的 Samples 頁中選 AutoClose 到 Form 中測試看看有沒有正常.

可以放到 Form 而且 Object Inspector 內也有這二個自訂property了, 應 該沒問題了吧 ! 將 Enabled 設成 True 測試看看

可以出現 (圖 10) 對話框沒問題了.
但是這元件如果在 Design Time 那不是也有問題嗎 ? 沒錯, 所以要稍微加 工改一下, 再將 TAutoClose 真正要做的事寫到 NewTimer 中, 完整程式碼如 下:
unit AutoClose;    interface    uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;    type
  TAutoClose = class(TComponent)
  private
    { Private declarations }
    FEnabled: Boolean;
    FTimer: TTimer;
    FOnTimer: TNotifyEvent;        procedure NewTimer(Sender: TObject);
    function GetInterval: Cardinal;
    procedure SetEnabled(const Value: Boolean);
    procedure SetInterval(const Value: Cardinal);
  protected
    { Protected declarations }
  public
    { Public declarations }
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;      published
    { Published declarations }
    property Enabled: Boolean read FEnabled write SetEnabled;
    property Interval: Cardinal read GetInterval write SetInterval;
    property OnTimer: TNotifyEvent read FOnTimer write FOnTimer;
  end;    procedure Register;    implementation    procedure Register;
begin
  RegisterComponents('Samples', [TAutoClose]);
end;    { TAutoClose }    constructor TAutoClose.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FTimer := TTimer.Create(Self);
  FTimer.Enabled := False;
  FTimer.OnTimer := NewTimer;
end;    destructor TAutoClose.Destroy;
begin
  FreeAndNil(FTimer);
  inherited Destroy;
end;    function TAutoClose.GetInterval: Cardinal;
begin
  Result := FTimer.Interval;
end;    procedure TAutoClose.SetEnabled(const Value: Boolean);
begin
  FEnabled := Value;
  // 確定在 Run Time 時才有作用
  if not (csDesigning in ComponentState) then
    FTimer.Enabled := Value; 
end;    procedure TAutoClose.SetInterval(const Value: Cardinal);
begin
  FTimer.Interval := Value;
end;    procedure TAutoClose.NewTimer(Sender: TObject);
begin
  Enabled := False;  // 先將 FTimer 關掉避免重覆觸發.
  // 如果 OnTimer 內有程式則執行.
  if Assigned(FOnTimer) then
    FOnTimer(Sender);
    
  (Owner as TForm).Close;
end;    end.
以上程式已經將 procedure GetEnabled 移除, 並宣告一個 FEnabled 欄 位, 這樣作的目的是可以讓我們在 Design 中設 Enabled := True , 但不會真 正的觸發 FTimer , 當然 procedure SetEnabled 也要改寫才行, 另外再增加一 個 FOnTimer , 可以讓User 在 Form Close 前處理一些事情; 完成後再寫一個 程式測試一下此元件是否可以正常運作, 例如: 在Design Time 設 Enabled := True 看在Design Time 會不會動作, Run Time 是否會在設定時間 時Close Form, 如果沒問題那此元件就測試完成了; 但是您有沒有覺得內定的元 件Icon有點醜, 而且如果每一個元件 ICON 都長得一樣User也會弄錯, 接下來做 元件 ICON 吧!
選 Image Editor , File -> New -> Component Resource File (.dcr)

按 Mouse 右鍵, New -> Bitmap

圖型長寬設成 24 x 24 這是 Delphi 元件盤可以接受的ICON大小

按 Mouse 右鍵, Rename 輸入 Class Name TAutoClose

在 Class Name 上, 快按 Mouse 左鍵二次, 開始畫 ICON 內容, 您也可以按
[Ctrl] + [I] 放大
[Ctrl] + [U] 縮小

存檔檔名設 AutoClose.dcr 並且必需和 AutoClose.pas 同目錄才可以重新 Install TAutoClose 的 Package (MyPackage.dpk), 如果 AutoClose.dcr 沒有 在 Package 中, 您要手動加進來, 完成後看 Samples 的頁面:

已經有我們自己設計的 ICON 在上面了…..

前面講解的不只是如何寫一個元件, 還包含程式的debug方法及製造流程, 雖然 有一點繁複但是卻是問題最少, 比較不會發生程式寫完了, 卻發生程式也完蛋了 的情形, 必竟良好的程式設計習慣也是很重要的.

附錄A: 訊息的應用

訊息(Message)的應用很廣, 精確的說,如果沒有訊息, Borland 的 VCL 應 該架構不出來吧!
訊息的使用時機大部份是補您在元件設計上的不足, 或者是為了程式的精簡 而使用, 像有時候需要對很多的元件作處理(例如:重畫元件), 如果一個一個去 處理, 是乎不是個好方法, 尤其元件種類繁多, 這時用訊息就是很好的選 擇.
訊息可以只對某元件傳送或是用廣播的方式送出, 但是接受的元件必需有相 對應的處理程序, 而且必須是元件的 Month, 聽起來好像和網路的處理方式一 樣, 沒錯! 是一樣的.
VCL其實已經將訊息處理機制包含在裡面了, 在所有元件(物件)的始祖 TObject 中已經包含訊息處理機制, 也就是說所有的元件都有處理訊息的能力, 不過 VCL 將訊息包裝的比較簡單了, 所以使用起來就很簡單了, 接下來我就來 示範如何使用訊息.

元件內的訊息廣播:

要能夠做訊息的廣播必須是 TWinControl 的後代子孫, 廣播使用的是 BroadCast 方法, 要做廣播大慨像以下這樣寫法
var 
  Msg: TMessage;
begin
  Msg.Msg := CM_REPAINT_BY_SELF;
  Msg.WParam := 0;
  Msg.LParam := 0;
  Msg.Result := 0;
  (Self as TWinControl).Broadcast(Msg);
end;
其中 CM_REPAINT_BY_SELF; 是我自己定的訊息, 當然您也可以使用 Windows 的訊息, 他們定義在Windows.pas 中, 如果要定義自定訊息要像以下這 樣
const
  CM_REPAINT_BY_SELF = WM_USER + 100;
自定訊息必須以 WM_USER + 100 開始一直到 $7FFF 結束, 我想 Windows 提 供的應該夠用了, 這個區域以外請不要使用, 因為 Windows 已經定義了這區 域, 如果重覆定義可能會有想不到的問題發生

接受訊息部份程式像以下這樣:
procedure WMREPAINT_BY_SELF(var Message: TMessage); message CM_REPAINT_BY_SELF;    … 省略 …    procedure TahDBEdit.WMREPAINT_BY_SELF(var Message: TMessage);
begin
  Invalidate;
end;
以上例子只是收到訊息重畫元件而已, 當然您可以做很複雜的事. 不過以上範例最多只有侷限在一個 TForm 中而已.

待續...

2. TDoHotKey 簡單設定 HotKey
3. 有底圖的TLabel
4. TStatusProcess 在 TStatusBar 上加上 TProcessBar 功能
5. 資料感知元件:
6. 元件協同處理:
7. 自製密碼詢問元件:
8. 不同程序(Processe)程式(EXE),視窗(Form)的訊息廣播:
</body>
站長表揚:優良文章
------
將問題盡快結案也是一種禮貌!
領航天使
站長


發表:12216
回覆:4186
積分:4084
註冊:2001-07-25

發送簡訊給我
#2 引用回覆 回覆 發表時間:2002-05-03 17:14:35 IP:61.219.xxx.xxx 未訂閱
danny兄: 真是佩服您,內容一級棒不說,連排版都是一流的,該粗體字的地方就粗體,該大則大,該變色就變色,不知您是否考慮出書,一定暢銷! 加油喔,站長支持您! ~~~Delphi K.Top討論區站長~~~
------
~~~Delphi K.Top討論區站長~~~
danny
版主


發表:100
回覆:522
積分:595
註冊:2002-03-11

發送簡訊給我
#3 引用回覆 回覆 發表時間:2002-05-03 17:28:12 IP:210.200.xxx.xxx 未訂閱
引言: danny兄: 真是佩服您,內容一級棒不說,連排版都是一流的,該粗體字的地方就粗體,該大則大,該變色就變色,不知您是否考慮出書,一定暢銷! 加油喔,站長支持您!
首先謝謝您幫我改成能直接顯示(但圖型好像看不到, 位置也偏了) 其實排版是 煥麟 兄幫我改的, 我也認為排版一流, 他是用 Frontpage 2000 編輯, 我之前是用 WORD 編輯(排版很醜), 今天才知道要用 Frontpage, 真不好意思 ... 出書就不必了, 我還沒到出書的水準 ... 不過還是謝謝您的鼓勵 !!!
------
將問題盡快結案也是一種禮貌!
領航天使
站長


發表:12216
回覆:4186
積分:4084
註冊:2001-07-25

發送簡訊給我
#4 引用回覆 回覆 發表時間:2002-05-03 17:34:45 IP:61.219.xxx.xxx 未訂閱
引言: 首先謝謝您幫我改成能直接顯示(但圖型好像看不到, 位置也偏了) 其實排版是 煥麟 兄幫我改的, 我也認為排版一流, 他是用 Frontpage 2000 編輯, 我之前是用 WORD 編輯(排版很醜), 今天才知道要用 Frontpage, 真不好意思 ... 出書就不必了, 我還沒到出書的水準 ... 不過還是謝謝您的鼓勵 !!!
因為是在資料庫中的排版不比FrontPage的Html方便,雖然我已開啟HTML語法支援,但仍無法完全相容於FrontPage,版面排歪請見諒! 至於圖形應該可以出的來啊?是不是要按重新整理才可以? 可否請您再試試看,告訴我結果,謝謝! 慢慢累積專業的經驗,有特殊風格的書就會有特定族群的讀者存在! ~~~Delphi K.Top討論區站長~~~
------
~~~Delphi K.Top討論區站長~~~
danny
版主


發表:100
回覆:522
積分:595
註冊:2002-03-11

發送簡訊給我
#5 引用回覆 回覆 發表時間:2002-05-04 09:29:32 IP:210.200.xxx.xxx 未訂閱
引言: 因為是在資料庫中的排版不比FrontPage的Html方便,雖然我已開啟HTML語法支援,但仍無法完全相容於FrontPage,版面排歪請見諒! 至於圖形應該可以出的來啊?是不是要按重新整理才可以? 可否請您再試試看,告訴我結果,謝謝! 慢慢累積專業的經驗,有特殊風格的書就會有特定族群的讀者存在!
不好意思! 經我測試圖形部份看不到是原網站的問題... 其實這篇文章是我讀了大約十本以上的書(很多書 VCL 設計都只講一部份)及我設計元件所累計下的經驗(大約30個左右), 因為很冷門所以應該沒有出書的價值, 寫寫文章 post 上來是可以... 發表人 - danny 於 2002/05/04 09:30:00
------
將問題盡快結案也是一種禮貌!
天外來客
初階會員


發表:22
回覆:199
積分:44
註冊:2001-11-27

發送簡訊給我
#6 引用回覆 回覆 發表時間:2002-05-06 04:00:48 IP:61.10.xxx.xxx 未訂閱
我很喜歡這主題, 很謝謝 Danny.
caesar
一般會員


發表:9
回覆:8
積分:3
註冊:2002-03-12

發送簡訊給我
#7 引用回覆 回覆 發表時間:2002-05-08 16:21:49 IP:61.220.xxx.xxx 未訂閱
受益良多,感恩!
------
Caesar Come
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#8 引用回覆 回覆 發表時間:2003-11-18 22:50:14 IP:140.135.xxx.xxx 未訂閱
不好意思,請問一下,有沒有含完整圖片的文件或連結呢?
bruce0211
版主


發表:157
回覆:668
積分:279
註冊:2002-06-13

發送簡訊給我
#9 引用回覆 回覆 發表時間:2003-11-19 08:38:43 IP:211.21.xxx.xxx 未訂閱
引言: 不好意思,請問一下,有沒有含完整圖片的文件或連結呢? < face="Verdana, Arial, Helvetica"> http://sun.cis.scu.edu.tw/~nms9115/articles/delphi/VclWrite/VclWrite.htm google 上找一下同名主題就有了
taishyang
站務副站長


發表:377
回覆:5490
積分:4563
註冊:2002-10-08

發送簡訊給我
#10 引用回覆 回覆 發表時間:2003-11-19 12:08:28 IP:61.231.xxx.xxx 未訂閱
bruce0211您好,謝謝您
系統時間:2024-11-25 9:44:46
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!