Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Crear un evento propio (https://www.clubdelphi.com/foros/showthread.php?t=63084)

noob 28-01-2009 23:45:27

Crear un evento propio
 
Hola, me gustaría saber si es posible realizar un evento propio en Delphi, es decir, yo tengo un código que quiero que se ejecute cada vez que una variable cambia de valor, por ejemplo:

Código Delphi [-]
Cadena: string;
...
Cadena := 'azul'; // Se ejecuta el evento OnCambiaCadena
Cadena := 'verde' // Se ejecuta el evento OnCambiaCadena
...

procedure MiClase.OnCambiaCadena;
begin
  ShowMessage('Salté');
end;

No se si me explico.

Saludos.

Al González 29-01-2009 01:14:21

¡Hola!

Existen varias formas de implementar lo que deseas, una de ellas es convertir a Cadena en una propiedad de una clase. Pero creo que lo mejor ahora sería que ahondaras un poco sobre lo que quieres conseguir.

¿Cuál es la motivación? ¿Por dónde va esa idea?

Saludos.

Al González. :)

Delphius 29-01-2009 02:15:40

Hola noob,
Como dice Al, sería oportuno que nos dieras más detalle.
Formalmente un evento se hace aplicando punteros a métodos. Por ejemplo:

Código Delphi [-]
type
  TCambiaCadenaEvent = procedure (Cadena: string) of object;

Luego tu clase debe definir un atributo de dicho de evento:

Código Delphi [-]
TMiClase = class
...
  private
    FCadena: string; 
    FOnCambiaCadenaEvent: TCambiaCadenaEvent;
...
end;

Ahora viene lo interesante. Tenemos el tipo, más no cuando salta. Dices que se produce al cambiar una cadena. Formalmente, un método hace disparar el evento.

Pero he aquí que en realidad el evento está incompleto. Necesitamos darle una respuesta, en otro caso no debería suceder. Lo de esperar es que uno pueda implementar su rutina, pero tranquilamente uno puede definir un método que tenga la misma declaración que el tipo del evento como respuesta al mismo.

Supongamos que hacemos uso de propiedades para cambiar el texto de la cadena:
Código Delphi [-]
property Cadena: string read FCadena write SetCadena;

SetCadena es un método privado, y en el hacemos que se dispare el evento:

Código Delphi [-]
procedure TMiClase.SetCadena(Value: string);
begin
  if Value <> FCadena
     then  begin
               FCadena := Value;
               if Assigned(FOnCambiaCadenaEvent) // comprobamos que haya Rta
                  then FCambiaCadenaEvent(Value); // disparamos evento
             end;
end;

Ahora si estamos en condiciones de darte Rta al evento y asociarlo.

1) Disparará un método propio de la clase:

Para ello se necesita definir un método que tenga la misma declaración del puntero a método en la clase:

Código Delphi [-]
TMiClase = class
  private
  ...
  procedure EventoCambiarCadena(Cadena: string);
...

procedure TMiClase.EventoCambiarCadena(Cadena: string);
begin
  ShowMeesage(Cadena); // o lo que quieras que haga.
end;


Asociamos el evento a la clase, (tal vez en el constructor):

Código Delphi [-]
FOnCambiaCadenaEvent := EventoCambiarCadena;


2) Y como dije, lo normal es que la clase no sea la "dueña" de la respuesta. Por tanto el método formalmente se define fuera. Necesitamos asignarle el método de alguna manera. Por ejemplo, propiedades:

Código Delphi [-]
property OnCambiaCadenaEvent: TCambiaCadenaEvent read FOnCambiaCadenaEvent ....

Y en base a eso, podemos hacer esto:

Código Delphi [-]
MiClase.OnCambiaCadenaEvent := MiRutina;
MiClase.Cadena := 'Hola, mira como cambio';

En este caso,

La clase solita dispará el evento y aplicará las sentencias definidas en MiRutina.

MiRutina puede ser un método ajeno a la clase TMiClase, necesita ser un método, con la misma declaración más puede ser declarado en otro lado. Por ejemplo:

Código Delphi [-]
procedure TForm1.MiRutina(Cadena: string);
begin
  Label1.Caption := Cadena;
end;

En este caso, es un método definido en el Form1, y lo que hace es visualizar la cadena que cambió en un label.

Espero que se entienda:o,

Sugiero una leída al capítulo dedicado a los eventos del libro La Cara Oculta de Delphi 4.

Saludos,

noob 30-01-2009 18:15:42

Hola Delphius, he seguido tus indicaciones pero creo que algo me falla.

Tengo esto:

Unit1.pas (mi formulario)

Código Delphi [-]
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    MiClase: cMiClase;
    procedure MiRutina(Cadena: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  MiClase := cMiClase.Create;
  MiClase.OnCambiaCadenaEvent := MiRutina;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  MiClase.Cadena := 'Hola, mira como cambio';
end;

procedure TForm1.MiRutina(Cadena: string);
begin
  Edit1.Text := Cadena;
end;

end.

MiUnit.pas

Código Delphi [-]
unit MiUnit;

interface

type

  TCambiaCadenaEvent = procedure (Cadena: string) of object;

  cMiClase = class
               private
                 FCadena: string;
                 FOnCambiaCadenaEvent: TCambiaCadenaEvent;
                 procedure SetCadena(Value: string);
                 procedure SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);
                 procedure EventoCambiarCadena(Cadena: string);
               public
                 constructor Create;
                 property Cadena: string read FCadena
                                         write SetCadena;
                 property OnCambiaCadenaEvent: TCambiaCadenaEvent read FOnCambiaCadenaEvent
                                                                  write SetOnCambiaCadenaEvent;
             end;

implementation

uses Dialogs;

constructor cMiClase.Create;
begin
  FOnCambiaCadenaEvent := EventoCambiarCadena;
end;

procedure cMiClase.SetCadena(Value: string);
begin
  if Value <> FCadena then
    begin
      FCadena := Value;
      if Assigned(FOnCambiaCadenaEvent) then // comprobamos que haya Rta
        FOnCambiaCadenaEvent(Value); // disparamos evento
    end;
end;

procedure cMiClase.SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);
begin
  FOnCambiaCadenaEvent := Value;
end;

procedure cMiClase.EventoCambiarCadena(Cadena: string);
begin
  ShowMessage(Cadena); // o lo que quieras que haga.
end;

end.

Saludos.

Delphius 30-01-2009 20:11:36

Pues debería funcionar. A vista rápida no veo error. Prueba este código, verás que funciona apropiadadamente:

Unidad donde está la clase
Código Delphi [-]
unit UMiClase;

interface

type

  // Mi tipo de evento
  TCambiaCadenaEvent = procedure(Cadena: string) of object;

  TMiClase = class
    private
      FCadena: string;
      // nuestro campo de tipo evento
      FOnCambiaCadenaEvent: TCambiaCadenaEvent;

      // métodos privados
      procedure SetCadena(Value: string);
      procedure SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);
    public
      constructor Create;
      destructor Destroy; override;
      property Cadena: string read FCadena write SetCadena;
      property OnCambiaCadenaEvent: TCambiaCadenaEvent read FOnCambiaCadenaEvent write SetOnCambiaCadenaEvent;
   end;



implementation

{ TMiClase }

constructor TMiClase.Create;
begin
  inherited Create;
  FOnCambiaCadenaEvent := nil;
end;

destructor TMiClase.Destroy;
begin
  FOnCambiaCadenaEvent := nil;
  inherited Destroy;
end;

procedure TMiClase.SetCadena(Value: string);
begin
  if FCadena <> Value
     then begin
            if Assigned(FOnCambiaCadenaEvent)
               then FOnCambiaCadenaEvent(Value);
          end;
end;

procedure TMiClase.SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);
begin
  FOnCambiaCadenaEvent := Value;
end;

end.


Unidad del form:
Código Delphi [-]
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    FMiClase: TMiClase;
    procedure MiRutina(Value: string);
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FMiClase := TMiClase.Create;
  FMiClase.OnCambiaCadenaEvent := MiRutina;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  FMiClase.Free;
  Action := CaFree;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  FMiClase.Cadena := Edit1.Text;
end;

procedure TForm1.MiRutina(Value: string);
begin
  // esta es la respuesta al evento
  Label1.Caption := 'Hey mira... a cambiado el texto, ahora es: ' + Value;
end;

end.

Saludos,

Delphius 30-01-2009 20:14:03

Hasta, incluso funciona si se define dentro de la propia clase la rutina:

Código Delphi [-]
unit UMiClase;

interface

uses Dialogs;

type

  // Mi tipo de evento
  TCambiaCadenaEvent = procedure(Cadena: string) of object;

  TMiClase = class
    private
      FCadena: string;
      // nuestro campo de tipo evento
      FOnCambiaCadenaEvent: TCambiaCadenaEvent;

      // métodos privados
      procedure SetCadena(Value: string);
      procedure SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);

      procedure CambiaCadenaRespuesta(Cadena: string);
    public
      constructor Create;
      destructor Destroy; override;
      property Cadena: string read FCadena write SetCadena;
      property OnCambiaCadenaEvent: TCambiaCadenaEvent read FOnCambiaCadenaEvent write SetOnCambiaCadenaEvent;
   end;



implementation

{ TMiClase }

procedure TMiClase.CambiaCadenaRespuesta(Cadena: string);
begin
  ShowMessage(Cadena);
end;

constructor TMiClase.Create;
begin
  inherited Create;
  FOnCambiaCadenaEvent := CambiaCadenaRespuesta;
end;

destructor TMiClase.Destroy;
begin
  FOnCambiaCadenaEvent := nil;
  inherited Destroy;
end;

procedure TMiClase.SetCadena(Value: string);
begin
  if FCadena <> Value
     then begin
            if Assigned(FOnCambiaCadenaEvent)
               then FOnCambiaCadenaEvent(Value);
          end;
end;

procedure TMiClase.SetOnCambiaCadenaEvent(Value: TCambiaCadenaEvent);
begin
  FOnCambiaCadenaEvent := Value;
end;

end.

Y ahora en el create del form no hacemos la asignación:
Código Delphi [-]
procedure TForm1.FormCreate(Sender: TObject);
begin
  FMiClase := TMiClase.Create;
  //FMiClase.OnCambiaCadenaEvent := MiRutina;
end;

Y si no le comentamos la acción notarás que realiza la rutina que defines en tu form.

Saludos,


La franja horaria es GMT +2. Ahora son las 10:30:07.

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