PDA

Ver la Versión Completa : Array de controles - Control has no parent window


SyncReuter
23-01-2007, 19:05:25
Hola,

Alguien sabe cual es la forma correcta de definir un array de controles. Algo asi como:

LabD: array[1..8] of TLabel

Esa definición esta presente en protected de una clase X que deriva de TPanel. Ahora bien, en Create y Destroy tengo el siguiente codigo:

Create:

inherited Create(AOwner);
SetBounds(0, 0, cMCW, cMCH);
CreateObjects;

Destroy:

RemoveObjects;
inherited Destroy;

como podran notar en Create llamo a un procedimiento CreateObject que se encuentra declarado en Private dentro de la clase. El unico objectivo es crear los controles adiciones, que en este caso en particular son 8 etiquetas (TLabel). El codigo es el siguiente :


x:=5;
y:=21;
for i:=1 to 8 do
begin
LabD[i]:=TLabel.Create(Self);
with LabD[i] do
begin
Parent:=Self;
AutoSize:=True;
Caption:=CA_D[i];
Alignment:=taCenter;
Transparent:=True;
ParentFont:=True;
Width:=21;
Height:=13;
Top:=y;
Left:=x;
Inc(x, Width + 2);
end;
end;

En Destroy llamo a otro procedimiento RemoveObjects declarado tambien el Private que lo unico que hace es destruir los objectos que han sido creados.

var
i: Integer;
begin
for i:=8 downto 1 do
begin
LabD[i].Free;
LabD[i]:=nil;
end;
end;

Ahora bien...Cual es mi problema. Cuando intento pegar el componente dentro de la Form, delphito me lanza un cuadro de dialogo con lo siguiente :

Control has no parent window :eek:

El objetivo de usar array es unicamente para poder tratarlos por lotes los controles TLabel.

¿Alguien sabe a que se debe este problema?

Saludos desde Chile.
:)

Lepe
23-01-2007, 19:15:58
en protected de una clase X que deriva de TPanel.

Quizás el que no tiene Aowner es el propio panel en lugar de los labels...

Para el uso de controles... un TobjectList sería más cómodo.

Saludos.

Ñuño Martínez
23-01-2007, 19:49:02
Creo que el problema está en el procedimiento CreateObject, concretamente aquí:
with LabD[i] doCon el "with" estas dando a entender que utilice LabD[i], así que en la asignación que hay a continuación:
Parent:=Self; en realidad lo que estás haciendo es
LabD[i].Parent := LabD[i].Self;O puede que no, no lo he comprobado, pero es lo que se me ha ocurrido.

De todas formas, la sugerencia de utilizar un TObjectList es buena.

SyncReuter
23-01-2007, 20:22:50
Hola, bueno realice el cambio en el codigo para probar, las lineas me quedaron asi:

x:=5;
y:=21;
for i:=1 to 7 do
begin
LabD[i]:=TLabel.Create(Self);
LabD[i].Parent:=Self;
LabD[i].AutoSize:=True;
LabD[i].Caption:=CA_D[i];
LabD[i].Alignment:=taCenter;
LabD[i].Transparent:=True;
LabD[i].ParentFont:=True;
LabD[i].Width:=21;
LabD[i].Height:=13;
LabD[i].Top:=y;
LabD[i].Left:=x;
x:=x + LabD[i].Width + 2;
end;

Lo compile y lo volvi a colocar dentro de la Form obteniendo el mismo resultado "Control has no parent window" :eek:. Tengo que decir ademas, que tengo 4 botones definidos en un array cuya creacion no da problemas. con el codigo:

x:=3;
for i:=1 to 4 do
begin
BtnNave[i]:=TPrcBtnNave.Create(Self);
with BtnNave[i] do
begin
Parent:=Self;
Width:=15;
Height:=15;
Top:=3;
//with ArrowOptions do
begin
case i of
1: begin
Left:=x;
inc(x, Width + 1);
BtnNaveType:=bntPYear;
end;
2: begin
Left:=x;
x:=cMCW - Width - 3;
BtnNaveType:=bntPMonth;
end;
3: begin
Left:=x;
Dec(x, Width + 1);
BtnNaveType:=bntNYear
end;
4: begin
Left:=x;
BtnNaveType:=bntNMonth;
end;
end;
//PosArrow:=paCenter;
//ShowArrow:=True;
end;

Tag:=i;
OnClick:=BtnNaveClick;
end;
end;

me tiene loco este maldito problema.:mad: Ya llevo mas de 5 horas cascandome la cabeza, la clase la hago una y otra vez obteniendo el mismo resultado.

Estoy usando Delphi 2005 Professional con el Update3

A todo esto de que forma trabaja TObjectList?

Gracias por su tiempo, saludos

roman
23-01-2007, 22:47:05
Yo creo que hay algo de código que no nos pones y que es el causante del error.

Ahora bien, ya te han dicho que posiblemente quien se queja de no tener padre sea el panel y no las etiquetas. Puedes salir de dudas asignando la propiedad Name, tanto del panel como de las etiquetas y demás controles que crees, al principio del constructor, inmediatamente después de inherited. De esa forma, el mensaje de error dirá el nombre de la componente que da el problema.

Por otra parte puedes hacer una depuración del código de tu componente. Intenta primero crear una componente en tiempo de ejecución y mira si te da el mismo error; así sabrás exactamente en qué línea se produce.

Si eso no da resultado entonces el error sólo se produce en tiempo de diseño, lo cual hace un poco más difícil la depuración, pero puede hacerse.



Ahora, cambiando un poco de tema. Self no es una propiedad, sino un parámetro (escondido) que se pasa a cualquier método de un objeto, de manera que lo que se indica del with, no aplica. Self siempre será el objeto al que pertenece el método.

Finalmente, si el número de etiquetas es fijo, yo no me complicaría usando un TObjectList; te hará más difícil la escritura al tener que hacer moldeos de tipo para ajustar las propiedades de sus elementos.

// Saludos

basti
23-01-2007, 23:07:48
Como bien te dijeron antes, el problema es que el panel no tiene Owner en el constructor.

Lo que puedes hacer es quitar la creación de etiquetas del Create.

Luego sobreescribes el método Loaded:


protected:
procedure Loaded; override;

.
.
.
procedure TControlNuevo.Loaded;
begin
CreateObjects;
end;


Loaded se ejecuta cuando el componente ya está creado e insertado en el Form, así ya tiene Owner.

roman
23-01-2007, 23:12:42
Yo no estaría tan seguro de que ese sea el problema, pues yo hice la prueba y no pude reproducir el error. Pero por otra parte, el error se produce cuando se hace una operación que requiere que la ventana del padre ya esté creada. Por ello el método más adecuado sería CreateWnd y no Loaded.

// Saludos

SyncReuter
24-01-2007, 01:18:35
Hola nuevamente,

Gracias por responder tan pronto, les cuento lo siguiente: De lo que realmente estamos seguro aca es que el error sale unicamente en tiempo de diseño. Por que? El componente que estoy creando se llama TPrcMonthCalendar y tengo otro componente que se llama TPrcDateEdit que es un TEdit con un boton insertado en el interior del control. Cuando el usuario hace clic en el botón la clase PrcMonthCalendar se visualiza sin problemas. El drama esta unicamente al momento de insertar el calendario dentro de la Form. ¿Se entiende?

Hare las pruebas pertinente con CreateWnd y Loaded. Es importante señalar que el drama es unicamente con los componentes TLabel NO asi con los botones de navegacion (PriorMonth, PriorYear.....etc) y los botones de control del calendario (BtnOK, BtnCancel) y por supuesto los botones correspondientes a los dias del mes.

Ahora me pondre manos a la obra y colocar la llamada CreateObjects en CreateWnd o Loaded.

Muchas gracias por su tiempo, saludos

SyncReuter
24-01-2007, 02:21:14
Bueno aqui estamos de nuevo. Les cuesto. Agrege el siguiente procedimiento a la clase en la sección protected

Procedure CreateWnd; Override;

con el siguiente codigo:

procedure TPrcMonthCalendar.CreateWnd;
begin
inherited;
AjustWH;
CreateObjects;
end;

...Las etiquetas se crearon de la siguiente forma:

x:=5;
y:=21;

for i:=1 to 7 do
begin
FLabD[i]:=TLabel.Create(Self);
with FLabD[i] do
begin
Name:='Lab'+IntToStr(i);
FLabD[i].Parent:=Self;
Caption:=CA_D[i];
AutoSize:=True;
Alignment:=taCenter;
Transparent:=True;
Left:=x;
Top:=y;
Width:=21;
Height:=13;
inc(x, Width + 2);
end;
end;


Ahora todo funciona a la perfección ;). Para terminar debo señalar lo siguiente. Al momento de alterar las propiedades de las etiquetas y botones internos del componente se producia un error grave en delphi, observando la clase completamente me doy cuenta que tenia un procedimiento dentro de Paint que alteraba las propiedades de las etiquetas y botones la cual es necesario para el cambio de estilo del calendario, entonces...para alterar las propiedades (utilizando For... para recorrer el array) coloque una bifurcación if..then preguntando si el elemento contenido en el array era <> a nil... como lo indico en la fracción de codigo:

for i:=1 to 42 do
if FBtnD[i]<>nil then
with FBtnD[i] do
begin
GetBtnStateData(TD_MONTHCALENDAR_DM_NORMAL_BSTATE, StateNormal);
GetBtnStateData(TD_MONTHCALENDAR_DM_FOCUS_BSTATE, StateFocus);
GetBtnStateData(TD_MONTHCALENDAR_DM_DISABLED_BSTATE, StateDisabled);
GetBtnStateData(TD_MONTHCALENDAR_DM_DOWN_BSTATE, StateDown);
end;


...con ello ahora el control se puede colocar dentro de la form sin causar problema alguno...al = que al momento de quitarlo. ;)

La destrucción de los controles internos se genero justo antes de ejecutar el inherited Destroy;

;)

Bueno no me queda mas que AGRADECER a cada uno de ustedes por sus lineas. Desde Chile reciban un gran abrazo.

GRACIAS!!!