-
Начал писать компонент наследник 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". Как решить?
-
Реализация Item'ов в ListBox сделана "родными" средствами Windows, через посылку сообщений окну. А в момент выполнения деструктора окно уже уничтожено - видимо, в этом и причина. Перенесите код уничтожения объектов в DestroyWindow, например.
-
Не достаточно хорошо знаком с "родными" средствами Windows. Заменил destructor Destroy(); override; на procedure DestroyWnd(); override; но управление ей не передаётся при закрытии окна.
-
Сорри, был невнимателен, спутал ListBox и ListView. А StdCtrl и ComCtrls реализованы в VCL несколько по-разному.
Если все у Вас сделано правильно, то ошибки быть не должно. Приводите весь код, буде разбираться вместе.
-
type
TImgListBox = class(TCustomListBox)
private
protected
public
constructor Create(AOwner: TComponent); override;
destructor Destroy(); override;
procedure Add(Text, ImgFileName: string);
procedure Delete(Text: string);
published
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Custom', [TImgListBox]);
end;
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;
-
type
TImgListBox = class(TCustomListBox)
private
protected
procedure DestroyWindowHandle; override;
public
constructor Create(AOwner: TComponent); override;
procedure Add(Text, ImgFileName: string);
procedure Delete(Text: string);
...
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; end;
procedure TImgListBox.DestroyWindowHandle;
var
i: Integer;
begin
for i := Items.Count -1 downto 0 do
Items.Objects[i].Free; inherited;
end;
-
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;
-
> MBo © (06.11.07 08:47) [5]
В DestroyWindowHandle он даже не заходит
-
>В DestroyWindowHandle он даже не заходит хм.. Действительно. При уничтожении родителем не заходит, а при ручном освобождении, которое я использовал при проверке - заходит ;)
-
Интересно, чем это можно объяснить ???
-
Брейкройнт на USER32.DestroyWindow показывает, что при уничтожении панели с несколькими винконтролами на ней DestroyWindow вызывается только один раз. Похоже, изнутри она уничтожает все дочерние окна, причем рекурсивно себя не вызывая. До дочерних окон доходят только WM_DESTROY и WM_NCDESTROY (в котором обнуляется FHandle), и никакие VCLные методы уничтожения хэндла не вызываются.
-
Огромное всем спасибо. Работает. Ну а чтоб в будущем не обращаться с подобными вопросами посоветуйте плиз литературу. Интересуют именно внутренние механизмы работы vcl.
-
-
Удалено модератором
|