Конференция "Компоненты" » Control has no parent window в наследнике TCustomListBox [D7, WinXP]
 
  • Elio (05.11.07 20:08) [0]
    Начал писать компонент наследник TCustomListBox'а и сразу же столкнулся с ошибкой: в деструкторе выполняю очистку всех объектов содержащихся в Objects:

    destructor TImgListBox.Destroy;
    begin
     while Items.Count > 0 do
     begin
       Items.Objects[0].Free;
       Items.Delete(0);
     end;
     inherited;
    end;


    при первом же обращении к Items вылетает "Control has no parent window". Как решить?
  • Юрий Зотов © (05.11.07 20:17) [1]
    Реализация Item'ов в ListBox сделана "родными" средствами Windows, через посылку сообщений окну. А в момент выполнения деструктора окно уже уничтожено - видимо, в этом и причина. Перенесите код уничтожения объектов в DestroyWindow, например.
  • Elio (05.11.07 20:39) [2]
    Не достаточно хорошо знаком с "родными" средствами Windows. Заменил
    destructor Destroy(); override;


    на
    procedure DestroyWnd(); override;


    но управление ей не передаётся при закрытии окна.
  • Юрий Зотов © (05.11.07 21:13) [3]
    Сорри, был невнимателен, спутал ListBox и ListView. А StdCtrl и ComCtrls реализованы в VCL несколько по-разному.

    Если все у Вас сделано правильно, то ошибки быть не должно. Приводите весь код, буде разбираться вместе.
  • Elio (05.11.07 21:18) [4]

    type
     TImgListBox = class(TCustomListBox)
     private
       { Private declarations }
     protected
       { Protected declarations }
     public
       constructor Create(AOwner: TComponent); override;
       destructor Destroy(); override;

       procedure Add(Text, ImgFileName: string);
       procedure Delete(Text: string);

     published
       { Published declarations }
     end;

    procedure Register;

    implementation

    procedure Register;
    begin
     RegisterComponents('Custom', [TImgListBox]);
    end;

    { TImgListBox }

    procedure TImgListBox.Add(Text, ImgFileName: string);
    var
     Bmp: TBitmap;
    begin
     Bmp := TBitmap.Create;
     try
       Bmp.LoadFromFile(ImgFileName);
       Items.AddObject(Text, Bmp);
     except
       FreeAndNil(Bmp);
       raise;
     end;
    end;

    procedure TImgListBox.Delete(Text: string);
    var
     Index: Integer;
    begin
     Index := Items.IndexOf(Text);
     Items.Objects[Index].Free;
     Items.Delete(Index);
    end;

    constructor TImgListBox.Create(AOwner: TComponent);
    begin
     inherited Create(AOwner);
     Style := lbOwnerDrawFixed;
    end;

    destructor TImgListBox.Destroy;
    begin
     while Items.Count > 0 do
     begin
       Items.Objects[0].Free;
       Items.Delete(0);
     end;
     inherited;
    end;

  • MBo © (06.11.07 08:47) [5]

    type
    TImgListBox = class(TCustomListBox)
    private
      { Private declarations }
    protected
      { Protected declarations }
      procedure DestroyWindowHandle; override;
    public
      constructor Create(AOwner: TComponent); override;
      procedure Add(Text, ImgFileName: string);
      procedure Delete(Text: string);
    //Destroy не нужен

    ...
    procedure TImgListBox.Delete(Text: string);
    var
    Index: Integer;
    begin
    Index := Items.IndexOf(Text);
    if Index >= 0 then begin
      Items.Objects[Index].Free;
      Items.Delete(Index);
    end;// else стоит обработать эту ситуацию
    end;

    procedure TImgListBox.DestroyWindowHandle;
    var
     i: Integer;
    begin
     for i := Items.Count -1 downto 0 do
       Items.Objects[i].Free;//строковый массив освободится сам
     inherited;
    end;


  • DimaBr © (06.11.07 09:24) [6]

    TImgListBox = class(TCustomListBox)
    private
      procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY;
    ......

    procedure TImgListBox.WMNCDestroy(var Message: TWMNCDestroy);
    begin
    while Items.Count > 0 do begin
      Items.Objects[0].Free;
      Items.Delete(0);
    end;
    inherited;
    end;

  • DimaBr © (06.11.07 09:48) [7]

    > MBo ©   (06.11.07 08:47) [5]

    В DestroyWindowHandle он даже не заходит
  • MBo © (06.11.07 11:32) [8]
    >В DestroyWindowHandle он даже не заходит
    хм.. Действительно.
    При уничтожении родителем не заходит, а при ручном освобождении, которое я использовал при проверке  - заходит ;)
  • DimaBr © (06.11.07 11:44) [9]
    Интересно, чем это можно объяснить ???
  • reonid © (06.11.07 14:14) [10]
    Брейкройнт на USER32.DestroyWindow показывает, что
    при уничтожении панели с несколькими винконтролами на ней
    DestroyWindow вызывается только один раз.
    Похоже, изнутри она уничтожает все дочерние окна,
    причем рекурсивно себя не вызывая.
    До дочерних окон доходят только
    WM_DESTROY и WM_NCDESTROY (в котором обнуляется FHandle),
    и никакие VCLные методы уничтожения хэндла не вызываются.
  • Elio (06.11.07 20:51) [11]
    Огромное всем спасибо. Работает. Ну а чтоб в будущем не обращаться с подобными вопросами посоветуйте плиз литературу. Интересуют именно внутренние механизмы работы vcl.
  • Юрий Зотов © (06.11.07 21:40) [12]
    > Elio   (06.11.07 20:51) [11]

    http://pda.delphimaster.net/?id=1194173504&n=12
  • имя (19.12.08 18:12) [13]
    Удалено модератором
 
Конференция "Компоненты" » Control has no parent window в наследнике TCustomListBox [D7, WinXP]
Есть новые Нет новых   [134464   +62][b:0][p:0.002]