Получить размер и границы формы - PullRequest
4 голосов
/ 13 января 2020

Я пытаюсь выровнять свою дочернюю форму после основной формы "бок о бок", но у меня возникают некоторые трудности

Чтобы воспроизвести проблему, создайте новое приложение VCL и добавьте в форму одну кнопку:

procedure TForm1.Button1Click(Sender: TObject);
var
  Form: TForm1;
begin
  Application.CreateForm(TForm1, Form);
  Form.BorderStyle := bsSingle;
  Form.Left := Left + Width;
  Form.Top := Top;
  Form.Show;
end;

И результат:

Windows 7: enter image description here

Windows 10: enter image description here

После использования Winapi.DwmApi:

DXR1 := 0;
DXL2 := 0;
if (Win32MajorVersion >= 6) and DwmCompositionEnabled then begin
  DwmGetWindowAttribute(Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @R1, SizeOf(R1));
  Winapi.Windows.GetWindowRect(Handle, R2);
  DXR1 := R2.Right - R1.Right;
  DYT1 := R2.Top   - R1.Top;
end;

FormJob.Left := Left + Width - DXR1;
FormJob.Top := Top - DYT1;
FormJob.Show;

if (Win32MajorVersion >= 6) and DwmCompositionEnabled then begin
  DwmGetWindowAttribute(FormJob.Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @R1, SizeOf(R1));
  Winapi.Windows.GetWindowRect(FormJob.Handle, R2);
  DXL2 := R1.Left - R2.Left;
  DYT2 := R2.Top  - R1.Top;
end;
FormJob.Left := FormJob.Left - DXL2;
FormJob.Top := FormJob.Top + DYT2;

И теперь это полностью выровнено на Windows 7 и Windows 10

Windows 7: enter image description here Windows 10: enter image description here

Но для этого мне нужно сначала показать дочернюю форму. Если я вызываю DwmGetWindowAttribute для дочерней (и невидимой) формы перед показом, я получаю те же значения, что и для GetWindowRect. Невозможно получить это до показа?

1 Ответ

7 голосов
/ 13 января 2020

Благодаря комментарию Джонатана Поттера теперь у меня есть такой код, и он работает:

var
  R1, R2: TRect;
  DXR1, DXL2, DYT1, DYT2: Integer;
  bCloak: BOOL; // Can't use Boolean here
begin
  Application.CreateForm(TFormJob, FormJob);
  if (Win32MajorVersion >= 6) and DwmCompositionEnabled then begin
    DXR1 := 0;
    DXL2 := 0;
    DYT1 := 0;
    DYT2 := 0;

    if (DwmGetWindowAttribute(Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @R1, SizeOf(R1)) = S_OK) and
       Winapi.Windows.GetWindowRect(Handle, R2) then begin
      DXR1 := R2.Right - R1.Right; // Right width of the shadow for parent
      DYT1 := R2.Top   - R1.Top;   // Top height of the shadow for parent
    end;

    bCloak := True; // Make form invisible
    DwmSetWindowAttribute(FormJob.Handle, DWMWA_CLOAK, @bCloak, SizeOf(bCloak));
    FormJob.Show; // Draw invisible form

    if (DwmGetWindowAttribute(FormJob.Handle, DWMWA_EXTENDED_FRAME_BOUNDS, @R1, SizeOf(R1)) = S_OK) and
       Winapi.Windows.GetWindowRect(FormJob.Handle, R2) then begin
      DXL2 := R1.Left - R2.Left; // Left width of the shadow for child
      DYT2 := R2.Top  - R1.Top;  // Top height of the shadow for child
    end;

    FormJob.Left := Left + Width  - DXR1 - DXL2;
    FormJob.Top := Top - DYT1 + DYT2;

    bCloak := False; // Make form visible
    DwmSetWindowAttribute(FormJob.Handle, DWMWA_CLOAK, @bCloak, SizeOf(bCloak));
  end
  else begin
    FormJob.Left := Left + Width;
    if FormJob.Left + FormJob.Width > Screen.DesktopRect.Right then
      FormJob.Left := Screen.DesktopRect.Right - FormJob.Width;
    FormJob.Top := Top;
    FormJob.Show;
  end;

На самом деле этот код менее читабелен и содержит то же, что и исходный код, но это может помочь в будущем, когда будет необходимо нарисовать нестандартную форму для рисования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...