Добавление окна без VCL в очередь выравнивания VCL - PullRequest
9 голосов
/ 11 ноября 2011

Некоторый фон ( вид продолжения Мерцания надписей TLabel и TGroupbox при изменении размера ):

  • Итак, у меня есть приложение, которое загружает различные плагины и создает Новая вкладка в TPageControl для каждого.
  • С каждой DLL связана TForm.
  • Формы создаются с их родительским hWnd как новый TTabSheet. Поскольку TTabSheets не является родителем формы, насколько VCL ( не хотел использовать динамический RTL, а плагины сделаны в другие языки ) Я должен обрабатывать изменения размера вручную.

Мне кажется, что я сталкиваюсь с множеством новых проблем (, но с большим опытом обучения ) для этого типа "плагина".

Итак, в настоящее время я пытаюсь создать плагин, который не будет вставлен в TTabSheet, но будет изменен в размерах и выровнен непосредственно в форме.

Так как это было бы легче объяснить с помощью картинки: Visual representation of question Теперь я мог бы вручную выполнить выравнивание и изменение размера, но я бы предпочел, чтобы процедуры выравнивания VCL ( alClient, alTop и т. Д. ) делали это для меня. Таким образом, мне просто нужно было бы настроить выравнивание плагинов на его форму, не задумываясь.

После просмотра источника VCL я начал шагать по коду выравнивания и как он называется. Обычно, когда TControl получает WM_RESIZE, он будет:

  1. Вызов Realign (), который вызывает AlignControl ()
  2. AlignControl () получит прямоугольник клиента и вызовет AlignControls ()
  3. AlignControls () будет вызывать DoAlign () для каждого типа TAlignment в следующем порядке: alTop, alBottom, alLeft, alRight, alClient, alCustom, alNone
  4. DoAlign () будет перебирать FControls и FWinControls (, которые являются TLists ) и выравнивать их соответствующим образом

Итак, мой мыслительный процесс заключается в том, что если я создам новый TWinControl, установите его дескриптор на дескриптор формы плагинов ( window ) и вставьте его в список FControls с соответствующим выравниванием, это должно сделать мою работу для меня.

Конечно, я здесь, поэтому он с треском провалился. Я даже получаю AV при выходе из приложения о недопустимом дескрипторе окна. Я предполагаю, что созданный мной TWinControl пытается освободить дескриптор формы плагинов ( window ), которая больше не существует.

Что я пробовал:

procedure AddHandleToControlList(AHandle: DWORD; Align: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  NewWinControl.WindowHandle := AHandle;
  NewWinControl.Align := Align;
  NewWinControl.Width := frmMain.ClientWidth;
  NewWinControl.Height := 30;
  NewWinControl.Parent := frmMain;
end;

procedure AddHandleToControlList(AHandle: DWORD; Align: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  NewWinControl.WindowHandle := AHandle;
  NewWinControl.Align := Align;
  NewWinControl.Width := frmMain.ClientWidth;
  NewWinControl.Height := 30;
  TWinControl(frmMain).Insert(NewWinControl);
end;

Тааак, мысли?

РЕДАКТИРОВАТЬ 1:

Хорошо, так что это правильно добавляет элемент управления в список и соответствует набору TAlign (почему я трачу 8 часов, пытаясь что-то выяснить, я публикую здесь, а затем просто появляется ответ ... о хорошо кому-то может пригодиться этот вопрос и мои разговоры):

procedure AddHandleToControlList(AHandle: DWORD; AName: PChar; ATop, ALeft, AWidth, AHeight: Integer; AAlign: TAlign);
var
  NewWinControl : TWinControl;
begin
  NewWinControl := TWinControl.Create(frmMain);
  With NewWinControl Do
    begin
    Name := AName;
    Top := ATop;
    Left := ALeft;
    Width := AWidth;
    Height := AHeight;
    Align := AAlign;
    WindowHandle := AHandle;
    Visible := True;
  end;
  TWinControl(frmMain).InsertControl(NewWinControl);
end;

Проблема теперь в том, что когда приложение закрывается, я получаю неверную ошибку AV ... Я продолжу !!

РЕДАКТИРОВАТЬ 2: Итак, именно TWinControl.DestroyWindowHandle вызывает AV, потому что дескриптор окна больше не существует. Я пытаюсь придумать чистое решение.

1 Ответ

9 голосов
/ 11 ноября 2011

Извлеките новый класс из TWinControl и переопределите его виртуальный метод DestroyWindowHandle(), чтобы не освободить предоставленный вами HWND.Реализация по умолчанию TWinControl.DestroyWindowHandle() вызывает функцию Win32 API DestroyWnd().

...