Multi-processing mechanism of Delphi 7 event
Allen Tao
2007-08-19
First explain the subject. In my process of using Delphi 7, I found that an object's events can only be handled by a single process. If the event is assigned to the process of handling the event multiple times, the last real process of handling the event will be the last assignment. For example, there is a class Tmyclass that defines an event onsomefired, which is instantiated in the class Tclientclass and its events are processed. As shown below:
Constructor Tclientclass.create;
Var
Myobj:tmyclass;
Begin
...
Myobj:= tmyclass.create;
Myobj.onsomefired:= SomeFired1;
Myobj.onsomefired:= SomeFired2;
The SomeFired1 and SomeFired2 here are the processes defined in Tclientclass. The end result is that only SomeFired2 is called when the Onsomefired event occurs.
But in the actual programming, it is often necessary for an event to be handled by multiple methods. To this end, I refer to a number of solutions to this problem, summed up a method of their own, called the event of the multi-processing mechanism.
Rationale
The event in Delphi 7 is essentially a process pointer. However, the event type is defined more than the generic procedure pointer at the last one "of object", as commonly used tnotifyevent is defined as:
Tnotifyevent = procedure (sender:tobject) of object;
Therefore, assigning a value to an event property, that is, assigning a value to a member variable of a class's procedure pointer type, is, of course, valid for the last assignment. For multiple assignments to be valid there must be a data structure that records the process pointer variables assigned to each assignment, and the most appropriate data structure is of course the list tlist. However, it is not convenient to add a list object that records event assignments in every event class, and the code that uses this list is similar in different classes and should be drawn out to form a class. This class is the core of the event multi-processing mechanism.
Practice
To log an event-handling procedure, you need to put the procedure pointer variable into the list object. But a list object can only add a pointer-type object (that is, a reference type), and a procedure pointer variable refers to a type variable that cannot be added directly. This requires a class to wrap the procedure pointer variable into a pointer-type object. So, first define the wrapper class Tcallmethod, as follows:
Tcallmethod = Class
Private
_callback:tmethod;
Public
Property Callback:tmethod read _callback write _callback;
End
The TMethod here is the Delphi predefined record type, and any procedure pointer variable can be coerced into this type. After that, you define the class for the record processing, as follows:
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
Here is the implementation section:
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
As can be seen from the above code, the purpose of teventobject is to wrap tlist objects, shielding the Tlist class of most methods, only exposed 2 processes, a property and 1 indexes, respectively, to add, delete processing event process, get the number of procedures and retrieve records by ordinal process variables.
Use
When used, the event's type is changed from the procedure pointer to Teventobject in the class that needs to use the event, allowing it to have a multi-processing capability. As shown in the following code:
Tmyclass=class
Private
Somefired:teventobject;
Public
Constructor Create;
Procedure Dosth;
Property Onsomefired:teventobject read somefired write somefired; Multi-processing events
End
Here is the implementation code:
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
&nbs p; begin
method:= tnotifyevent (somefired[i]);// The true type of event in this class is tnotifyevent, so when the event is triggered, it is preceded by a procedure pointer of this type before calling
method (self);
end;
End; After the
defines a class that contains a multi-processing event, let's see if this kind is called in its client class. such as the following code:
{class Tclientclass}
var
Myobj:tmyclass;
/...
myobj:= tmyclass.create;
MYOBJ.ONSOMEFIRED.ADD (SomeFired1);
MYOBJ.ONSOMEFIRED.ADD (SOMEFIRED2);
when the Dosth method of Tmyclass is called in the Customer class code, the event is triggered, and the 2 processes SomeFired1 and SOMEFIRED2 are called sequentially for multi-processing purposes.
One more step forward
The Teventobject class above can achieve the purpose of multi-processing of events, but it is a hidden danger that there is no check on the type of procedure pointer being added to it. Therefore, you can inherit a class from Teventobject for the type of procedure pointer that is required for each event to implement type checking. If the type of event required is tnotifyevent, you can inherit a Tnotifyeventobject class, such as the following code:
Tnotifyeventobject = Class (Teventobject)
Public
Procedure Add (p:tnotifyevent); overload;
Procedure Remove (p:tnotifyevent); overload;
End
Here is the implementation section:
Procedure Tnotifyeventobject.add (p:tnotifyevent);
Begin
Inherited Add (TMethod (p));
End
Procedure Tnotifyeventobject.remove (p:tnotifyevent);
Begin
Inherited Remove (TMethod (p));
End
The Add and remove methods are overloaded in this class, and you can effectively check the type of the procedure pointer.
The above is a solution to the problem of multi-processing in Delphi 7. If interested, please visit my blog http://allentao430.spaces.live.com enlighten.
Reference: http://blog.csdn.net/iseekcode/article/details/5352709
Multi-processing mechanism of Delphi 7 event