• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Chip Studio

            常用鏈接

            統計

            最新評論

            Delphi 7事件的多處理機制

            Delphi 7事件的多處理機制
            Allen Tao
            2007-08-19

              首先解釋一下這個題目。在我使用Delphi 7的過程中發現,一個對象的事件只能被一個過程處理。如果多次給這個對象的事件賦給處理事件的過程,最后真正處理事件的將是最后賦值的那個過程。例如,有 類TMyClass中定義了一個事件OnSomeFired,在類TClientClass中該類被實例化,它的事件被處理。如下所示:
            constructor TClientClass.Create;
            var
              myObj: 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);
            var
              a: TCallMethod;
            begin
              a:= TCallMethod.Create;
              a.Callback:= p;
              callList.Add(a);
            end;

            procedure TEventObject.Remove(p: TMethod);
            var
              i: 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;
            var
              a: 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;
            var
              i: 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;
              定義了一個包含多處理事件的類后,再看看這種類如果在其客戶類中被調用。如以下代碼:
            {類TClientClass中}
            var
              myObj: 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;
              在這個類中重載了添加與移除方法,可以有效地對過程指針類型進行檢查。


            posted on 2008-02-07 03:06 MyChip 閱讀(412) 評論(0)  編輯 收藏 引用

            欧美伊人久久大香线蕉综合69| 亚洲精品午夜国产VA久久成人| 伊人久久综合成人网| 99久久精品国内| 热久久国产欧美一区二区精品| 久久婷婷人人澡人人| 91久久婷婷国产综合精品青草| 精品国产VA久久久久久久冰| 99精品国产99久久久久久97| 激情伊人五月天久久综合| 中文字幕亚洲综合久久| 国产精品久久99| 日韩久久无码免费毛片软件| 久久精品蜜芽亚洲国产AV| 伊人久久综合精品无码AV专区| 狠狠色丁香久久综合五月| 久久成人国产精品| 久久影院午夜理论片无码 | 久久免费小视频| 久久免费的精品国产V∧ | 香蕉99久久国产综合精品宅男自 | 久久国产欧美日韩精品免费| 久久精品人人槡人妻人人玩AV| 精品久久久久一区二区三区| 99久久免费只有精品国产| 亚洲国产精品18久久久久久| 久久国产免费| 欧美日韩精品久久久久| 久久久99精品一区二区 | 日韩久久无码免费毛片软件| 青青青青久久精品国产h| 人妻久久久一区二区三区| www.久久99| 99久久无码一区人妻a黑| 久久中文骚妇内射| 亚洲AV日韩AV天堂久久| 久久天天躁狠狠躁夜夜avapp | 久久精品国产91久久综合麻豆自制 | 一本一本久久A久久综合精品| 四虎国产精品成人免费久久| 久久99亚洲综合精品首页|