Save and restore event handlers
Asked Answered
R

2

5

My class contains dataset (TDataSet). Users of my class can assign event handlers for this dataset:

ds.FieldByName('ID').OnChange := @ID_OnChange;

Then I have to reopen dataset:

ds.Close;
ds.Open;

After this all event handlers are gone:

if Assigned(ds.FieldByName('ID').OnChange) //returns false

So, I need to save handlers and restore them after reopen. I use TStringList for it:

var
  EventHandlers: TStringList;
...
  //I do this for every event of every field
  if Assigned(ds.FieldByName('ID').OnChange) then
    EventHandlers.AddObject('ID', @ds.FieldByName('ID').OnChange);

The problem is how to restore handlers:

ds.FieldByName('ID').OnChange := TFieldNotifyEvent(ObjToInt(EventHandlers.Objects[0]));//Invalid typecast error

How can I assign stored address to event handler? Thanks.

Redound answered 6/3, 2012 at 14:48 Comment(3)
Which version of Delphi? Modern Delphi generic container classes will do the job you need. Also, you can't put an event handler into an Integer. An event handler is a method of object. That means it is two pointers.Monomerous
Sorry, forgot to mention: Delphi 6.Redound
@DavidHeffernan Ok, I can create list of two pointers record (TMethod?). How to save and restore handler from that record?Redound
M
5

If you really want to save the events, you can use TMethod Record:

unit Unit6;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm6 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    MTD : TMethod;
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.btn1Click(Sender: TObject);
begin
  ShowMessage('Hello World!');
end;

procedure TForm6.btn2Click(Sender: TObject);
begin
  ShowMessage('I am copy cat!');
  MTD := TMethod(btn1.OnClick);
  btn2.OnClick := TNotifyEvent(MTD);
end;

end.

The First Click on Btn2 will show "I am copy cat!" and The 2nd one will show Hello World.

Edit : Improve assign event to MTD(TMethod). More simple and allow events from other objects.

Maidenhead answered 6/3, 2012 at 16:30 Comment(2)
You could do away with the type casting if you simply declared MTD as type TNotifyEvent.Denicedenie
@MarjanVenema I am saving different types of events, so type casting is ok.Redound
M
2

I myself subclass my own dataset and has options to create all fields before opening the table and mapping the field events. In doing so, the field (and their events) will not disappear after close.

This can also be done in OnBeforeOpen Event.

If CreateFIeldBeforeOpen
  If FieldDefs.Count = 0 then
    FieldDefs.Update;
  for I := 0 to FieldDefs.Count - 1 do
    If not Assigned(FindField(FieldDefs[I].Name)) then
      FieldDefs[I].CreateField(Self, nil, FieldDefs[I].Name);
Maidenhead answered 6/3, 2012 at 15:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.