delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (0)


Event Chain Mechanism IIGo to Alex Wijoyo's websiteComponent available for this articleFormat this article printer-friendly!Bookmark function is only available for registered users!
Attach and detach many event handlers to an event at runtime
Product:
Delphi 3.x (or higher)
Category:
VCL-General
Skill Level:
Scoring:
Last Update:
03/24/2003
Search Keys:
delphi delphi3000 article borland vcl code-snippet attach detach event handler chain tnotifyevent
Times Scored:
2
Visits:
2288
Uploader: Alex Wijoyo
Company: Excellont
Reference: http://www.delphi3000.com/articles/article_3543.asp
Component Download: http://www.delphi3000.com/article/3560/3560.zip
 
Question/Problem/Abstract:
Attach and detach many event handlers to an event at runtime
Answer:



My last event chain mechanism doesn't include UnSaveEvent method. We use UnSafeEvent method for removing an event from event chain. EventId parameter is removed from event chain mechanism, so only event wrapper mechanism can be used.
There aren't any changes on SaveEvent usage, here's the example:

procedure TfrmEventChain.btnAttachEvent1Click(Sender: TObject);
begin
  SaveEvent(btnTrigger.OnClick,Event1Click,btnTrigger);
  btnTrigger.OnClick:=Event1Click;
end;

There aren't any changes on ChainedEvent usage also, here's the example:

procedure TfrmEventChain.Event1Click(Sender: TObject);
begin
  ChainedEvent(Event1Click,TComponent(Sender));
  chbEvent1.Checked:=not chbEvent1.Checked;
end;

I only add new usage of UnSaveEvent, here's the example:

procedure TfrmEventChain.btnDetachEvent1Click(Sender: TObject);
var
  NextEvent:TNotifyEvent;
begin
  NextEvent:=UnSaveEvent(Event1Click,btnTrigger);
  if SameEvent(btnTrigger.OnClick,Event1Click) then
    btnTrigger.OnClick:=NextEvent;
end;

OK, here's the unit source code for TNotifyEvent (this unit and the demo project will be sent to delphi3000 admin immediately):

unit EventChain;

interface

uses Classes, SysUtils;

type
  ECircularEventChain = class(Exception);

//EventId is removed,
//use event handler wrapper to differentiate events of single component
//that share one event handler
procedure SaveEvent(OldEvent,NewEvent:TNotifyEvent;Sender:TComponent);overload;
procedure ChainedEvent(NewEvent:TNotifyEvent;Sender:TComponent);overload
function UnSaveEvent(Event:TNotifyEvent;Sender:TComponent):TNotifyEvent;overload
function SameEvent(LeftEvent,RightEvent:TNotifyEvent):boolean;overload;

var
  EventList:TStringList;
//move declaration to implementation section after testing

implementation

type
  TEventListCleaner = class(TComponent)
  protected
    procedure Notification(AComponent: TComponent;Operation: TOperation);override;
  end;

var
  EventListCleaner:TEventListCleaner;

procedure SaveEvent(OldEvent,NewEvent:TNotifyEvent;Sender:TComponent);
var
  EventName:string;
  EventString:string;
  i,u:integer;
  SenderString:string;
begin
  if Assigned(OldEvent) and Assigned(NewEvent) and Assigned(Sender) and (@OldEvent<>@NewEvent) then
  begin
    EventString:=IntToStr(Integer(TMethod(NewEvent).Data))+'.'+
    IntToStr(Integer(TMethod(NewEvent).Code));
    u:=EventList.Count-1;
    SenderString:=IntToStr(Integer(Sender));
    //check for circular event chain
    for i:=0 to u do
    begin
      EventName:=EventList.Names[i];
      if (pos(SenderString,EventName)=1)and
      (EventList.Values[EventName]=EventString) then
        raise ECircularEventChain.Create('Circular event chain found!');
    end;
    EventName:=SenderString+'.'+IntToStr(Integer(@NewEvent));
    EventString:=IntToStr(Integer(TMethod(OldEvent).Data))+'.'+
    IntToStr(Integer(TMethod(OldEvent).Code));
    EventList.Values[EventName]:=EventString;
    Sender.FreeNotification(EventListCleaner);
  end;
end;

procedure ChainedEvent(NewEvent:TNotifyEvent;Sender:TComponent);
var
  EventName:string;
  OldEvent:TNotifyEvent;
  EventString:string;
  Separator:integer;
begin
  if Assigned(NewEvent) and Assigned(Sender) then
  begin
    EventName:=IntToStr(Integer(Sender))+'.'+IntToStr(Integer(@NewEvent));
    EventString:=EventList.Values[EventName];
    if (EventString<>'') then
    begin
      Separator:=pos('.',EventString);
      TMethod(OldEvent).Data:=Pointer(StrToInt(Copy(EventString,1,Separator-1)));
      TMethod(OldEvent).Code:=Pointer(StrToInt(Copy(EventString,Separator+1,length(EventString)-Separator)));;
      if Assigned(OldEvent) then
        OldEvent(Sender);
    end;
  end;
end;

function UnSaveEvent(Event:TNotifyEvent;Sender:TComponent):TNotifyEvent;overload
var
  i,u,pstn,separator:integer;
  EventName,EventString,EventCodeString,SenderString,NextEventString:string;
begin
  Result:=nil;
  if Assigned(Event) and Assigned(Sender) then
  begin
    NextEventString:=IntToStr(Integer(TMethod(Result).Data))+'.'+
    IntToStr(Integer(TMethod(Result).Code));
    EventCodeString:=IntToStr(Integer(TMethod(Event).Code));
    EventString:=IntToStr(Integer(TMethod(Event).Data))+'.'+
    EventCodeString;
    SenderString:=IntToStr(Integer(Sender));
    u:=EventList.Count-1;
    pstn:=EventList.IndexOfName(SenderString+'.'+EventCodeString);
    for i:=u downto 0 do
    begin
      EventName:=EventList.Names[i];
      if (pos(SenderString,EventName)=1)and(EventList.Values[EventName]=EventString)then
      begin
        //Next event found redirect next event
        if pstn>=0 then
          NextEventString:=EventList.Values[SenderString+'.'+EventCodeString];
        EventList.Values[EventName]:=NextEventString;
      end;
    end;
    if pstn>=0 then
    begin
      NextEventString:=EventList.Values[SenderString+'.'+EventCodeString];
      Separator:=pos('.',NextEventString);
      TMethod(Result).Data:=Pointer(StrToInt(Copy(NextEventString,1,Separator-1)));
      TMethod(Result).Code:=Pointer(StrToInt(Copy(NextEventString,Separator+1,length(NextEventString)-Separator)));;
      EventList.Delete(pstn);
    end;
  end;
end;

function SameEvent(LeftEvent,RightEvent:TNotifyEvent):boolean;
begin
  with TMethod(LeftEvent) do
    Result:=(Data=TMethod(RightEvent).Data)and(Code=TMethod(RightEvent).Code);
end;

end.





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment













 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
D. Souchard
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)