第十九章-Delphi自訂組件開發(二)(3)

來源:互聯網
上載者:User

這三句運算式使用RegisterPropertyEditor三種不同的用法:

● 第一種最典型

它註冊了用於所有TComponent類型屬性的屬性編輯器TComponentProperty。通常,當為某種類型屬性註冊屬性編輯器時,它就能應用於所有這種類型的屬性,因此,第二和第三個參數為nil。

● 第二個運算式註冊特定類型的屬性編輯器

它為特定組件的特定屬性註冊屬性編輯器,在這種情況下,編輯器用於所有組件的Name屬性。

● 第三個運算式介於第一個和第二個運算式之間

它為組件TMenu的TMenuItem類型的所有屬性註冊了屬性編輯器。

19.2.2.2 建立事件

事件是組件的很重要的部分。事件是組件必須響應的系統事件與響應事件的一段代碼的聯結。響應代碼被稱為事件處理過程,它總是由組件使用者來編寫。通過使用事件,應用開發人員不需要改變組件本身就能定製組件的行為。作為組件編寫者,運用事件能使應用發者定製所有的標準Delphi組件。要建立事件,應當理解:

● 什麼是事件

● 怎樣實現標準事件

● 怎樣定義自己的事件

1. 什麼是事件

事件是聯結發生的事情與某些代碼的機制,或者說是方法指標,一個指向特定對象執行個體的特定方法的指標。從組件使用者的角度,事件是與系統事件(如OnClick)有關的名稱,使用者能給該事件賦特定的方法供調用。例如,按鈕Buttonl有OnClick方法,預設情況下Delphi在包含該按鈕的表單中產生一個為ButtonlClick的方法,並將其賦給OnClick。當一個Click事件發生在按鈕上時,按鈕調用賦給OnClick的方法ButtonlClick:

組件使用者將事件看作是由使用者編寫的代碼,而事件發生時由系統調用的處理辦法。

從組件編寫者角度事件有更多的含義。最重要的是提供了一個讓使用者編寫代碼響應特定事情的場所。

要編寫一個事件,應當理解:

● 事件和方法指標

● 事件是屬性

● 事件處理過程類型

● 事件處理過程是可選的

⑴ 事件是方法指標

Delphi使用方法指標實現事件。一個方法指標是指向特定對象執行個體的特定方法的特定指標。作為組件編寫者,能將方法指標作為一種容器。你的代碼一發現事情發生,就調用由使用者定義的方法。 

方法指標的工作方式就象其它的過程類型,但它們保持一個隱含的指向對象執行個體的指標。所有的控制都繼承了一個名為Click的方法,以處理Click事件。Click方法調用使用者的Click事件處理過程。

procedure TControl.Click;

begin

if Assigned(OnClick ) then OnClick( Self );

end;

如果使用者給Control的OnClick事件賦了處理過程(Handle),那滑鼠點按Control時將導致方法被調用。

⑵ 事件是屬性

組件採用屬性的形式實現事件。不象大多數其它屬性,事件不使用方法來使實現read和write部分。事件屬性使用了相同類型的私人對象域作為屬性。按約定網域名稱在屬性名稱前加“F”。例如OnClick方法的指標,存在TNotifyEvent類型FOnClick域中。OnClick事件屬性的聲明如下:

type

TControl=class ( TComponent )

private

FOnClick: TNofiFyEvent; { 聲明儲存方法指標的域 }

protected

property OnClick: TNotifyEvent read FOnClick write FOnClick;

end;

象其它類型的屬性一樣,你能在運行時設定和改變事件的值。將事件做成屬性的主要好處是組件使用者能在設計時使用Object Inspector設定事件處理過程。

⑶ 事件處理過程類型

因為一個事件是指向事件處理過程的指標,因此事件屬性必須是方法指標類型,被用作事件處理過程的代碼,必須是相應的對象的方法。

所有的事件方法都是過程。為了與所給類型的事件相容,一個事件處理過程必須有相同數目和相同類型的相同順序的參數。Delphi定義了所有標準事件處理過程的方法類型,當你建立自己的事件時,你能使用已有的事件類型,或建立新的。雖然不能用函數做事件處理過程,但可以用var參數得到返回資訊。

在事件處理過程中傳遞var參數的典型例子是TKeyPressEvent類型的KeyPressed事件。TKeyPressEvent定義中含有兩個參數。一個指示哪個對象產生該事件。另一個指示那個鍵按下:

type

TKeyPressEvent=procedure( Sender: TObject; var key: char) of Object;

通常key參數包含使用者按下鍵的字元。在某些情況下,組件的使用者可能想改變字元值。例如在編輯器中強制所有字元為大寫,在這種情況下,使用者能定義下列的事件處理過程:

procedure TForml.EditlKeyPressed( Sender: TObject; var key: char);

begin

key := Upcase( key );

end;

也可使用var參數讓使用者覆蓋預設的處理。

⑷ 事件處理過程是可選的

在為組件建立事件時要記住組件使用者可能並不編寫該事件的處理過程。這意味著你的組件不能因為組件使用者沒有編寫處理代碼而出錯。這種事件處理過程的可選性有兩個方面:

① 組件使用者並非不得不處理事件

事件總是不斷地發生在Windows應用程式中。例如,在組件上方移動滑鼠就引起Windows發送大量的Mouse-Move訊息給組件,組件將滑鼠訊息傳給OnMouseMove事件。在大多數情況下,組件使用者不需要關心MouseMove事件,這不會產生問題,因為組件不依賴滑鼠事件的處理過程。同樣,自訂組件也不能依賴使用者的事件處理過程。

② 組件使用者能在事件處理過程寫任意的代碼

一般說來,對使用者在事件處理過程中的代碼沒有限制。Delphi組件庫的組件都支援這種方式以使所寫代碼產生錯誤的可能性最小。顯然,不能防止使用者代碼出現邏輯錯誤。

2. 怎樣實現標準事件

Delphi帶的所有控制繼承了大多數Windows事件,這些就是標準事件。儘管所有這些事件都嵌在標準控制中,但它們預設是protected,這意味著使用者無法訪問它們,當建立控制時,則可選擇這些事件使使用者可用。將這些標準事件嵌入自訂控制需要考慮如下:

● 什麼是標準事件

● 怎樣使事件可見

● 怎樣修改標準事件處理過程

⑴ 什麼是標準事件

有兩種標準事件:用於所有控制和只用於標準Windows控制。

最基本的事件都定義在對象TControl中。視窗控制、圖形控制和自訂控制都繼承了這些事件,下面列出用於所有控制的事件:

OnClick OnDragDrop OnEndDrag OnMouseMove

OnDblClick OnDragOver OnMouseDown OnMouseUp

所有標準事件在TControl中都定義了相應的protected動態方法,只是沒有加“On”例如OnClick事件調用名為Click的方法。

標準控制(從TWinControl繼承)具有下列事件:

OnEnter OnKeyDown OnkeyPress OnKeyUp OnExit

正如TControl中的標準事件,視窗控制也有相應protected動態方法。

⑵ 怎樣使事件可見

標準事件的聲明是protected,如果想使使用者在運行時或設計時能訪問它們,就需要將它們重聲明為public和 published。重聲明屬性而不描述它的實現將繼承相同的實現方法,只是改變了存取層級。例如,建立一個組件並使它的OnClick事件出現在運行時,你可增加下面的組件聲明:

type

TMyControl=class(TCustomControl)

published

property OnClick; { 使OnClick在objectinspector中可見 }

end;

⑶ 怎樣修改標準事件處理過程

如果想修改自訂組件響應某種事件的方法,可以重寫代碼並將其賦給事件。將聯結每個標準事件的方法聲明的protected是出於慎密的考慮。通過,覆蓋實現方法,能修改內部事件處理過程,通過調用繼承的方法,能保持標準事件處理過程。

調用繼承的方法的順序是很重要的。一般首先調用繼承的方法,允許使用者的事件處理過程代碼在你的定製代碼前執行。然而也有在調用繼承的方法之前執行自己的代碼情況出現。

下面是一個覆蓋Click事件的例子:

procedure TMyControl.Click;

begin

inherited Click; { 執行標準處理,包括呼叫事件處理過程你自己的定製代碼 }

end;

3. 定義自己的事件

定義全新的事件的情況是很少見的。只有當組件的行為完全不同於任何其它事件才需要定義新事件。定義新事件一般包含三個步驟:

● 觸發事件

● 定義處理過程類型

● 聲明事件

● 呼叫事件

⑴ 觸發事件

定義自己的事件要遇到的第一個關鍵是:當使用標準事件時你不需要考慮由什麼觸發事件。對某些事件,問題是顯然的。例如:一個MouseDown事件是在使用者按下滑鼠的左鍵時發生,Windows給應用發送WM_LBUTTONDOWN訊息。接到訊息後,一個組件調用它的MouseDown方法,它依次調用使用者的OnMouseDown事件處理過程代碼。但是有些事件卻不是那麼可以描述清楚的。例如:滾行杠有一個OnChange事件,可被各種情況觸發,包括按鍵、滑鼠點按或其它按制中的改變。當定義事件時,你必須使各種情況的發生調用正確的事件。

這裡有TControl處理WM_LBUTTONDOWN訊息的方法,DoMouseDown是私人的實現方法,它提供了一般的處理左、右和中按鈕的方法,並將Windows訊息的參數轉換為MouseDown方法的值。

type

TControl = class(TComponent)

private

FOnMouseDown: TMouseEvent;

procedure DoMouseDown(var Message: TWMMouse; Button: TMouseButton;

Shift: TShiftState);

procedure WMLButtonDown(var Message: TWMLButtonDown);

message M_LBUTTONDOWN;

protected

procedure MouseDown(Button: TMouseButton; Shift: TShiftState;

X, Y: Integer); dynamic;

end;

procedure TControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

begin

if Assigned(FOnMouseDown) then

FOnMouseDown(Self, Button, Shift, X, Y); { 呼叫事件處理過程 }

end;

procedure TControl.DoMouseDown(var Message: TWMMouse; Button: TMouseButton;

Shift: ShiftState);

begin

with Message do

MouseDown(Button, KeysToShiftState(Keys) + Shift, XPos, YPos); { 調用動態方法 }

end;

procedure TControl.WMLButtonDown(var Message: TWMLButtonDown);

begin

inherited; { perform default handling }

if csCaptureMouse in ControlStyle then

MouseCapture := True;

if csClickEvents in ControlStyle then

Include(FControlState, csClicked);

DoMouseDown(Message, mbLeft, []); { 調用常規的mouse-down 方法 }

end;

當兩種事情-狀態變化和使用者互動—發生時,處理機制是相同的,但過程稍微不同。使用者互動事件將總是由Windows訊息觸發。狀態改變事件也與Windows訊息有關,但它們也可由屬性變化或其它代碼產生。你擁有對自訂事件觸發的完全控制。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.