首页 > 解决方案 > 获取表单的大小和边框

问题描述

我试图在主表单“并排”之后对齐我的子表单,但有一些困难

要重现该问题,请创建新的 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的:在此处输入图像描述

视窗 10:在此处输入图像描述

使用后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 上完全一致

视窗 7:在此处输入图像描述 视窗 10:在此处输入图像描述

但要做到这一点,我需要先显示子表单。如果我DwmGetWindowAttribute在显示之前调用子(和不可见)表单,我会得到与 for 相同的值。GetWindowRect在显示之前不可能得到这个?

标签: delphiwinapiwindow

解决方案


感谢Jonathan Potter的评论,现在我有了这样的代码并且它可以工作:

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;

实际上,这段代码的可读性较差,并且包含与原始代码相同的代码,但这可以在将来需要绘制自定义绘图表单时有所帮助。


推荐阅读