Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > Varios
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 20-12-2005
pelaorb68 pelaorb68 is offline
Miembro
 
Registrado: oct 2005
Posts: 32
Poder: 0
pelaorb68 Va por buen camino
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 //   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.......

Última edición por jachguate fecha: 20-12-2005 a las 00:21:53.
Responder Con Cita
  #2  
Antiguo 20-12-2005
Avatar de jachguate
jachguate jachguate is offline
Miembro
 
Registrado: may 2003
Ubicación: Guatemala
Posts: 6.254
Poder: 27
jachguate Va por buen camino
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.

__________________
Juan Antonio Castillo Hernández (jachguate)
Guía de Estilo | Etiqueta CODE | Búsca antes de preguntar | blog de jachguate
Responder Con Cita
  #3  
Antiguo 20-12-2005
Avatar de dec
dec dec is offline
Moderador
 
Registrado: dic 2004
Ubicación: Alcobendas, Madrid, España
Posts: 13.107
Poder: 34
dec Tiene un aura espectaculardec Tiene un aura espectacular
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.
__________________
David Esperalta
www.decsoftutils.com
Responder Con Cita
  #4  
Antiguo 20-12-2005
Avatar de Ohcan
[Ohcan] Ohcan is offline
Miembro Premium
 
Registrado: ago 2004
Ubicación: Madrid (España)
Posts: 119
Poder: 20
Ohcan Va por buen camino
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.
__________________
La violencia es el último recurso del incompetente. (Salvor Hardin)
Responder Con Cita
  #5  
Antiguo 20-12-2005
pelaorb68 pelaorb68 is offline
Miembro
 
Registrado: oct 2005
Posts: 32
Poder: 0
pelaorb68 Va por buen camino
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....
Responder Con Cita
  #6  
Antiguo 20-12-2005
pelaorb68 pelaorb68 is offline
Miembro
 
Registrado: oct 2005
Posts: 32
Poder: 0
pelaorb68 Va por buen camino
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;
Responder Con Cita
  #7  
Antiguo 20-12-2005
Avatar de Ohcan
[Ohcan] Ohcan is offline
Miembro Premium
 
Registrado: ago 2004
Ubicación: Madrid (España)
Posts: 119
Poder: 20
Ohcan Va por buen camino
Arrow 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...
__________________
La violencia es el último recurso del incompetente. (Salvor Hardin)
Responder Con Cita
  #8  
Antiguo 20-12-2005
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
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
Responder Con Cita
  #9  
Antiguo 20-12-2005
Avatar de Ohcan
[Ohcan] Ohcan is offline
Miembro Premium
 
Registrado: ago 2004
Ubicación: Madrid (España)
Posts: 119
Poder: 20
Ohcan Va por buen camino
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é
__________________
La violencia es el último recurso del incompetente. (Salvor Hardin)
Responder Con Cita
  #10  
Antiguo 20-12-2005
pelaorb68 pelaorb68 is offline
Miembro
 
Registrado: oct 2005
Posts: 32
Poder: 0
pelaorb68 Va por buen camino
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....
Responder Con Cita
  #11  
Antiguo 20-12-2005
pelaorb68 pelaorb68 is offline
Miembro
 
Registrado: oct 2005
Posts: 32
Poder: 0
pelaorb68 Va por buen camino
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......
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 11:00: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
Copyright 1996-2007 Club Delphi