Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 09-02-2007
Avatar de buildero_d
buildero_d buildero_d is offline
Miembro
 
Registrado: sep 2005
Ubicación: Puebla, México
Posts: 37
Poder: 0
buildero_d Va por buen camino
Override evento

Que tal colegas....

Tengo ya varios dias tratando de resover este poblema y no doy con la solución. Les explico...

He desarrollado un componente no visual para ejecutar ciertas acciones que me interesan cuando se ejecuta el evento OnCloseQuery de un formulario.

Dentro de mi clase creo una variable de tipo TForm para poder accesar al formulario, haciendo el cast correspondiente cuando mi compenente es creado.

Dentro del constructor de mi componente...
Código:
FFormPropietario = static_cast<TForm*>(Owner);
De esta forma, apunto al formulario en que fue agregado mi componente.

Mediante la siguiente instrucción asigno la función que debe ejecutarse en el evento CloseQuery del formulario.
Código:
FFormPropietario->OnCloseQuery = MiCloseQuery;
MiCloseQuery es un metodo que tengo implementado en mi componente. Hasta aqui bien. Cuando inserto mi componente en un form y cierro el form se ejecuta el código de mi componente tal como debe ser.

El problema esta cuando agrego código en el evento OnCloseQuery del formulario donde he insertado mi componente, este no es ejecutado, solo se ejecuta el de mi componente.

Lo que necesito es que si agrego código al evento OnCloseQuery del form, este se ejecute, pero tambien se debe ejecutar el de mi componente.

En pocas palabras, necesito hacer un override del evento OnCloseQuery.

A lo mejor lo que necesito es capturar el evento (desde mi componente) que me indica que se intenta cerrar el form y ejecutar el código que me interesa (desde mi componente) y seguir con la secuencia de instrucciones que se han agregado en el evento OnCloseQuery del formulario.

Cualquier ayuda o sugerencia será bienvenida.

Gracias y saludos
Responder Con Cita
  #2  
Antiguo 09-02-2007
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
¿Qué código necesitas ejecutar al cerrar el form?

Igual no deberías hacerlo en ese momento.
Quizás haya un momento mejor de hacerlo.
Quizás se le deba proporcionar un evento al usuario del componente... con esto quiero decir que estas intentando modificar el comportamiento de algo que no es tuyo, y por tanto, quizás no sea buena idea hacerlo.

Cuando declaras una variable reservando memoria.... ¿el form se encarga de liberarlo? No, eres tú en el Onclose de la ventana el encargado de hacer un .Free del mismo.

La solución más rápida es proporcionar un método al usuario de tu componente que pueda ser llamado al cerrar el form o cuando al usuario se le antoje.

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #3  
Antiguo 09-02-2007
Avatar de buildero_d
buildero_d buildero_d is offline
Miembro
 
Registrado: sep 2005
Ubicación: Puebla, México
Posts: 37
Poder: 0
buildero_d Va por buen camino
Que tal lepe, gracias por contestar.

Bien, el código que se ejecuta al cerrar el form es una rutina en particular que he creado y que aplica para uno o varios forms. Si yo como desarrollador se que un formulario en particular necesita ejecutar dicho código... simplemente agrego mi componente y listo. Pondré un simple ejemplo.... imagina que encapsulé en un nuevo componente la famosa pregunta "¿Esta seguro que desea salir?", esta rutina la pude haber diseñado como una función que no pertenece a niguna clase y mandarla a ejecutar las veces que sea necesario en los forms que sean necesarios..... ahora yo voy un poco mas adelante... imagina que en lugar de tener que hacer la llamada de manera explicita lo hago de manera implicita a través del componente. Con solo agregarlo bastaria para que cada vez que se intente cerrar el form la rutina que envia el mensaje se ejecuta. En pocas palabras escribir menos y solo dedicarme a "ensamblar".

Asi que si por algún motivo necesito ademas de la pregunta de cierre del form, agregar otras lineas de código (que solo aplica en un caso en particular) y esas lineas las agrego en el evento OnCloseQuery del form ... solo se ejecuta la rutina del componente y no ambas.

Seguire investigando, a ver que puedo encontrar... y si hay mas ideas, pues serán bien recibidas.

Saludos!
Responder Con Cita
  #4  
Antiguo 09-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Antes de asignar tu propio evento CloseQuery guarda el que pudiera tener el formulario para poder llamarlo en su momento. Te pongo un ejemplo, está en delphi pero imagino que no tendrás problemas para pasarlo a C++:

Código Delphi [-]
{
  Componente para manejar el evento CloseQuery del formulario
  donde se inserte.
}
unit CloseQuery;

interface

uses
  Windows, SysUtils, Classes, Forms;

type
  TCloseQueryComponent = class(TComponent)
  private
    FForm: TForm; // formulario contenedor
    FOldCloseQuery: TCloseQueryEvent; // evento propio del formulario

  protected
    procedure ValidateContainer(AComponent: TComponent); override;
    procedure Loaded; override;
    procedure CloseQuery(Sender: TObject; var CanClose: Boolean); virtual;

  public
    constructor Create(AOwner: TComponent); override;
  end;

procedure Register;

implementation

{
  Registrar la componente
}
procedure Register;
begin
  RegisterComponents('buildero_d', [TCloseQueryComponent]);
end;

{ TCloseQueryComponent }

{
  Constructor de la componente

  Aquí sólo asignamos la referencia al formulario
}
constructor TCloseQueryComponent.Create(AOwner: TComponent);
begin
  inherited;

  if AOwner is TForm then
    FForm := TForm(AOwner);
end;

{
  Valida el contenedor

  Aquí nos aseguramos que estamos insertando la componente
  en un formulario y no, por ejemplo, en un DataModule.
}
procedure TCloseQueryComponent.ValidateContainer(AComponent: TComponent);
begin
  inherited;

  if not (AComponent is TForm) then
    raise Exception.Create('Este componente sólo puede insertarse en un formulario');
end;

{
  La VCL llama al método Loaded cuando ha terminado de leer el dfm
  del formulario. Entonces podemos estar seguros de que ya se dispone
  del evento CloseQuery asignado en el diseño. Esto no podría asegurarse
  en el constructor.
}
procedure TCloseQueryComponent.Loaded;
begin
  inherited;

  if Assigned(FForm) then
  begin
    FOldCloseQuery := FForm.OnCloseQuery;
    FForm.OnCloseQuery := CloseQuery;
  end;
end;

{
 Nuestro evento CloseQuery
}
procedure TCloseQueryComponent.CloseQuery(Sender: TObject; var CanClose: Boolean);
const
  Flags = MB_YESNO or MB_ICONWARNING;

begin
  if Assigned(FForm) then
  begin
    if Application.MessageBox('¿Desea cerrar esta ventana?', 'Confirmar', Flags) = ID_YES then
    begin
      CanClose := true;

      {
         Si el usuario accede a cerrar el formulario, probamos si había un
         evento asignado drante el diseño y, de ser así, lo invocamos.
      }
      if Assigned(FOldCloseQuery) then
        FOldCloseQuery(FForm, CanClose);
    end
    else
      CanClose := false;
  end;
end;

end.

// Saludos
Responder Con Cita
  #5  
Antiguo 09-02-2007
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is online now
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.286
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por buildero_d
Lo que necesito es que si agrego código al evento OnCloseQuery del form, este se ejecute, pero tambien se debe ejecutar el de mi componente.
Lo que se suele hacer en esos casos es al asignar tu evento, guardarte en una variable el apuntador al otro evento y al ejecutar el tuyo, llamar al otro antes o después segun te interese.

Algo aí:

Código Delphi [-]
==> La variable para guardar el otro evento
private 
  _OLDMouseMove: TMouseMoveEvent;  // Para guardar el otro

==> El procedimiento que quieres ejecutar tú
    // procedimiento para capturar movimiento del ratón
    procedure MyMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

...


==> Qué hay en tu procedimiento; En este caso lo primero que 
==> se hace es llamar al otro
//: procedimiento para capturar movimiento del ratón
procedure TCustomizeGrid.MyMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  pt: TGridCoord;
begin

  // Lanzamos el evento programado anteriormente
  if Assigned(_OLDMouseMove) then begin
    _OLDMouseMove(Sender, Shift, X, Y);
  end;
......


==> Aquí es donde asignar tu procedimiento y te apuntas el otro...
  // Asignado ya el evento del Grid?  (OnMouseMove)
  if Assigned(FGrid.OnMouseMove) then begin
    // Lo redireccionamos
    _OLDMouseMove := FGrid.OnMouseMove;
  end;
  // Lo "Capturamos" para realizar nuestras cosas
  FGrid.OnMouseMove := MyMouseMove;
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #6  
Antiguo 09-02-2007
Avatar de buildero_d
buildero_d buildero_d is offline
Miembro
 
Registrado: sep 2005
Ubicación: Puebla, México
Posts: 37
Poder: 0
buildero_d Va por buen camino
Muchas gracias colegas por sus comentarios.. me han sido de gran ayuda y me han dado una idea mas clara.

Pues bien, antes de tratar de que mi rutina quede como la necesito, decidí hacer un componente con el que cual he probado todo lo aqui explicado.

Y el ejemplo trata solamente de enviar el mensaje de advertencia para que el usuario decida si desea cerrar el form.

Les comento que el objetivo se ha conseguido... ejecutar el codigo del componente y también el código que se asigna en modo diseño del form. El codigo del componente envia el mensaje de advertencia y el codigo del evento OnCloseQuery del form envia un simple mensaje.

Aqui les dejo el código...claro que es sencillo, pero ilustra el objetivo y puede servir como referencia si alguien necesita algo similar.

Nota: Al final explico el único detalle que se me presenta

Esta es declaración de la clase
Código:
//---------------------------------------------------------------------------

#ifndef CloseQueryH
#define CloseQueryH
//---------------------------------------------------------------------------
#include <SysUtils.hpp>
#include <Classes.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class PACKAGE TCloseQuery : public TComponent
{
private:
    TForm *FForm;
    TCloseQueryEvent FOldCloseQuery;
protected:
    virtual void __fastcall MiCloseQuery(TObject *Sender, bool &CanClose);
    DYNAMIC void __fastcall ValidateContainer(TComponent *AComponent);
    void __fastcall Loaded();
public:
    __fastcall TCloseQuery(TComponent* Owner);
__published:
};
//---------------------------------------------------------------------------
#endif
Y aqui tenemos la implementación...
Código:
//---------------------------------------------------------------------------

#include <basepch.h>
#pragma hdrstop
#include "CloseQuery.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//

static inline void ValidCtrCheck(TCloseQuery *)
{
    new TCloseQuery(NULL);
}
//---------------------------------------------------------------------------
__fastcall TCloseQuery::TCloseQuery(TComponent* Owner)
    : TComponent(Owner)
{
    /*  Si el Owner hereda da un clase tipo TForm
    asignamos la referencia al formulario (aunque tal vez
    no seria necesario verificar ya que existe la función que
    válida el tipo de contenedor, que en este caso debe ser un form) */
    if ( Owner->InheritsFrom(__classid(TForm)) )
           FForm = (TForm*)Owner;
}
//---------------------------------------------------------------------------
namespace Closequery
{
    void __fastcall PACKAGE Register()
    {
         TComponentClass classes[1] = {__classid(TCloseQuery)};
         RegisterComponents("Samples", classes, 0);
    }
}
//---------------------------------------------------------------------------

/* Nuestro evento CloseQuery */
void __fastcall TCloseQuery::MiCloseQuery(TObject *Sender, bool &CanClose)
{
    /* Se si a asignado un evento en modo de diseño del form
    este debe ejecutarse */
    if ( FOldCloseQuery != NULL)
        FOldCloseQuery(FForm, CanClose);


    if ( Application->MessageBoxA("¿Desea salir?",
        "Confirme", MB_ICONQUESTION | MB_YESNO ) != IDYES )
            CanClose = false;
}

/* Se valida el contender del componente */
void __fastcall TCloseQuery::ValidateContainer(TComponent *AComponent)
{
    if ( ! AComponent->InheritsFrom(__classid(TForm)) )
        throw Exception("Este componente sólo puede insertarse en un formulario");
}


/*
  La VCL llama al método Loaded cuando ha terminado de leer el dfm
  del formulario. Entonces podemos estar seguros de que ya se dispone
  del evento CloseQuery asignado en el diseño. Esto no podría asegurarse
  en el constructor. (Texto extraido de la constestación de roman. Gracias)
*/
void __fastcall TCloseQuery::Loaded()
{
    //TComponent::Loaded();
    if ( FForm != NULL )
    {
        FOldCloseQuery = FForm->OnCloseQuery;
        FForm->OnCloseQuery = MiCloseQuery;
    }
}
Bien, el único detalle que se presenta es el siguiente: resulta que cuando cierro mi proyecto y lo vuelvo a abrir.....en la pestaña de eventos del Inspector de Objetos (teniendo seleccionado el form)... se pierde la referencia al código agregado en modo diseño del form del evento OnCloseQuery.. aunque al ejecutar la aplicación si se ejecuta dicho código.

Basta con volver a hacer doble click sobre el evento para que vuelva a tomar la referencia....pero si lo cierro y lo vuelvo a abrir, nuevamente se pierde. Es un extraño comportamiento que no "afecta" el funcionamiento dado que se ejecutan ambos códigos.

Nota: utilizo C++ Builder 6.0

Les agradezco su atención y consejos. Ahora a investigar sobre este "extraño comportamiento..."

Saludos!!!

Última edición por buildero_d fecha: 09-02-2007 a las 19:25:20.
Responder Con Cita
  #7  
Antiguo 09-02-2007
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Debí preveerlo El comportamiento no es extraño: el dfm se carga cada vez que abres el proyecto, se ejecuta Loaded y se hace el reemplazo del evento, y como apunta a algo que no está publicado (published), el inspector de objetos no sabe qué poner. No sé yo si pueda tener consecuencias pero me late que sí. Tampoco sé cómo solucionarlo pero prueba poner el Loaded así:

Código Delphi [-]
  inherited;

  if Assigned(FForm) and not (csDesigning in ComponentState) then
  begin
    FOldCloseQuery := FForm.OnCloseQuery;
    FForm.OnCloseQuery := CloseQuery;
  end;

No estoy seguro que funcione pero en principio, ahora verifica que no se esté en modo de diseño antes de hacer la reasignación del evento.

// Saludos
Responder Con Cita
  #8  
Antiguo 09-02-2007
Avatar de buildero_d
buildero_d buildero_d is offline
Miembro
 
Registrado: sep 2005
Ubicación: Puebla, México
Posts: 37
Poder: 0
buildero_d Va por buen camino
Asi es roman... es correcta tu teoría. Al cargar la definición del form intentaba asignar a algo "inexistente". Fue suficiente con verificar que antes de reasignar el evento no se este en modo diseño.

Saludos y gracias a todos por sus aportes.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Llamar evento desde otro evento nachito_tuc OOP 1 23-08-2006 21:37:43
Override eventos On... lento manu OOP 12 08-10-2005 11:37:31
Procedure SetVisible... ; override elcigarra OOP 3 22-07-2005 19:27:27
Qué Evento Programar andresenlared Conexión con bases de datos 1 30-12-2003 20:57:18
evento OnRecordChange? pepe2000 Tablas planas 3 18-12-2003 15:59:34


La franja horaria es GMT +2. Ahora son las 08:36:53.


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
Copyright 1996-2007 Club Delphi