Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Array de controles - Control has no parent window (https://www.clubdelphi.com/foros/showthread.php?t=39545)

SyncReuter 23-01-2007 19:05:25

Array de controles - Control has no parent window
 
Hola,

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

Código Delphi [-]
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:

Código Delphi [-]
inherited Create(AOwner);
SetBounds(0, 0, cMCW, cMCH);
CreateObjects;

Destroy:

Código Delphi [-]
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 :

Código Delphi [-]
  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.

Código Delphi [-]
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

Cita:

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í:
Código Delphi [-]
      with LabD[i] do
Con el "with" estas dando a entender que utilice LabD[i], así que en la asignación que hay a continuación:
Código Delphi [-]
          Parent:=Self;
en realidad lo que estás haciendo es
Código Delphi [-]
          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:

Código Delphi [-]
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:

Código Delphi [-]
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:
Código Delphi [-]

  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

Código Delphi [-]
Procedure CreateWnd; Override;

con el siguiente codigo:

Código Delphi [-]
procedure TPrcMonthCalendar.CreateWnd;
begin
  inherited;
  AjustWH;
  CreateObjects;
end;

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

Código Delphi [-]
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:

Código Delphi [-]
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!!!


La franja horaria es GMT +2. Ahora son las 10:24:08.

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