【问题标题】:Get size and borders of the Form获取表单的大小和边框
【发布时间】:2020-04-29 23:01:04
【问题描述】:

我正在尝试“并排”在主表单之后对齐我的子表单,但遇到了一些困难

要重现问题,请创建新的 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:

Windows 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 上完全一致

Windows 7: Windows 10:

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

【问题讨论】:

  • 这是 DWM 的一个怪癖,在显示窗口之前您无法查询框架边界。您可以做的是在显示之前使用 DWMWA_CLOAK 隐藏窗口。
  • 我认为这个问题缺少关于为什么表格首先不对齐的上下文。复制案例会很好。
  • @SertacAkyuz,但是第一部分代码已经重现了问题,还是我需要扩展这部分?
  • 我向一个新的 VCL 应用程序添加了第二个表单。调用您从主窗体中显示的代码,将 FormJob 替换为 Form2,并且无法重现该问题。表格对齐好了。在 Windows 7 上测试。
  • 您是否禁用了主题?另外,尝试设置您的 Form2.BorderStyle := bsSingle;不同风格的窗户有不同的阴影宽度和高度值。

标签: delphi winapi window


【解决方案1】:

感谢 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;

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

【讨论】:

    猜你喜欢
    • 2012-04-15
    • 1970-01-01
    • 2013-04-21
    • 2014-07-13
    • 1970-01-01
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多