Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > C++ Builder
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 27-05-2004
Sonic Sonic is offline
Miembro
 
Registrado: may 2004
Posts: 40
Poder: 0
Sonic Va por buen camino
Unhappy Usar eventos en un VCL

Tengo diseñado una primera versión funcional de un TRichEdit que reconoce la sintaxis de lo que se esta escribiendo y resalta mediante el formato del texto escrito diversas secciones del texto. Se me ocurrió que con este código podría crear un componente VCL para poder usarlo en otros proyectos. Pero no he conseguido realizar una buena gestión de los eventos. Me explico:
En mi componente uso eventos como OnSelectionChange y OnChange, pero el en VCl no sé muy bien como hacer uso de esto. Ya que si suplanto el manejador del evento, el usuario final de mi componente no podrá usarlo.

La solución que encontré fue suplantar el proceso WndProc y esperar a recibir un mensaje concreto (que sinceramente no se cuál es 45109) pero, a partir del cual puedo compobar si el usuario final ha colocado un manejador de evento, si es así tomo la dirección de este manejador y lo suplanto por una función propia que ejecuta el código que yo necesito y posteriormente usa el puntero para llamar a la función del usuario.

Me pareció una buena solución, de hecho es justo lo que necesito, pero lo que no sabía es que el componente VCL se ejecuta cuando estás en fase de diseño de la aplicación, borrando la casilla del inspector de objetos en la se pone el nombre de la función que el usuario quiere que responda. En principio se comporta bien pero si guardas el proyecto ya se guarda con esa casilla borrada y mi componente piensa que el usuario no ha asignado ninguna funcion y por tanto solo ejecuta la interna.

Por favor, cualquier idea al respecto me resultará útil. Gracias
Responder Con Cita
  #2  
Antiguo 27-05-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Dos cosas:

-Dices que quieres hacer que tu componente sea VCL... ¿Ahora no lo es?¿entonces qué es?

-Si te he entendido bien, todo funciona Ok excepto la asignación del evento.. ¿por qué no nos pones el código donde lo haces y vemos si hay algun problema?
__________________
E pur si muove
Responder Con Cita
  #3  
Antiguo 27-05-2004
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 29
Lepe Va por buen camino
Sonic, creo que el propio delphi puede sacarte de ese apuro, por supuesto tambien un buen manual de POO, pero bueno, al grano.

inserta un combobox (por ejemplo) en un form, y despues en la zona de declaración: mantén la tecla CTRL presionada y pulsa en lo subrayado.

Código Delphi [-]
type Form1 = Tform
   combobox1:Tcombobox

Así accedes a la declaración del combobox. Verás que ese combo hereda de TCustomComboBox, que tambien tiene eventos con el mismo nombre y que hace un override de esos métodos. Creo entender que es lo que necesitas, pero la creación de componentes es una tarea árdua si no se tienen los conocimientos. (hay monton de cursillos en internet sobre ello, pero se necesita tiempo).

Una alternativa rápida para reutilizar componentes es crear un TFrame o un Component Template.

Saludos
Responder Con Cita
  #4  
Antiguo 27-05-2004
Sonic Sonic is offline
Miembro
 
Registrado: may 2004
Posts: 40
Poder: 0
Sonic Va por buen camino
Supongo que no me explicado muy bien, suele ocurrirme a menudo, es que aprendí builder por mi cuenta y es muy probable que no esté usando los términos correctos, veras:

Cuando digo que mi componente lo quiero hacer VCL lo que quiero decir es que lo quiero incrustar en las barras de herramientas, ahora mismo lo tengo en la barra Samples (lo llamo TSRichEdit y hereda obviamente de TRichEdit), disponible para poder ser arrastrado a la aplicación de cualquier usuario.

Según tenía entendido eso es un componente VCL, pero ya te digo si no es así agradecería una aclaración.

Mi problema no es la asignación del evento, para asignarlo uso órdenes como:

Puntero_a _funcion_de_usuario =OnSelectionChange;
OnSelectionChange=MiFuncion;

Y el evento se asigna correctamente.

Lo que yo quiero es que mi componente, cuando alguién lo "pegue" en su aplicación responda al evento OnSelectionChange, primero mediante mi funcion y despus mediante la que él tenga especificada en el Inspector de Objetos.

Para ello, la última linea del código de MiFuncion es :

Puntero_a _funcion_de_usuario (Owner);

Y así se ejcuta primero mi función y luego la del usuario.

Y ahora cuento de nuevo el problema:

Cuando, como usuario, del Componente VCL abro un proyecto, que contiene ese nuevo componente, pegado desde la barra de herramientas Samples. Éste entra en estado de ejecucíón (en la versión anterior del componente, la que no está integrada en la barra SAMPLES no se ejecuta el código del componente hasta que no se ejecuta el proyecto completo por eso me refiero a uno como VCL (Visual Component Library) y al otro como componente o clase a secas). Al ajecutarse el código del componente se llega a las lineas:

Puntero_a _funcion_de_usuario =OnSelectionChange;
OnSelectionChange=MiFuncion;

En concreto la última borra automáticamente en el inspector de objetos la casilla donde antes ponía SRichEdit1SelectionChange (por ejemplo) y me la deja vacía.
La función SRichEdit1SelectionChange sigue existiendo en el código pero el vículo se ha roto.

Cuando posteriormente le doy a ejecutar, la aplicación se ejecuta sin problemas, ya que el componente tiene capturada la dirección de la funcion del usuario (SRichEdit1SelectionChange). Pero, si guardo el proyecto, esta vez se guarda sin el vículo a la función de usuario (es decir con la casilla del Inspector de Objetos vacía). De modo que al cerrar y abrir el proyecto otra vez, cuando mi componente va a guardar en la variable
Puntero_a _funcion_de_usuario la dirección de la funcion de usuario que atiende a OnSelectionChange se encuentra con que esta dirección es NULL (el vínculo hora no existe) y posteriomente cuando se ejecuta el proyecto completo al producirse el evento OnSelectionChange solo se ejecuta mi función y no la del usuario pese a que está esta escrita.

Espero que esta vez haya quedado un poco más claro que es lo que quiero hacer y cuál es mi problema, y espero que ahora sí me podaís ayudar.

Gracias
Responder Con Cita
  #5  
Antiguo 27-05-2004
Sonic Sonic is offline
Miembro
 
Registrado: may 2004
Posts: 40
Poder: 0
Sonic Va por buen camino
Muchas gracias Lepe ya he mirado muchos manuales y creo haberlos entendido, lo que quiero hacer es algo parecido a lo que me comentas del override. Lo que en realidad quiero es que mi manejador de evento se ejecute siempre, ponga o no ponga el usuario uno propio, por eso hago el override pero al final en mi función (la propia) hago una llamada a la función del usuario.

Creo que en mi post anterior te puede quedar un poco más claro lo que quiero, no obstante cualquier alternativa es de considerar, a si que te agradecería que me explicaras un poco mejor lo del TFrame y el Component Template, pero te aviso que es impresindible que se pueda disponer de mi componente en la barra de herramientas.

Muchas Gracias
Responder Con Cita
  #6  
Antiguo 27-05-2004
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 25
__cadetill Va por buen camino
Aunque te ponga código Delphi espero que lo entiendas

El ejemplo muestra como lanzar (en un TDbGrid) el evento OnCellClick siempre (y si lo tiene, luego el del usuario).

Código Delphi [-]
  TExtendedGrid = class(TDbGrid)
  private
    FOldCellClick: TDBGridClickEvent;     // Evento antiguo de DBGridClick
  protected
    procedure ClicCelda(Column: TColumn);

    property OldCellClick: TDBGridClickEvent read FOldCellClick write FOldCellClick;
  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

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

  if Assigned(OnCellClick) then
    OldCellClick := OnCellClick // si tiene, lo guardo
  else
    OldCellClick := nil;
  OnCellClick := ClicCelda; // le asigno mi procedimiento
end;

procedure TExtendedGrid.ClicCelda(Column: TColumn);
begin
  // Hago lo que sea..........

  // Si tenía evento asociado.... lo lanzo
  if Assigned(OldCellClick) then
    OldCellClick(Column);
end;

Espero te sirva
Responder Con Cita
  #7  
Antiguo 27-05-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Cita:
Empezado por Sonic
Cuando digo que mi componente lo quiero hacer VCL lo que quiero decir es que lo quiero incrustar en las barras de herramientas, ahora mismo lo tengo en la barra Samples (lo llamo TSRichEdit y hereda obviamente de TRichEdit), disponible para poder ser arrastrado a la aplicación de cualquier usuario.
Vale, ahora te entiendo. Por lo que dices, imagino que lo que ahota tienes es un component template, que lo que hace es pegar el código asignado a los eventos el form donde lo sueltas. Lo que quieres hacer es un componente nuevo que encapsule ese comportamiento.

Cita:
Empezado por Sonic
Lo que yo quiero es que mi componente, cuando alguién lo "pegue" en su aplicación responda al evento OnSelectionChange, primero mediante mi funcion y despus mediante la que él tenga especificada en el Inspector de Objetos.
Ok, entonces tienes que cambiar un poco la filosofía. Te pongo un ejemplo en Delphi porque el CB no lo tengo a mano, pero la traducción no es complicada.
Código Delphi [-]
unit richEdit1;
interface
uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls, ComCtrls, Dialogs;
type
  trichEdit1 = class(trichedit)
  private
    { Private declarations }
  protected
    //este método se declara en TCustomRichEdit y es el encargaado de lanzar el evento
    procedure SelectionChange; override;
  public
    { Public declarations }
  published
    { Published declarations }
  end;
procedure Register;
implementation
procedure Register;
begin
  RegisterComponents('NexContr', [trichEdit1]);
end;
{ trichEdit1 }
procedure trichEdit1.SelectionChange;
begin
  ShowMessage('hola');
  //Aquí va tú código, que se ejecutará antes que el que haya asignado el usuario
  inherited;
  //como llamamos a la versión de la superclase, ésta ya se encarga de activar el
  //manejador del evento si se ha asignado alguno
end;
end.
__________________
E pur si muove
Responder Con Cita
  #8  
Antiguo 27-05-2004
__cadetill __cadetill is offline
Miembro
 
Registrado: may 2003
Posts: 3.387
Poder: 25
__cadetill Va por buen camino
mmmm, Marto, perdona, pero..... de esta manera creo que no saltará el evento si no lo tiene asociado en el componente, no?

PD: lo digo con la voca xica, que no lo he probado
Responder Con Cita
  #9  
Antiguo 27-05-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Cita:
Empezado por cadetill
mmmm, Marto, perdona, pero..... de esta manera creo que no saltará el evento si no lo tiene asociado en el componente, no?
Copia y pega el código, lo pruebas y luego me cuentas
__________________
E pur si muove
Responder Con Cita
  #10  
Antiguo 27-05-2004
Sonic Sonic is offline
Miembro
 
Registrado: may 2004
Posts: 40
Poder: 0
Sonic Va por buen camino
Estimado Cadetill:

He respasado el código Delphi aunque no estoy muy ducho en la sintaxis de Delphi creo que es exáctamente lo que yo hago. Pero me alegra ver que ya más o menos se sabe por donde van los tiros.

Pego a continuación mi código:
Código:
 
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
 
static inline void ValidCtrCheck(TSRichEdit *)
{
  new TSRichEdit(NULL);
}
//---------------------------------------------------------------------------
__fastcall TSRichEdit::TSRichEdit(TComponent* Owner)
: TRichEdit(Owner)
{
  ExOnSelectionChange=false;
  Primer_evento=false;
} 
//---------------------------------------------------------------------------
namespace Srichedit
{
	void __fastcall PACKAGE Register()
  {
	TComponentClass classes[1] = {__classid(TSRichEdit)};
	RegisterComponents("Samples", classes, 0);
  }
}
//---------------------------------------------------------------------------
void __fastcall TSRichEdit::WndProc (Messages::TMessage &Message)
{
  if (!Primer_evento)
  { 
	{
	   Primer_evento=true;
	   if (OnSelectionChange!=NULL)
	   {
		 ExOnSelectionChange=true;
		 FExOnSelectionChange=OnSelectionChange;
	   }
 
	   OnSelectionChange=FInOnSelectionChange;
	   ShowMessage("Hola quillo 0");
	   OnSelectionChange=FExOnSelectionChange;
	 }
   }
 
  TWinControl::WndProc(Message);
}
//---------------------------------------------------------------------------
void __fastcall TSRichEdit::FInOnSelectionChange (TObject *Sender)
{
  ShowMessage("Hola Quillo 1");
  if (ExOnSelectionChange)
  FExOnSelectionChange(Owner);
}
//---------------------------------------------------------------------------
Según entiendo yo, es lo mismo, salvo que el puntero a la funcion FExOnSelectionChange no lo he declarado como una propiedad. El problema sigue siendo el mismo, mientras estoy en modo de diseño de la aplicación. El componente se ejecuta y en la linea en la que se suplanta el MAnejador del evento, se porvoca el borrado de la citada casilla en el Inspector de objetos

Te dejo el código por si puedes darme alguna pista
Gracias

Última edición por marto fecha: 27-05-2004 a las 13:20:58.
Responder Con Cita
  #11  
Antiguo 27-05-2004
Sonic Sonic is offline
Miembro
 
Registrado: may 2004
Posts: 40
Poder: 0
Sonic Va por buen camino
Guau! He ido a desayunar, no me esperaba que respondiérais tan rápido, muchísimas gracias. Respondo a Marto, diciendo que no se me había ocurrido esa forma de implemetar mi función, entre otras cosas porque desconocía el siginificado de Inherit;.

Voy a intentar hacer una traducción a Borland y a ver que pasa, No creo que tarde más de 15 minutos.

Por cierto aun no se si lo que hago es un VCL o un template, por favor si puedes aclararmelo o direccionarme a alguna página te lo agradecería.
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


La franja horaria es GMT +2. Ahora son las 22:19:52.


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