Delphi 7事件的多處理機制

2021-04-13 07:12:54 字數 4543 閱讀 6392

delphi 7事件的多處理機制

allen tao

2007-08-19

首先解釋一下這個題目。在我使用delphi 7的過程中發現,乙個物件的事件只能被乙個過程處理。如果多次給這個物件的事件賦給處理事件的過程,最後真正處理事件的將是最後賦值的那個過程。例如,有類tmyclass中定義了乙個事件onsomefired,在類tclientclass中該類被例項化,它的事件被處理。如下所示:

constructor tclientclass.create;

varmyobj: tmyclass;

begin

//…myobj:= tmyclass.create;

myobj.onsomefired:= somefired1;

myobj.onsomefired:= somefired2;

這裡的somefired1與somefired2都是tclientclass中定義的處理過程。其最終的結果是當onsomefired事件發生時,只有somefired2被呼叫。

但在程式設計的實際中,往往需要乙個事件被多個方法所處理。為此,我參考了一些對這個問題的解決辦法,總結得出了乙個自己的方法,稱為事件的多處理機制。

原理

delphi 7中的事件本質上是一種過程指標。但事件型別在定義時要比一般過程指標在最後多乙個「of object」,如常用的tnotifyevent的定義是:

tnotifyevent = procedure(sender: tobject) of object;

因此,給乙個事件屬性賦值,也就是給乙個類的過程指標型別的成員變數賦值,當然是最後一次的賦值才有效。要想多次賦值有效就必須有乙個資料結構把每次賦值賦給的過程指標變數都記錄下來,最合適的資料結構當然是列表tlist。但如果在每乙個有事件的類中都加乙個記錄事件賦值的列表物件,自然是不方便的,而且使用這個列表的**在不同類中也差不多,應該抽取出來形成乙個類。這個類就是事件多處理機制的核心內容。

做法

要記錄事件處理過程,就需要將過程指標變數放入列表物件中。但列表物件只能新增指標型別物件(也就是引用型別),而過程指標變數是指型別變數,不能直接新增。這就需要有乙個類對過程指標變數進行包裝,轉化為指標型別物件。於是,先要定義包裝類tcallmethod,如下所示:

tcallmethod = class

private

_callback: tmethod;

public

property callback: tmethod read _callback write _callback;

end;

這裡的tmethod是delphi預定義的記錄型別,任何過程指標變數都可以強制轉化為這種型別。之後,再定義記錄處理過程的類,如下所示:

teventobject = class

private

calllist: tlist;

function getitem(i: integer): tmethod;

function getcount: integer;

public

constructor create;

procedure add(p: tmethod);

procedure remove(p: tmethod);

property count: integer read getcount;

property items[i: integer]: tmethod read getitem;  default;

end;

下面是實現部分:

constructor teventobject.create;

begin

calllist:= tlist.create;

end;

procedure teventobject.add(p: tmethod);

vara: tcallmethod;

begin

a:= tcallmethod.create;

a.callback:= p;

calllist.add(a);

end;

procedure teventobject.remove(p: tmethod);

vari: integer;

begin

for i:= 0 to getcount - 1 do

if (tcallmethod(calllist[i]).callback.code = p.code) and

(tcallmethod(calllist[i]).callback.data = p.data) then

calllist.delete(i);

end;

function teventobject.getcount: integer;

begin

result:= calllist.count;

end;

function teventobject.getitem(i: integer): tmethod;

vara: tcallmethod;

begin

a:= tcallmethod(calllist[i]);

result:= a.callback;

end;

從上面的**可以看到,teventobject的目的是包裝tlist物件,遮蔽了tlist類的大多數方法,只對外暴露了2個過程、1個屬性與1個索引,分別用於新增、刪除處理事件過程、獲得過程個數及通過序號檢索記錄的過程變數。

使用

使用時,在需要使用事件的類中將事件的型別由過程指標改為teventobject,即可使該事件擁有多處理的能力。如下面**所示:

tmyclass=class

private

somefired: teventobject;

public

constructor create;

procedure dosth;

property onsomefired: teventobject read somefired write somefired; // 多處理事件

end;

以下是實現**:

constructor tmyclass.create;

begin

self.somefired:= teventobject.create;

end;

procedure tmyclass.dosth;

vari: integer;

method: tnotifyevent;

begin

if somefired.count > 0 then

for i:= 0  to somefired.count - 1 do

begin

method:= tnotifyevent(somefired[i]); // 在該類中事件的真正型別是tnotifyevent,因此在觸發事件時先要轉成這種型別的過程指標後再進行呼叫

method(self);

end;

end;

定義了乙個包含多處理事件的類後,再看看這種類如果在其客戶類中被呼叫。如以下**:

varmyobj: tmyclass;

//…myobj:= tmyclass.create;

myobj.onsomefired.add(somefired1);

myobj.onsomefired.add(somefired2);

當客戶類**中呼叫tmyclass的dosth方法時,事件將被觸發,而2個處理過程somefired1與somefired2則會依次呼叫,實現多處理的目的。

再發展一步

上面的teventobject類可以實現事件多處理的目的,但它對加入其中的過程指標型別沒有檢查,這是乙個隱患。因此可以針對每一種事件要求的過程指標型別從teventobject繼承乙個類,實現型別檢查。如要求事件的型別是tnotifyevent,就可以繼承乙個tnotifyeventobject類,如下面**:

tnotifyeventobject = class(teventobject)

public

procedure add(p: tnotifyevent); overload;

procedure remove(p: tnotifyevent); overload;

end;

以下是實現部分:

procedure tnotifyeventobject.add(p: tnotifyevent);

begin

inherited add(tmethod(p));

end;

procedure tnotifyeventobject.remove(p: tnotifyevent);

begin

inherited remove(tmethod(p));

end;

在這個類中過載了新增與移除方法,可以有效地對過程指標型別進行檢查。

以上是我對delphi 7中事件多處理問題的乙個解決辦法。如有興趣,請光臨我的部落格http://allentao430.spaces.live.com賜教。

Delphi異常處理機制

delphi的異常處理方式有兩種 try.except.end try.finally.end try.except主要用於捕獲異常,只有出現異常的時候才會執行except部分。try.finally主要用於資源釋放,無論try語句塊是否有異常都會執行finally語句塊。如下面的 1 try2 r...

事件委託處理機制

事件委託處理機制實現了在兩個沒有聯絡的物件之間建立一種事件收發機制,事件傳送方和事件監聽方互相不必知道對方的任何細節,避免物件之間的依賴,降低系統耦合性。直接上 event.h pragma once include using std map ifdef dll export define dll...

android事件處理機制

談到android事件處理,最複雜的就是對touch事件的處理,因為touch事件包括 down,move,up,cancle和多點觸控等多種情況,多點觸控的情況先不討論,因為touch有這麼多的狀態,所以touch相對來說是最難處理的,下面就來討論一下android系統是如何處理touch事件的 ...