Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Ayuda: Control Has No Parent Window (https://www.clubdelphi.com/foros/showthread.php?t=28435)

pelaorb68 20-12-2005 00:03:33

Ayuda: Control Has No Parent Window
 
Hola a todos, estoy incursionando en Delphi(7) y tengo el siguiente problema:
Estoy tratando de crearme un componente que hereda de TComboBox. La idea es poder utilizar todas las funcionalidades del Combo, pero además estoy creando unas funciones para poder agregar valores a la propieded Object de cada Item. Esto con el fin de rescatar estos valores(dependiendo del item seleccionado) y realizar algunas taras con ese valor.
De acuerdo al código que he hecho, esto funciona, pero cuando cierro el formulario que contiene mi control, se dispara el Destroy de mi componente y cuando trato de accesar los Items, la aplicación me arroja el mensaje '.....has no parent windows'.

Agragdeceré cualquier ayuda al respecto......

Este el código del control que estopy haciendo:
Código Delphi [-]
 
unit uRBComboBox;
 
interface
 
uses Classes, StdCtrls, SysUtils;
 
type
   TString = class(TObject)
   private
     FStr: String;
   public
     constructor Create ;
     property Str: String read FStr write FStr;
   end;
 
   TCustomComboIData = class(TComboBox)
   public
    constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
     function GetItemData(Indice: Integer): String;
     function NewItem(Cadena: String; Valor: String = ''): Integer;
   end;
 
   TRBComboBox = Class(TCustomComboIData);
 
procedure Register;
 
implementation
 
uses Windows;
var obj: TString;
 
procedure Register;
begin
 RegisterComponents('Samples', [TRBComboBox]);
end;

constructor TString.Create();
begin
  inherited Create;
end;
 
constructor TCustomComboIData.Create(AOwner: TComponent);
begin
  inherited;
end;
 
destructor TCustomComboIData.Destroy;
var i:integer;
begin
  for i:= 0 to Self.Items.Count-1 do // :confused:  Aquí lanza el Error.....
  begin
    TString(Items.Objects[i]).Free;
    Items.Objects[i]:= nil;
  end;
  inherited Destroy;
end;

function TCustomComboIData.NewItem(Cadena: String; Valor: String = ''): Integer;
begin
  Result := Items.Add(Cadena);
  obj := TString.Create;
  obj.Str := Valor;
  Items.Objects[Result] := obj;
end;
 
function TCustomComboIData.GetItemData(Indice: Integer): String;
begin
  Result := TString(Items.Objects[Indice]).Str;
end;
 
end.
Gracias.......

jachguate 20-12-2005 00:24:39

Hola pelaorb68, bienvenido(a) al ClubDelphi.

He editado tu mensaje para añadir la etiqueta [delphi]. Su uso es obligatorio aqui para publicar fragmentos de código, y estarás de acuerdo conmigo que la presentación del mismo ahora es mucho mas legible que en la versión original del mensaje.

Te invito a leer la guia de estilo y la ayuda sobre el uso de estas etiquetas (vínculos en mi firma).

Hasta luego.

;)

dec 20-12-2005 11:02:02

Hola,

Tal vez podrías valerte del método protegido "Notification", que "TComboBox" hereda de "TComponent". Sobreescribe este método en tu componente y estáte atento a sus parámetros: entre otras cosas, mediante este método, se avisará a tu componente de que va a ser "removido": es ahí acaso donde tienes que hacer lo que te sea preciso, mejor que en "Destroy".

Adéntrate un tanto en la ayuda de "TComponent" y su método "Notificacion". De todos modos deja que te diga que no estoy muy puesto en todo esto: un vistazo a los métodos que "TComponent", "TWinControl", "TControl", "TObject"... en definitiva, no olvidar la jerarquía de clases: darte cuenta de que puedes aprovecharte de métodos y propiedades que se implementan en clases de las que, directa o indirectamente, hereda tu componente.

Lamentaría mucho que te hubiera confundido más que otra cosa. ;)

Ohcan 20-12-2005 11:24:03

Hola pelaorb68

Creo que, para solucionar el error de 'Control Has No Parent Window', basataría con esto:
Código Delphi [-]
constructor TCustomComboIData.Create(AOwner: TComponent);
begin
  inherited;
  ParentWindow := AOwner; //<-- o tú ventana principal....
end;

destructor TCustomComboIData.Destroy;
var i:integer;
begin
  for Self.Items.Count-1 downto 0 do // <-- hacerlo al revés
  begin
    TString(Items.Objects[i]).Free;
    Items.Objects[i]:= nil;
  end;
  inherited Destroy;
end;
Espero que te sirva... y ¡bienvenido!

Saludos.

pelaorb68 20-12-2005 15:31:36

Ohchan, gracias por tu respuesta pero cuando asigno AOwner a ParentWindow, al compilar me arroja el mensaje: Incompatible Types: 'HWND' and 'TComponent'.
Estoy leyendo la ayuda de Delphi para entender la propiedad ParentWindow....

pelaorb68 20-12-2005 15:53:21

Dec, gracias por tu ayuda. Agregué el método Notification. Ahora, puse en un formulario, solamente el Combo. Cuando cierro el formulario, se dispara el 'Notification', en él logro detectar que es opRemove, pero no sé como evaluar que componente(AComponent) es el que viene indicado en sus parámetros, ya que la primera vez que entra AComponent no es del tipo TRBComboBox. La segunda vez que entra si lo es, pero me arroja error al querer evaluar los Items.

El procedimiento es el sgte:

Código Delphi [-]
procedure TCustomComboIData.Notification(AComponent: TComponent; Operation: TOperation);
var i:integer;
begin
  if Operation = opRemove then
     if (AComponent is TRBComboBox) then  //Esto lo hace la segunda vez que entra, 
                                                         // pero la primera vez no sé que 
                                                        // componente está destruyendo
     begin
        for i:= Self.Items.Count-1 downto 0 do // Aquí produce Access Violation at
                                                            // address 00BD26FF. Write of address 
                                                            // 3A7A0F12, una vez que entró la
                                                           //  segunda vez.
        begin
           TString(Items.Objects[i]).Free;
           Items.Objects[i]:= nil;
        end
     end;

end;

Ohcan 20-12-2005 18:11:44

Un ejemplo significado
 
Bueno... me he creado un ejemplo simplificando:
Código Delphi [-]
unit Unit2;

interface
 
uses Classes, StdCtrls, SysUtils, Dialogs;
 
type
  TMiCombo = class(TComboBox)
    FItems:TStringList; 
  published
    property Items:TStringList read FItems;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{ TMiCombo }

constructor TMiCombo.Create(AOwner: TComponent);
begin
  inherited;
  FItems := TStringList.Create;
end;

destructor TMiCombo.Destroy;
var
  i:integer;
begin
  if FItems<>nil then
  for i:= 0 to Self.Items.Count-1 do
    begin
      Items.Objects[i].Free; 
      Items.Objects[i] := nil;
    end;
  inherited Destroy;
end;

end.
Y cuando creo el objeto:
Código Delphi [-]
MiCombo := TMiCombo.Create(Self);
MiCombo.Parent := Self;
Si quito lo que está marcado en rojo... me da el mismo error que en tu código...
Espero que te sirva de pista ;)
Ya nos contarás...

roman 20-12-2005 18:17:45

Pero tú estás creando un objeto TStrings distinto.

Buscando en los foros de Borland veo que el problema al parecer radica en que los strings de un combobox realmente pertenecen al sistema y para cuando se llama a Destroy, estos items ya no existen. Al no existir, el control intenta crearlos de nuevo, lo cual ya no puede hacer porque el Handle del combo ya no existe.

Vi una solución que al parecer funciona pero habrá que probarla más a fondo. Consiste en definir un manejador para el mensaje WMDestroy y liberar ahí los objetos:


Código Delphi [-]
type
  TCustomComboIData = class(TComboBox)
  private
    procedure WMDestroy(var Msg: TWMDestroy); message WM_DESTROY;
  end;

implementation

procedure TCustomComboIData.WMDestroy(var Msg: TWMDestroy);
begin
  {
    Liberar aquí los objetos
  }

  inherited;
end;

// Saludos

Ohcan 20-12-2005 18:22:05

Cita:

Empezado por roman
[...]strings de un combobox realmente pertenecen al sistema y para cuando se llama a Destroy, estos items ya no existen[...]

Gracias Roman...
Al recorrer paso a paso depurando me encontraba que Items estaba vacío (en el Destroy)... ahora sabemos porqué :)

pelaorb68 20-12-2005 19:34:33

Roman, gracias por tu respuesta, se ve genial la solución, pero te comento que estoy hace poco incursionando en Delphi, por lo tanto, no sé cómo puedo implementar tu ayuda..?????

De todas formas, mil gracias....

pelaorb68 20-12-2005 20:36:26

Roman, he revisado nuevamente el código que pusiste y me he dado cuenta que me faltó incluir la Unit Messages en el Uses. He compilado y funciona perfectamente, es decir, libera los objetos de todos los controles(RBCombobox) que posea el formulario.

Mil Gracias a ti y a todos los que respondieron a mis dudas......


La franja horaria es GMT +2. Ahora son las 13:43: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