Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Evento OnClick en runtime (https://www.clubdelphi.com/foros/showthread.php?t=86382)

hgiacobone 30-07-2014 15:49:34

Evento OnClick en runtime
 
Tal vez sea la pregunta del millón...
¿ Cómo disparar dinámicamente (runtime) un evento OnClick ?

Ejemplo:
Tenemos un procedimiento que en runtime crea un formulario, un Memo y un Boton.
El fin de esto, es que, el usuario final escriba algo en el Memo y al hacer clic en el Boton lo pueda enviar a imprimir o a realizar otro tipo de tarea (en este caso no importa mucho).
El código es similar a esto:
Código Delphi [-]
procedure TForm1.MostrarFormularioDinamico;
var
  DebugForm: TForm;
  memo1: TMemo;
  Btn1: TButton;
  Pnl1: TPanel;
begin
    DebugForm:= TForm.Create(self);
    DebugForm.Width:= Trunc(Self.Width/2);

    Pnl1:= TPanel.Create(DebugForm);
    Pnl1.Parent:= DebugForm;
    Pnl1.Align:= alBottom;

    Btn1:= TButton.Create(DebugForm);
    Btn1.Parent:= Pnl1;
    Btn1.OnClick:= ClickMe; //<----este es el problematico

    memo1:= Tmemo.Create(DebugForm);
    memo1.Parent:= DebugForm;
    memo1.Align:= alClient;
    memo1.ScrollBars:= ssBoth  ;

    DebugForm.Show;
end;

Por lo general, el evento se declara en el formulario principal, en su sección privada y funciona correctamente (mientras se haga referencia a componentes, procedimientos, variables, etc, que sean visibles al TForm principal):
Código Delphi [-]
type
  TForm1 = class(TForm
  ...
  ...
  private
    procedure ClickMe(Sender : TObject);
  published
  end;

El problema reside es que a este evento no lo puedo asignar a un procedimiento "pre-declarado" ya que hace referencia y uso de elementos que se crean dinámicamente tal como el TMemo.
Tampoco fue posible dispararlo con un procedimiento local, al estilo:
Código Delphi [-]
procedure TForm1.MostrarFormularioDinamico;
var
  DebugForm: TForm;
  memo1: TMemo;
  Btn1: TButton;
  Pnl1: TPanel;
      
      procedure ClickMe(Sender: TObject);
      var
        s: string;
      begin
            try   
              s:= memo1.Text;
              ...
              ...
            except
              on E:Exception do MessageDlg(E.Message, mtWarning, [mbOk],0);
            end;
      end;

begin
    DebugForm:= TForm.Create(self);
    DebugForm.Width:= Trunc(Self.Width/2);

    Pnl1:= TPanel.Create(DebugForm);
    Pnl1.Parent:= DebugForm;
    Pnl1.Align:= alBottom;

    Btn1:= TButton.Create(DebugForm);
    Btn1.Parent:= Pnl1;
    Btn1.OnClick:= ClickMe; 

    memo1:= Tmemo.Create(DebugForm);
    memo1.Parent:= DebugForm;
    memo1.Align:= alClient;
    memo1.ScrollBars:= ssBoth  ;

    DebugForm.Show;
end;

¿ Alguien tiene alguna aproximación para su solución ? ^\||/

Neftali [Germán.Estévez] 30-07-2014 17:18:09

Asignando nombres a los componentes y usando FindComponent no debería ser difícil.
POdría ser una primera forma sin muchas complicaciones.

Código Delphi [-]
procedure TForm1.MostrarFormularioDinamico;
var
  DebugForm: TForm;
  memo1: TMemo;
  Btn1: TButton;
  Pnl1: TPanel;
begin
    DebugForm:= TForm.Create(self);
    DebugForm.Width:= Trunc(Self.Width/2);
    DebugForm.Name := 'FormException';

    Pnl1:= TPanel.Create(DebugForm);
    Pnl1.Parent:= DebugForm;
    Pnl1.Align:= alBottom;
    Pnl1.Name := 'pnl1';

    Btn1:= TButton.Create(DebugForm);
    Btn1.Parent:= Pnl1;
    Btn1.Name := 'Btn1';
    Btn1.OnClick := ClickMe; //<----Ahora ya no da problemas  ;-)

    memo1:= Tmemo.Create(DebugForm);
    memo1.Parent:= DebugForm;
    memo1.Align:= alClient;
    memo1.ScrollBars:= ssBoth  ;
    memo1.Name := 'memo1';

    DebugForm.Show;
end;

En el evento ClickMe puedes hacer algo así (no he puesto comprobaciones de error):

Código Delphi [-]
procedure TForm1.ClickMe(Sender: TObject);
var
  s: string;
  f:TForm;
  m:TMemo;
begin
  try
    f := TForm(TComponent(Sender).Owner);
    m := TMemo(f.FindComponent('memo1'));
    s := m.Text;

    MessageDlg(Format('Se ha pulsado el botón en el Formulario: %s'+
                      #13+#10+'En el Memo hay lo siguiente:'+#13+#10+
                      '----------------------------------------------'+
                      #13+#10+'%s'+#13+#10+'----------------------------------------------',
                      [f.Name, m.Text]), mtInformation, [mbOK], 0);

  except
    on E:Exception do MessageDlg(E.Message, mtWarning, [mbOk],0);
  end;
end;

Un saludo.

hgiacobone 30-07-2014 18:24:04

Cita:

Empezado por Neftali (Mensaje 479538)
...POdría ser una primera forma sin muchas complicaciones.

Esa es muy buena querido Neftali... lo voy a probar en la semana. ^\||/
Es una lástima que haya que "duplicar" los componentes en variables locales en el segundo procedimiento para poder trabajarlos, pero al menos, algo es algo...:D
Saludos cordiales,

ecfisa 31-07-2014 00:44:40

Hola hgiacobone.
Cita:

Empezado por hgiacobone (Mensaje 479541)
...Es una lástima que haya que "duplicar" los componentes en variables locales en el segundo procedimiento para poder trabajarlos, pero al menos, algo es algo...:D

Creo que Neftali escribió el código de ese modo para hacerlo mas claro y didáctico, pero es posible prescindir totalmente de las variables locales al método ClickMe:
Código Delphi [-]
procedure TForm1.ClickMe(Sender: TObject);
begin
  try
    MessageDlg(Format('Se ha pulsado el botón en el Formulario: %s'+
                      #13+#10+'En el Memo hay lo siguiente:'+#13+#10+
                      '----------------------------------------------'+
                      #13+#10+'%s'+#13+#10+'----------------------------------------------',
                      [TForm(TComponent(Sender).Owner).Name,
                       TMemo(TForm(TComponent(Sender).Owner).FindComponent('memo1')).Text]),
                       mtInformation, [mbOK], 0);

  except
    on E:Exception do MessageDlg(E.Message, mtWarning, [mbOk],0);
  end;
end;
Fijate que lo único que hice, fué reemplazar los nombres de variables por los moldeos y funciónes que estaban en el el ejemplo de Germán. En lo personal, me parece que usar las variables locales da un código mas eficiente y menos propenso a confusiones y errores.

Saludos :)

ozsWizzard 31-07-2014 10:08:28

Estoy con ecfisa. ;), no sé que tiene de malo usar variables.

Neftali [Germán.Estévez] 31-07-2014 10:22:18

Cita:

Empezado por hgiacobone (Mensaje 479541)
Es una lástima que haya que "duplicar" los componentes en variables locales en el segundo procedimiento para poder trabajarlos, pero al menos, algo es algo...

Tal y como ha comentado ecfisa, la definición de esas variables está principalmente para "clarificar" el código (sobre todo en este caso que mostraba un ejemplo de uso). No es obligatoria.

De todas yo habitualmente lo uso, por varias razones.
Lo pimero que hay que aclarar es que "no está duplicando componentes" simplemente estás creando variables que apuntan a ellos, por lo tanto no estás "duplicando" nada, y esas variables (no los componentes) se liberan al salir de ese procedimiento.
Por otro lado, tal y como he dicho, si se utilizara ese método, habría que añadir comprobaciones de seguridad de este tipo, cosa que se facilita/simplifica si defines la variables:

Código Delphi [-]
  ...
  // Si el owner está asignado
  if Assigned(TComponent(Sender).Owner ) then begin  
    // es un tForm?
  if (TComponent(Sender) is TForm) then begin
    TForm(TComponent(Sender).Owner).FindCom('memo1') ...
    
    ...
    // Asignar valor
    TMemo(TForm(TComponent(Sender).Owner).FindComponent('memo1')).Text := ...

Por último (personalmente) la estética de este código no me gusta, me "choca", es poco legible para un programador que llegue detrás tuyo a revisarlo, además de que soy "vago" y no me gusta escribir de más de la cuenta. Además cuantas más cosas vas poniendo en el código más tienes que repetir esos "churros".
Es algo personal, pero yo prefiero definir un par de variables y que el código se parezca al que he puesto anteriormente.


La franja horaria es GMT +2. Ahora son las 23:36:06.

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