Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   creando componente (https://www.clubdelphi.com/foros/showthread.php?t=6609)

Descendents 14-01-2004 20:32:19

creando componente
 
Tengo una pregunta, ¿como puedo yo en un determinado procedure dentro de mi componente, crear otro componente? pero que el parent sea el parent de mi componente.NO que el parent sea el mismo componente.

Es decir pongamos que hago un componetne que hereda de un tbutton, pero en el on create del mismo, que cree un tmemo, en el form , no dentro del boton.Dentro del boton seria, paren := self;

He probado parent := self.parent; pero entonces no me aparece nada.

Gracias.

La finalidad, es que en un deterrminado procedimiento o evento o lo que sea, poder crear un determinado componente, pero que el parent sea el form, o sino el parent de mi componente.

Seria que cuando pongo Tmibutton en el formulario, apreciera Tmibutton, y un Tmemo en una determinada posicion, quien dice tmemo, dice lo que sea.

Saludos
Muchas gracias

delphi.com.ar 14-01-2004 20:38:57

La solución es lo que tu propones, fíjate que el código que muestras no este dentro de un with, ten en cuenta que en el create del componente aún no esta asignado el parent del mismo.

Código:

constructor TMiComponente.Create(AOwner: TComponent); override;
begin
  inherited;
  FBoton := TButton.Create(Self);
end;

procedure TMiComponente.SetParent(AParent: TWinControl); override;
begin
  inherited;
  FBoton.Parent := AParent;
end;

en el caso que sea en un procedure como vos decís:

Código:

procedure TMiComponente.CrearBoton;
begin
  FBoton := TButton.Create(Self);
  FBoton.Parent := Parent;
end;

Saludos!

Descendents 15-01-2004 11:29:17

Cita:

ten en cuenta que en el create del componente aún no esta asignado el parent del mismo.
Pues este era mi problema, ya me funciona.
Gracias de nuevo

Descendents 15-01-2004 18:06:36

Uso windows Xp y delphi 7 lo digo por si acaso.

cuando se trata de procedimiento ningún problema, el parent se asinga bien y todo.Pero lo de setparent al crear el componente, en momento de diseño todo bien, pero cuando compilo, y cierro la aplicación me da un error bastante grande, que tengo que volver a reiniciar el delphi..

Este es mi codigo de un componente simple y me da error.Haber si podeis decirme porfavor donde esta el error.Ahora que lo pienso igual el error esta en el destroy, por que es cuando me da error.

Código:

unit Edit2;

interface

uses
  SysUtils, Classes, Controls, StdCtrls;

type
  TEdit2 = class(TEdit)
  private
  Fboton :Tbutton;
    { Private declarations }
  protected
    procedure SetParent(AParent: TWinControl); override;
    { Protected declarations }
  public
    constructor Create(AOwner : TComponent); override;    {Constructor}
    destructor  Destroy; override;
    { Public declarations }
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Lezandi', [TEdit2]);
end;


constructor TEdit2.Create(AOwner: TComponent);
begin
  inherited;
  FBoton := TButton.Create(Self);
end;

destructor TEdit2.Destroy;
begin
  Fboton.free;
  inherited;
end;

procedure Tedit2.SetParent(AParent: TWinControl);
begin
  inherited;
  FBoton.Parent := AParent;
end;

end.


Gracias
Saludos

Descendents 15-01-2004 19:40:00

debugueando he visto que el error me lo da en el destroy justo en el inherited.

Hago algo mal, que cuando la aplicacion se cierra, por culpa del parent, me da un error que me hace reiniciar el programa entero.

Gracias de antemano

delphi.com.ar 15-01-2004 20:01:47

Tienes un problema en el orden de liberación de los componentes, solución: elimina la línea Fboton.Free, total queda siempre eliminado cuando se elimina el TEdit, por su relación Owner.

Saludos!

roman 15-01-2004 20:14:02

Cita:

Empezado por delphi.com.ar
Tienes un problema en el orden de liberación de los componentes, solución: elimina la línea Fboton.Free, total queda siempre eliminado cuando se elimina el TEdit, por su relación Owner.

¿Has probado esto?

Estuve haciendo pruebas al respecto y también me marca errores (aún quitando la línea que indicas), uno montón de "Access violation" e "Invalid pointer operation" y no queda más que Ctrl-Alt-Supr.

Esto sucede cuando se inserta la componente durante el diseño y creo que tiene que ver con el hecho de que el Designer no se entera de la componente creada.

También intenté usar InsertControl y aunque los errores no fueron tan catastróficos aún apareción uno aunque esto último ya no lo probé con detalle.

// Saludos

delphi.com.ar 15-01-2004 20:20:54

Pues, si lo he probado.... Este fue el texto original de mi respuesta, solo que lo resumí (bastante) porque creí que lo estaba complicando:

Bueno, te comento que he probado tu código y el error solo lo da si el Owner del TEdit2 destruye al componente, si lo destruyes "a mano" no se produce esto, lo que me lleva a sospechar que el problema es que primero se ejecuta el destroy del TWinControl y luego el de TComponent, que quiero decir con esto, que el form libera primero a todos los componentes relacionados por el Parent y luego los relacionados por el Owner, y como accede a la lista de abajo hacia arriba, destruye primero el botón y luego al edit, entonces cuando quieres destuír el botón explícitamente en el Destroy da un access violation, solución: elimina la línea Fboton.Free, total queda siempre eliminado cuando se elimina el TEdit, por su relación Owner.

delphi.com.ar 15-01-2004 20:25:10

¿Has recompilado el paquete donde tienes instalado el componente?... porque si lo cambias solo en RunTime, el exe funcionará sin problemas pero el IDE fallará porque conserva una versión antigua del componente.

roman 15-01-2004 20:33:09

Como dije, aún eliminando la línea del Free obtengo errores. Aquí está el codigo completo que según yo coincide con lo que dices:

Código:

unit EditEx;

interface

uses
  SysUtils, Classes, Controls, StdCtrls;

type
  TEditEx = class(TEdit)
  private
    FBoton: TButton;

  protected
    procedure SetParent(AParent: TWinControl); override;

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

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TEditEx]);
end;

constructor TEditEx.Create;
begin
  inherited;
  FBoton := TButton.Create(Self);
end;

procedure TEditEx.SetParent(AParent: TWinControl);
begin
  inherited;
  FBoton.Parent := AParent;
end;

end.

¿Qué me falta?

roman 15-01-2004 20:36:49

Cita:

Empezado por delphi.com.ar
¿Has recompilado el paquete donde tienes instalado el componente?

Sí claro. Acabo de hacerlo nuevamente y pasó esto:

1. Inserté el componente
2. Cerré el formulario
3. Cerré Delphi

Sin problemas

Y me dije a mí mismo: "MiMismo, algo andabas haciendo mal"
Entonces volví a abrir Delphi e hice:

1. Inserté el componente
2. Cerré Delphi

Accesss violation again.

// Saludos

Descendents 15-01-2004 20:37:00

Buenas, lo he probado, y a mi aún me sigue dando errores.Me pasa igual que ha roman

Por todos sitios donde he mirado, lo hacen como tu dices, pero no me funciona.

El labelededit que lleva delphi, le he mirado el codigo fuente, y tambien lo hacen igual.

No se, pero no me funciona.

El error es una lista interminable de errores hasta que tengo que reiniciarlo.

Gracias.

Descendents 15-01-2004 20:48:56

además he hecho esto

procedure Tedit2.SetParent(AParent: TWinControl);
begin
inherited;
FBoton.Parent := AParent;
showmessage(AParent.Name);
end;

y el mensaje es 'Form1' es decir, lo esta asignando bien.Pero al cerrar la aplicación algo hace.

Saludos

roman 15-01-2004 20:51:28

Cita:

Empezado por Descendents
El labelededit que lleva delphi, le he mirado el codigo fuente, y tambien lo hacen igual.

¡Ahhhhh! ¡No podía recordar cuál era la componente que incluía Delphi y que usaba esta técnica.

Vuelve a revisar el código y seguro que encontrarás cómo solucionarlo. Observa los puntos donde crea la etiqueta (SetupInternalLabel) y donde le asigna el Parent (SetParent) y verás que primero verifica que sea distinto de nil. También observa el uso de FreeNotification y Notification. El primero le indica a la etiqueta que le avise cuando se destruya y así, en Notification poder poner a nil la referencia.

// Saludos

Descendents 15-01-2004 20:58:48

lo he hecho esto que me dices.El setupinternallabel, si no recuerdo mal, lo que hacia era crearlo.

Y el notification le pasa el componente y la orden opremove o algo asi era Flabel := nil

Todo esto lo he probado.

No se.Haber si alguien seria tan amable de hacer un pequeño componente muy pequeño que lo unico que haga sea crar dos componentes a partir de uno y que cuando se cierre el programa no de todos esos errores.

Se que es un poco pedir, pero es que no me funciona lo que en teoria deberia de funcionar.

Muchas gracias

roman 15-01-2004 21:10:17

Cita:

Empezado por Descendents
No se.Haber si alguien seria tan amable de hacer un pequeño componente muy pequeño que lo unico que haga sea crar dos componentes a partir de uno y que cuando se cierre el programa no de todos esos errores.

Vamos a ver. Intenta este:

Código:

unit EditEx;

interface

uses
  SysUtils, Classes, Controls, StdCtrls;

type
  TEditEx = class(TEdit)
  private
    FBoton: TButton;

  protected
    procedure SetParent(AParent: TWinControl); override;
    procedure Notification(AComponent: TComponent;
      AOperation: TOperation); override;

  public
    constructor Create(AOwner: TComponent); override;

  published
    property Boton: TButton read FBoton;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TEditEx]);
end;

constructor TEditEx.Create;
begin
  inherited;

  FBoton := TButton.Create(Self);
  FBoton.FreeNotification(Self);
end;

procedure TEditEx.SetParent(AParent: TWinControl);
begin
  inherited;

  if Assigned(FBoton) then
    FBoton.Parent := AParent;
end;

procedure TEditEx.Notification(AComponent: TComponent; AOperation: TOperation);
begin
  inherited;

  if (AComponent = FBoton) and (AOperation = opRemove) then
    FBoton := nil;
end;

end.

Al parecer no me marca ningún error.

Claro que verás que aunque puedes modificar las propiedades del botón en el inspector de objetos, no puedes moverlo, ni siquiera seleccionarlo en el formulario mediante el ratón. Dependiendo de lo que desees quizá te convenga fijarte con más detalle en la implementación de TLabeledEdit para lograr que el botón se mueva junto con tu Edit.

// Saludos

delphi.com.ar 15-01-2004 21:22:21

Vale aclarar que yo estoy haciendo las pruebas en Delphi 5.
Lo único que agregué en un momento, pero luego quité fue:
Código:

procedure Tedit2.SetParent(AParent: TWinControl);
begin
  inherited;
  if not (csDestroying in ComponentState) Then
    FBoton.Parent := AParent;
end;

El notification es obligatorio(a mi parecer) cuando el usuario puede eliminar un objeto relacionado con el componente, esta vez en lugar de un usuario tenemos un Owner :D... que nos elimina los objeto... es una solución válida

Saludos!

Descendents 16-01-2004 09:35:01

Funciona.

¿Una cosa delphi.com.ar, que significa esa linea que has añadido milagrosa? :p

¿Y que diferencia hay con delphi 5 ?

Muchas gracias a los dos.

Saludos

Descendents 16-01-2004 10:28:35

Una pequeña cosa, ya puestos.

como existen estos mensajes de windows

procedure CMVisiblechanged(var Message: TMessage);message CM_VISIBLECHANGED;
procedure CMEnabledchanged(var Message: TMessage);message CM_ENABLEDCHANGED;
procedure CMBidimodechanged(var Message: TMessage);message CM_BIDIMODECHANGED;

que me sirven para saber si ha cambiado el bidimode o etc..., entonces yo se lo asigno al button.

¿que mensaje de windows es, el que se llama cuando un componente se mueve por la pantalla? no DRAG, sino que se mueve como sea.

¿O no necesito un mensaje de windows con un twincontrol?

como por ejemplo esta el
doenter;override;

¿no habra un domove o algo asi?

Aunque he buscado en la ayuda y no encontrado nada.

La diferencia con el labelededit, es que lleva el buton asignado como una propiedad, entonces supongo que el solo ya se encarga de moverlo cuando toca.

Pero en mi caso no quiero hacerlo asi, quiero controlar yo de alguna manera cuando el edit se mueve.

Espero se me enitenda

Gracias y ya con esto creo que no tengo ninguna intención más de molestar.Por que tela la de preguntas que he hecho en este hilo

Muchas gracias a los dos (Repito)y un saludo.

Descendents 16-01-2004 13:09:50

mi ultima pregunta ya me la contesto yo.I lo pongo por si alguien nunca tiene la misma duda.

procedure WMmove(var Message: TMessage); message WM_MOVE;

Y creo que la penultima pregunta que hice lo de la linea milagrosa, es que no se le debe asignar el parent en el momento de la destrucción,
¿NO?


Saludos

delphi.com.ar 16-01-2004 13:35:16

Cita:

Empezado por Descendents
Y creo que la penultima pregunta que hice lo de la linea milagrosa, es que no se le debe asignar el parent en el momento de la destrucción

Así es!

Cita:

Empezado por Descendents
como existen estos mensajes de windows

Justo los mensajes que has nombrado no son propios de Windows, utilizan el sistema de mensajes de Windows, pero son mensajes propios de la VCL.

Bueno... vemos como te has contestado solo, eso significa que primero es conveniente investigar un poco y luego preguntar, aclaro que no te estoy recriminando nada, bien sabes que siempre te he contestado de buena gana ;) , solo para que lo tengas en cuenta!

Saludos!

Descendents 16-01-2004 13:58:32

Estoy totalmente de acuerdo contigo y creo que haces muy bien en decirlo, pero a veces la desesperación en algo, hace cometer estos errores.

Muchas gracias.

marto 16-01-2004 14:13:03

Hola a todos,

Pues yo no entiendo por qué la "linea milagrosa" soluciona el problema. Traduciendo a pseudocódigo el de Delphi.com.ar ...

Código:

procedure Tedit2.MeAsignanElParent(AParent: TWinControl);
begin
  inherited;
  if not (me están destruyendo) then
    FBoton.Parent := AParent;
end;

Es decir, si me están destruyendo, no asignes mi parent al del botón. ¿Qué tenemos que deducir de eso? que cuando TForm destruye a los Componets les cambia la propiedad Parent (y por eso se dispara el método)?

Otra cosa que no entiendo es ¿por qué el form ha destruído al Button? El Button forma parte del array Controls no de Components, ¿TForm tambien se encarga de destruir a Controls?

Finalmente en lugar de conprobar que no se esté destruyendo el componente, no os parece más elegante comprobar que el boton esté "assigned"??

delphi.com.ar 16-01-2004 14:30:43

Cita:

Empezado por marto
Es decir, si me están destruyendo, no asignes mi parent al del botón.

Esa es la idea!


Cita:

Empezado por marto
¿Qué tenemos que deducir de eso? que cuando TForm destruye a los Componets les cambia la propiedad Parent (y por eso se dispara el método)?.

En el TControl.Destroy se asigna el Parent a Nil, esto produce que se dispare este método cuando se está destruyendo el componente, despues de hacer el FButton.Free según el código original.


Cita:

Empezado por marto
Otra cosa que no entiendo es ¿por qué el form ha destruído al Button?

En el destructor de los TWinControl se destruyen todos los componentes hijos, relacionados por el parent (Controls)


Cita:

Empezado por marto
Finalmente en lugar de conprobar que no se esté destruyendo el componente, no os parece más elegante comprobar que el boton esté "assigned"??

Bueno.. el código original completo lo había hecho con assigned, pero el problema es que el owner destruye antes a componente, y no lo deja apuntado a Nil (0)... entoces assigned siempre da True, aunque el botón ya no exista.


Saludos!


La franja horaria es GMT +2. Ahora son las 17:35:31.

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