Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
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-01-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Sobrecargando destructor

Hola a todos,

Estoy creando un componente muy sencillo que hereda de TComboBox. El tema es que necesito que los punteros Objects de su propiedad items apunten a ciertos objetos de una clase. Para lo que hayan leido el hilo sobre "propiedades de clases" , se trata de cargarlo con las listas que allí describo. Bien, en caso de que así se indique, el componente se ha de encargar de liberar estos objetos. Esto lo intento con el siguiente código:
Código:
procedure Destroy; override;
....
destructor TNxAuxCombo.Destroy;
var
  i: Integer;
begin
  if FOwnObjects then
    for i := 0 to Count - 1 do
      if Items.Objects[i] <> Nil then
         Items.Objects[i].Free;
  inherited;
end;
Tengo dos problemas. En primer lugar, al ejecutarse el destructor, Items vale nil, de manera que se produce una excepción. No entiendo cómo puede pasar eso, ya que Items, si no recuerdo mal (no tego aqui el Delphi) se detruye en el destructor de TListControl.
En segundo lugar, si creo el combo en diseño, al destruirse el form me lanza una excepción de "Control xxxx has no parent window". Si depuro el código, efectivamente en mi destructor Parent = nil. Eso me parece muy bien, pero ¿Por que está accediendo al parent?
A ver si tenéis alguna idea y me echáis una mano.

Ah! os pongo el código del constructor por si os da más pistas:
Código:
constructor Create(AOwner: TComponent); override;
....
constructor TNxAuxCombo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FOwnObjects := true;
  Style := csDropDownList;

end;
__________________
E pur si muove
Responder Con Cita
  #2  
Antiguo 23-01-2004
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¡Buen día a todos!


Cita:
Empezado por marto
...creando un componente muy sencillo que hereda de TComboBox. El tema es que necesito que los punteros Objects de su propiedad items apunten a ciertos objetos de una clase...en caso de que así se indique, el componente se ha de encargar de liberar estos objetos...
Código:
procedure Destroy; override;
....
destructor TNxAuxCombo.Destroy;
var
  i: Integer;
begin
  if FOwnObjects then
    for i := 0 to Count - 1 do
      if Items.Objects[ I ] <> Nil then
         Items.Objects[ I ].Free;
  inherited;
end;
...al ejecutarse el destructor, Items vale nil, de manera que se produce una excepción...
Quizás el destructor heredado está siendo ejecutado antes de tiempo.


Cita:
Empezado por marto
...Items, si no recuerdo mal...se detruye en el destructor de TListControl...
En realidad es TCustomComboBox, la clase padre de TComboBox (Delphi 6), quien normalmente instancía y destruye la propiedad Items. Quizás estás destruyendo esa propiedad en otro lugar o modificaste su método de lectura.


Cita:
Empezado por marto
...si creo el combo en diseño, al destruirse el form me lanza una excepción de "Control xxxx has no parent window"...efectivamente en mi destructor Parent = nil...¿Por que está accediendo al parent?...
Pudiera ser que algún evento esté disparando una llamada al método SetFocus del control, lo cual causa la excepción mencionada si éste no tiene contenedor padre. Pero existen muchas otras situaciones donde se eleva una excepción con el mensaje SParentRequired, no obstante todas tienen que ver con la necesidad del control de tener un padre para desempeñar cierta función visual o de cálculo de coordenadas.


Por último debo agregar que el término sobrecarga se aplica más bien a los casos donde el compilador determina cuál de dos rutinas es a la que se refiere una expresión de código, cuando dichas rutinas tienen el mismo nombre y utilizan la directiva Overload. En este caso, se trata más bien de una redefinición (Override) de un método virtual (el destructor Destroy).

De cualquier forma te agradecería que detallaras un poco más este caso.

Para la administración del foro: Tuve que alterar un poco el código de Marto que cité arriba. Agregué dos espacios a los lados de la variable "I" que aparece entre corchetes, porque como estaba (sin espacios) afectaba el texto que escribí en cursiva más adelante. Ojalá se haga la corrección pertinente. Muchas gracias.

Espero esto sea de utilidad. Seguimos en contacto.

Al González .
Responder Con Cita
  #3  
Antiguo 23-01-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Cita:
Empezado por Al González
Quizás el destructor heredado está siendo ejecutado antes de tiempo.
No lo sé, pero como podrás ver en el código al final, yo no lo llamo (por lo menos intencionadamente)

Cita:
Empezado por Al González
En realidad es TCustomComboBox, la clase padre de TComboBox (Delphi 6), quien normalmente instancía y destruye la propiedad Items.
Correcto, error mío

Cita:
Empezado por Al González
Quizás estás destruyendo esa propiedad en otro lugar o modificaste su método de lectura.
El método de lectura no se módifica e Items no se destruye

Cita:
Empezado por Al González
Pudiera ser que algún evento esté disparando una llamada al método SetFocus del control, lo cual causa la excepción mencionada si éste no tiene contenedor padre.
No le programo ningún evento, tansolo lo instancio y ejecuto

Cita:
Empezado por Al González
Por último debo agregar que el término sobrecarga se aplica más bien a los casos donde el compilador determina....
Buena correccíon, se me cruzaron los conceptos

Cita:
Empezado por Al González
De cualquier forma te agradecería que detallaras un poco más este caso.
Ok, te paso el código del componente, no es nada secreto y es muyyyyy sencillo:
Código:
unit NxAuxCombo;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, 
  StdCtrls, NxAuxiliar, Dialogs;

type
  TNxAuxCombo = class(TComboBox)
  private
    FOwnObjects: Boolean;
    function GetSelectedObject: TNxAuxiliar;
    procedure SetOwnObjects(const Value: Boolean);
  protected
  public
    property SelectedObject: TNxAuxiliar 
    				read GetSelectedObject;
    property OwnObjects: Boolean 
    				read FOwnObjects 
    				write SetOwnObjects;

    procedure Carrega(List: TStringList);
    procedure Clear; override;

    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Nex', [TNxAuxCombo]);
end;

{ TNxAuxCombo }

procedure TNxAuxCombo.Carrega(List: TStringList);
var
  i: Integer;
begin
  for i := 0 to List.Count -1 do
    Items.AddObject(List[i], List.Objects[i]);
end;


procedure TNxAuxCombo.Clear;
var
  i: Integer;
begin
  if FOwnObjects then
  begin
    for i := 0 to Items.Count - 1 do
      if Items.Objects[i] <> Nil then
        try Items.Objects[i].Free; except end;
  end;
  inherited;
end;

constructor TNxAuxCombo.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FOwnObjects := true;
  Style := csDropDownList;

end;

destructor TNxAuxCombo.Destroy;
var
  i: Integer;
begin
  if FOwnObjects then
  begin
    for i := 0 to Items.Count - 1 do
      if Items.Objects[i] <> Nil then
        try Items.Objects[i].Free; except end;
  end;

  inherited;
end;

function TNxAuxCombo.GetSelectedObject: TNxAuxiliar;
begin
  if Items.Objects[ItemIndex] is TNxAuxiliar then 
    Result := TNxAuxiliar(Items.Objects[ItemIndex])
  else Result := Nil;
end;

procedure TNxAuxCombo.SetOwnObjects(const Value: Boolean);
begin
  FOwnObjects := Value;
end;

end.
__________________
E pur si muove

Última edición por marto fecha: 23-01-2004 a las 20:51:32.
Responder Con Cita
  #4  
Antiguo 23-01-2004
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¡Buen día a todos!


Cita:
Empezado por marto
...al ejecutarse el destructor, Items vale nil, de manera que se produce una excepción
Tengo un par de dudas: ¿cómo determinas que Items realmente tiene un valor de Nil, y cuál es exactamente la excepción que se produce?

Quizás la propiedad Items es válida, pero no así uno de sus objetos Items.Objects [ I ]. Esto podría deberse a una ejecución previa del método Clear, o a la destrucción previa de otro objeto TNxAuxCombo que comparta la misma lista de objetos. Considera que la sentencia
Código:
Items.Objects [ I ].Free;
destruye el objeto Items.Objects [ I ], pero no hace que dicha expresión se convierta en Nil (el puntero al objeto sigue siendo el mismo después de llamar a Free). No se si por ello habrás agregado un bloque de protección Try..Except:
Código:
try Items.Objects[i].Free; except end;
Estaré al tanto de este caso.

Una última cosa: ¿Serías tan amable de reducir las muestras de código a máximo 60 columnas por línea, para que el mensaje no se ensanche tanto?. Muchas gracias.

Al González .

Última edición por Al González fecha: 23-01-2004 a las 19:42:40. Razón: aclarar mensaje
Responder Con Cita
  #5  
Antiguo 23-01-2004
Avatar de marto
marto marto is offline
Miembro
 
Registrado: may 2003
Ubicación: Barcelona, Catalunya
Posts: 882
Poder: 22
marto Va por buen camino
Cita:
Empezado por Al González
¿cómo determinas que Items realmente tiene un valor de Nil, y cuál es exactamente la excepción que se produce?
Determino que vale nil haciendo un debug.... vale nil.
La excepcion es la que da siempre que intentas acceder a una propiedad de una referencia a nil.... Acces Violation

Cita:
Empezado por Al González
Quizás la propiedad Items es válida, pero no así uno de sus objetos Items.Objects [ I ].
Items apunta a nil, como te digo arriba, y nada ha destruido ninguno de los objetos. Lo unico que hago es crearlos, cargarlos, y destruir el form.

Cita:
Empezado por Al González
Esto podría deberse a una ejecución previa del método Clear, o a la destrucción previa de otro objeto TNxAuxCombo que comparta la misma lista de objetos.
Correcto. De hecho, he de reconocer que, que sea el combo quien se encarga de destruir los objetos, no es demasiado seguro. Lo que sucede es que es un componente "para mi" y que su única misión es evitarme repetir código

Cita:
Empezado por Al González
No se si por ello habrás agregado un bloque de protección Try..Except:
No, el bloque lo añadí por probar cosas cuando ya no se me ocurría nada pero no tiene ningún sentido

Cita:
Empezado por Al González
¿Serías tan amable de reducir las muestras de código a máximo 60 columnas por línea, para que el mensaje no se ensanche tanto?.
Perdón, perdón, pero es que a mi resolución se ve de una tirada

Al González .[/quote]
__________________
E pur si muove
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 12:29:32.


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