PDA

Ver la Versión Completa : Asignar metodo anonimo a eventos


AgustinOrtu
22-12-2015, 02:54:50
A medida que mas se empiezan a usar los metodos anonimos, te entran ganas de hacer cosas como esta:


procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.OnClick := procedure(Sender: TObject)
begin
ShowMessage(Sender.ClassName);
end);
end;


Pero no se puede, el IDE reporta el error:


[DCC Error] Unit1.pas(51): E2009 Incompatible types: 'method pointer and regular procedure'


Navegando por la web, el gran David Heffernan (http://stackoverflow.com/users/505088/david-heffernan) tiene una solucion muy elegante, la cual se puede ver en este enlace (http://stackoverflow.com/questions/11491593/tproctobject-to-tnotifyevent)

Sin mas, me he tomado la molestia de extenderla un poco para soportar distintos tipos de eventos; He dividido la funcionalidad en dos unidades, una bastante "aburrida" en la que hay que declarar la misma clase una y otra vez pero agregando siempre un parametro generico mas, asi:


TEventWrapper< T1, R > = class abstract(TComponent)
strict private
FProc: TProc< T1 >;
public
class function CreateEvent(AOwner: TComponent; AProc: TProc<T1>): R; virtual; abstract;
constructor Create(AOwner: TComponent; AProc: TProc<T1>); reintroduce;
procedure Event(Arg1: T1);
end;

TEventWrapper< T1, T2, R > = class abstract(TComponent)
strict private
FProc: TProc< T1, T2 >;
public
class function CreateEvent(AOwner: TComponent; AProc: TProc< T1, T2 >): R; virtual; abstract;
constructor Create(AOwner: TComponent; AProc: TProc< T1, T2 >); reintroduce;
procedure Event(Arg1: T1; Arg2: T2);
end;

TEventWrapper< T1, T2, T3, R > = class abstract(TComponent)

...


Y en otra unidad la implementacion para los eventos, seria basicamente implementar la funcion de clase CreateEvent

Esto permitiria escribir codigo de la siguiente manera:


uses
Events.Wrappers;

procedure ButtonOnClickEvent(Sender: TObject);
begin
ShowMessageFmt('%s - %s', [Sender.ClassName, TButton(Sender).Caption]);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
AEvent: TProc<TObject>;
begin
Button1.OnClick := TNotifyEventWrapper.CreateEvent(Self,
procedure(Sender: TObject)
begin
ShowMessageFmt('%s - %s', [Sender.ClassName, TButton(Sender).Caption]);
end);

AEvent := ButtonOnClickEvent;
Button2.OnClick := TNotifyEventWrapper.CreateEvent(Self, AEvent);

OnMouseDown := TMouseDownEventWrapper.CreateEvent(Self,
procedure(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer)
begin
ShowMessageFmt('Clicked on %d:%d', [X, Y]);
end);
end;


Las unidades las pueden obtener en un repo en GitHub que he creado ahora y que (espero) pueda ir actualizando con cosas similares (clases, funciones, ejemplos, etc)

Enlace a repositorio (https://github.com/ortuagustin/Delphi-Utils) o acá (https://github.com/ortuagustin/Delphi-Utils/tree/master/RTL) estan las dos unidades de las que hablo: Events.Core y Events.Wrappers

Casimiro Notevi
22-12-2015, 09:01:08
Gracias por compartirlo ^\||/

dec
22-12-2015, 14:05:09
Hola,

Bueno es saberlo. Gracias Agustín. :)

escafandra
22-12-2015, 14:27:17
Es interesante la solución. Lo que pretendes me recuerda a java y no es una cosa que me entusiasme mucho.


Saludos.

ecfisa
22-12-2015, 16:34:44
Muy interesante, gracias por compartirlo ^\||/

Saludos :)