Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Extender funcionalidad evento (https://www.clubdelphi.com/foros/showthread.php?t=77003)

kamuspik 13-12-2011 10:38:26

Extender funcionalidad evento
 
Hola, me presento en el foro con una duda sobre eventos.
Mi intención es que cuando se lance el evento OnDataChange de un TDataSource se ejecute un fragmento de código propio para después mantener el comportamiento original mendiante inherited.
Para ello he creado un componente nuevo que hereda de TDataSource y he intentado rescribir el evento OnDataChange ya que es requisito que todo el código implementado quede dentro del componente.

Lo que he realizado es lo siguiente:
Código Delphi [-]
unit IDSDataSource;

interface

uses
  SysUtils, Classes, DB, Dialogs;

type
  TIDSDataSource = class(TDataSource)
  private
    procedure IDSDataSource1DataChange(Event: TDataChangeEvent);
  protected
    { Protected declarations }
  public
    { Public declarations }
  published
    property OnDataChange: TDataChangeEvent write IDSDataSource1DataChange;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('IDS', [TIDSDataSource]);
end;

procedure TIDSDataSource.IDSDataSource1DataChange(Event: TDataChangeEvent);
begin
  ShowMessage('¡Entro aquí!');

  inherited;
end;

end.
¿Voy por el buen camino? No consigo que entre en la rutina MiDataSource1DataChange.

Muchas gracias por vuestro tiempo, un saludo.

Ñuño Martínez 13-12-2011 15:49:06

Hola kamuspik, bienvenido al foro. ¿Te has pasado por la Guía de Estilo?

Respecto a tu pregunta, no, no vas por buen camino. Es más, por lo que te leo me temo que no sabes cómo implementa Delphi la Programación Dirigida por Eventos. Si nunca antes has hecho PDE en Delphi, Builder ni Lazarus o similar te recomiendo que busques y te leas La Cara Oculta de Delphi, que el propio autor publicó en Internet para su acceso libre. Si no recuerdo mal, en el FTP del Club hay una copia.

Delphi implementa PDE usando propiedades y no vía métodos, como el caso de (por ejemplo) Objective C en NEXT. Para implementar un evento lo que hay que hacer es asignar a dicha propiedad una referencia a un método. En tu caso, después de añadir al formulario un objeto TDataSource, debes ir a la ventana de propiedades del objeto y asignar el método apropiado (con doble pulsación se crea automáticamente) y escribir ahí el código. No necesita herencia.

kamuspik 13-12-2011 16:37:11

Hola, gracias por contestar.
Todavía no domino demasiado Delphi, tengo un ejemplar de la Cara Oculta de Delphi que suelo consultar con frecuencia pero no he encontrado respuesta a este problema. Quizás no me haya explicado bien, entiendo como implementar eventos (por ejemplo, los asociados a un botón) pero mi intención no es esa, lo que pretendo hacer (que no sé si es posible) es extender la funcionalidad de un evento. Quiero que cuando se genere un evento (OnDataChange) se ejecute cierto fragmento de código y que después se haga un inherited para que mantenga su funcionamiento "natural" como evento.
En la ayuda de Delphi lo trata como "Changing the standard event handling", pero no da demasiadas pistas y me he quedado bloqueado.
Un saludo y gracias de nuevo ;)

kamuspik 13-12-2011 16:47:58

He encontrado en la guía del desarrollador de componentes de Delphi un caso análogo al que me interesa, pero respecto al evento Onclick:

Código Delphi [-]
procedure Click override { forward declaration }
...

procedure TMyControl.Click;
begin
inherited Click; { perform standard handling, incluiding calling handler }
... { your customizations go here }
end;

Espero que esto ayude a mi pobre explicación.

Un saludo.

kamuspik 14-12-2011 15:26:17

Hola, revisando un poco de bibliografía he conseguido dar con lo que me interesaba. Lo pongo a continuación por si le sirve a alguien.

Código Delphi [-]
type
  TMiDataSource = class(TDataSource)
  private

    procedure MiDataSourceOnDataChange (Sender: TObject; Field: TField);
  protected

  public
    constructor Create(AOwner : TComponent); override;
    destructor Destroy; override;
  published
  end;

procedure Register;

implementation


procedure Register;
begin
  RegisterComponents('Componentes', [TMiDataSource]);
end;

constructor TMiDataSource.Create(AOwner : TComponent);
begin
  inherited Create(AOwner);

  Self.OnDataChange := TMiDataSourceOnDataChange;  //instrucción necesaria para redefinir el evento OnDataChange

end;

destructor TMiDataSource.Destroy;
begin

  inherited destroy;
end;


procedure TMiDataSource.MiDataSourceOnDataChange (Sender: TObject; Field: TField);
begin
    ShowMessage('¡Entro aquí!');

    ....... //Codigo que extiende el comportamiento del evento

    inherited;  //instrucción que mantiene el comportamiento original

end;

end.

Un saludo.

maeyanes 14-12-2011 19:55:11

Hola...

Y si a ese componente le asignas un método en su evento OnDataChange, ¿este sigue comportándose como deseas? Has la prueba y verás que no.

Para redefinir el comportamiento de un evento, primero debes identificar cual es el método que dispara ese evento, mayormente en la VCL estos métodos se pueden redefinir, pero parece que para la clase TDataSource el método que llama al evento es privado (DataEvent).

Dicho lo anterior, tu componente debe quedar de la siguiente forma para que funcione:

Código Delphi [-]
type
  TMiDataSource = class(TDataSource)
  private
    // Campo para guardar el manejador de evento definido en tiempo de diseño...
    FOldDataChangeEvent: TDataChangeEvent;

    procedure DoOnDataChange (Sender: TObject; Field: TField);
  protected
    procedure Loaded; override;
  end;

implementation

procedure TMiDataSource.DoOnDataChange(Sender: TObject; Field: TField);
begin
  // Llamamos el manejador de eventos asignado en tiempo de diseño...
  if Assigned(FOldDataChangeEvent) then
    FOldDataChangeEvent(Sender, Field);
  // Aquí pones tu código...
end;

procedure TMiDataSource.Loaded;
begin
  inherited;
  // Si estamos en tiempo de ejecución, sustituimos el manejador de evento de OnDataChange con el nuestro...
  if not csDesigning in ComponentState then
  begin
    FOldDataChangeEvent := OnDataChangeEvent;
    OnDataChangeEvent := DoOnDataChange
  end
end;

Toma en cuenta que este código lo hago al vuelo, así que podría fallar. También ten en cuenta que si se cambia el manejador de evento de OnDataChange en tiempo de ejecución, el comportamiento de este código ya no será el deseado.



Saludos...

kamuspik 16-12-2011 09:06:44

Hola!
Gracias por tu respuesta, pensé que había resuelto el problema...de hecho el código parecía funcionar como quería. Voy a probar esto que has dicho y luego comento los resultados.

Un saludo ;)

kamuspik 16-12-2011 09:50:57

Hola maeyanes,
he probado tu código y funciona correctamente. Lo único que no consigo entender la diferencia entre lo que hacía yo y tu código.
A ver si me puedes ayudar a entenderlo, yo directamente asigno el procedimiento que quiero que se ejecute al evento y después hago un inherited.¿Por qué no se comporta como deseo?
En tu código guardas una copia del manejador de eventos y después la llamas antes de ejecutar el procedimiento ¿esto es para mantener el funcionamiento natural del evento no?¿Qué diferencia hay entre los dos comportamientos?

Muchas gracias por tu tiempo,

Un saludo.

maeyanes 16-12-2011 17:26:47

Hola...

La única diferencia entre tu código y el mio, es que si se asigna un manejador de evento en tiempo de diseño, tú código ya no va a funcionar como lo tienes pensado, esto es por que al asignar el nuevo manejador de evento este sustituye al que tu asignaste por código en el constructor.

El código que yo te proporcioné prevee este caso y asigna el manejador de evento interno después de "cargar" el component desde el DFM, guardando en un campo la referencia al posible manejador de evento asignado en tiempo de diseño. Luego, al dispararse el evento, el manejador interno llama primero (y puedes hacerlo también al final, depende de lo que desees hacer) al manejador asignado en tiempo de diseño (si es que se asigno uno) y luego ejecuta el código de lo que deseas implementar.

Espero que con esta pequeña explicación te quede más claro.


Saludos...

kamuspik 19-12-2011 10:01:22

Muchas gracias, ahora ya lo comprendo, el código que había puesto antes se comportaba de forma excluyente y mi intención era que se mantuviera la posibilidad de asignar un manejador de eventos en tiempo de diseño.

Un saludo ;)


La franja horaria es GMT +2. Ahora son las 07:53:56.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi