Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Función virtual... (https://www.clubdelphi.com/foros/showthread.php?t=69514)

mlara 23-08-2010 19:16:14

Función virtual...
 
Como ejemplo, cuando uso un objeto de la VCL, sé que puedo hacer algo como esto:

Código:

procedure TForm.MiObjetoOnEvento1(Sender: TObject);
begin
  ...
end;

procedure MiEventoAlternativo1(Sender: TObject);
begin
  ...
end;

procedure TForm.Button1Click(Sender: TObject);
begin
  ...
  MiObjeto.Evento1 := nil;
  ...
  // Aquí hago algo que involucra a MiObjeto y quiero evitar que se ejecute
  // el código del evento 1, pero más adelante sí necesito que el código
  // se ejecute, por lo cual hago nuevamente la asignación.
  ...
  MiObjeto.Evento1 := MiEventoOnEvento1;
  ...
  // Luego, necesito que el código a ejecutar sea otro, pero ante el mismo
  // evento, por lo cual hago esta otra asignación.
  ...
  MiObjeto.Evento1 := MiEventoAlternativo1;
  ...
end;

Esto lo he hecho y funciona perfectamente.

Ahora requiero declarar una función en el código de una forma (TForm), y luego, al ejecutar esa función, dependiendo de cierto parámetro, quiero que se ejecute un código diferente reasignando el código de la función, así:

Código:

if Tag = 1 then
  MiFuncion := MiFuncion1
else if Tag = 2 then
  MiFuncion := MiFuncion2
else if Tag = 3 then
  MiFuncion := MiFuncion3
...

// Todas las funciones son de tipo booleano, así que...
if MiFuncion then
  ...
else
  ...

La cuestión es que esto último no he podido hacerlo. El ejemplo de arriba me hace suponer que sí puedo asignar una función definida (MiEventoOnEvento1 o MiEventoAlternativo1) a una función declarada dentro de una clase (Evento1), pero como ven tengo problemas...

Sé también que podría implementar un código alternativo, pero de verdad requiero una solución como la solicitada.

Gracias, si alguien puede colaborarme.

Lord Delfos 23-08-2010 19:32:31

Hola mlara.

Te olvidaste de poner cuál es el error que recibís del compilador, pero me jugaría la cabeza a que el problema es de tipos incorrectos.

Esto se debe a que el compilador interpreta que vos querés llamar a la función y asignarle el resultado a tu evento. Solución:

Código Delphi [-]
MiFuncion:= @MiFuncion1;

El arroba le dice a Delphi explicitamente que vos querés asignar la dirección de memoria de tu función, y no el resultado de llamarla

Espero te sirva. Saludongos.

coso 23-08-2010 21:20:49

Hola, creo que el error lo tienes por definicion de tipos. Antes que nada, lo que estas comentando con los eventos es posible porque son procedures, no estoy seguro si lo que te pondre va tambien con funciones, si eso lo pruebas :D

Código Delphi [-]

type TMiTipoDeFuncion = function (Sender : TObject) : boolean of object

...

function TForm1.F1(Sender : TObject): boolean;
begin
...
end;

function TForm1.F2(Sender : TObject) : boolean;
begin
...
end;

var
  MiFuncion : TMiTipoDeFuncion;
begin
case Switch of 
1 : MiFuncion := F1;
2 : MiFuncion := F2;
...
end;

if MiFuncion(Argumento) = true then ...

Algo asi. No se si funcionaria porque creo que los punteros a funciones, no a procedures, se aplican tal como te dice Lord Delfos. De todas maneras, este codigo siguiente si que te funcionaria :

Código Delphi [-]

type TMiProcedureBoolean : procedure (Sender : TObject; var b : boolean) of object;

...

procedure TForm1.P1(sender : TObject;var b : boolean);
begin
...
   b := resultado
end;

...

var
   MiProcedure : TMiProcedureBoolean;
   Resultado : boolean;
begin

case Switch of 
1 : MiProcedure := P1;
2 : MiProcedure := P2;
...
end;

MiProcedure(self,Resultado);

if Resultado then ...

Espero te sirva de ayuda. Un saludo.

ecfisa 23-08-2010 21:32:34

Hola mlara.

Me llama la atención que no funcione... debería. Por lo que hice una prueba simple y me funciona bién.

Aunque no lo aclaras, creo que no te dá un error sino que simplemente no se ejecuta el código...
Me parece que el problema lo tenés en la evaluación del Tag.

Probá esto:
.Un PopupMenu asignado a la propiedad PopupMenu del Form.
.En el PopupMenu,tres Menuitems 'nil', 'OnChange1', 'Onchange2' y en sus eventos OnClick asignado: itOnChangeClick
.Por último un Edit.
Código Delphi [-]
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Edit: TEdit;
    PopupMenu1: TPopupMenu;
    itNil: TMenuItem;
    itOnChange1: TMenuItem;
    itOnChange2: TMenuItem;
    procedure itOnChangeClick(Sender: TObject);
  private
    procedure EditChange1(Sender: TObject);
    procedure EditChange2(Sender: TObject);
  public
  end;

var
  Form1: TForm1;

implementation {$R *.dfm}

procedure TForm1.EditChange1(Sender: TObject);
begin
  ShowMessage('OnChange 1')
end;

procedure TForm1.EditChange2(Sender: TObject);
begin
  ShowMessage('OnChange 2');
end;

procedure TForm1.itOnChangeClick(Sender: TObject);
begin
  case TMenuItem(Sender).Tag of
    1: Edit.OnChange:= nil;
    2: Edit.OnChange:= EditChange1;
    3: Edit.OnChange:= EditChange2;
  end;
end;

end.

Tecleá en el edit seleccionando las opciones del PopupMenu...:)


Saludos.

delphi.com.ar 23-08-2010 21:48:06

Cita:

Empezado por mlara (Mensaje 374225)
Ahora requiero declarar una función en el código de una forma (TForm), y luego, al ejecutar esa función, dependiendo de cierto parámetro, quiero que se ejecute un código diferente reasignando el código de la función, así:

En Delphi puedes tener referencia tanto a Métodos como a procedimientos regulares sin ningún problema, solo tienes que tener en cuenta que la lista de argumentos y el resultado de las funciones debe coincidir con el tipo especificado, sino se volcarán datos inválidos en los esperados.

Código Delphi [-]
unit Unit1;

interface

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

type
  TRegularProcedure = procedure;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    procedure Hola(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure Chau;
begin
  ShowMessage('Chau!');
end;


{ TForm1 }

procedure TForm1.Hola(Sender: TObject);
begin
  ShowMessage('Hola');
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  AMetodo: TNotifyEvent;
  AProcedimiento: TRegularProcedure;
begin
  AMetodo := Hola;
  AMetodo(nil);

  AProcedimiento := Chau;
  AProcedimiento;
end;

end.

Saludos!

ecfisa 24-08-2010 00:55:40

Hola.

Y ya que estamos con los punteros a funciones y a métodos, este es el ejemplo anterior implementado con
puntero a método. (como para no dejar las cosas a medias... :) )

Código Delphi [-]
type
  TEventoPtr= procedure(Sender: TObject) of object;
  TForm1 = class(TForm)
    Edit1: TEdit;
    PopupMenu1: TPopupMenu;
    Nil1: TMenuItem;
    ProcA1: TMenuItem;
    ProcB1: TMenuItem;
    procedure FormCreate(Sender: TObject);
  private
    procedure Proc_A(Sender: TObject);
    procedure Proc_B(Sender: TObject);
  public
    EventoPtr: TEventoPtr;
    procedure MenuItmOnClick(Sender: TObject);
  end;
var
  Form1: TForm1;

implementation {$R *.dfm}

procedure TForm1.Proc_A(Sender: TObject);
begin
  ShowMessage('Proc_A');
end;

procedure TForm1.Proc_B(Sender: TObject);
begin
  ShowMessage('Proc_B');
end;

procedure TForm1.MenuItmOnClick(Sender: TObject);
begin
  case TMenuItem(Sender).Tag of
    1: Edit1.OnChange:= nil;
    2: Edit1.OnChange:= Proc_A;
    3: Edit1.OnChange:= Proc_B;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  EventoPtr:= MenuItmOnClick;
  for i:= 0 to PopupMenu1.Items.Count -1 do
     PopupMenu1.Items[i].OnClick:= EventoPtr;
end;

Saludos.

mlara 24-08-2010 01:28:51

Perfecto...
 
Agradezco a todos su colaboración... fue muy útil, tanto que a partir de ahí tomé la decisión de usar el siguiente código:

Código Delphi [-]
function MyFunc1: Boolean;
begin
  ...
end;

function MyFunc2: Boolean;
begin
  ...
end;

procedure TForm.OnEvent(Sender: TObject); // En realidad se trata de cualquier procedimiento o función. OnEvent supone un evento cualquiera.
var
  MyFunc: function(): Boolean;
begin
  if Condition = 1 then
    MyFunc := MyFunc1
  else
    MyFunc := MyFunc2;
  ...
  if MyFunc then
    ...
  ...
end;

... y funciona a la perfección. Prácticamente el problema era la declaración, incluso el lugar de la declaración. Me estaba enredando un poco con la teoría de funciones virtuales, pero como no estaba derivando ninguna clase me quedé barado, pero ahora todo está bien.

Gracias nuevamente.


La franja horaria es GMT +2. Ahora son las 09:07:36.

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