对话框在Windows 8中向左和向上移动

时间:2015-04-11 09:15:28

标签: delphi winapi windows-8 dialog position

此对话框显示正好在按钮下,但在Windows 8对话框中向左和向上移动。如何在所有Windows版本中获得相同的结果?

procedure TForm1.Button3Click(Sender: TObject);
var p: TPoint;
begin
  p := Button3.ClientToScreen(Point(0, Button3.Height));
  MessageDlgPos('', mtInformation, [mbOK], 0, p.X, p.Y);
end;

Shifted dialog in Win 8

更新: 如果我们打开Form而不是Dialog,如果该Form有BorderStyle bsSizeable或bsSizeToolWin,那么一切都OK。否则(bsDialog,bsSingle,bsToolWindow),Form打开从上面的示例中转换为Dialog。

2 个答案:

答案 0 :(得分:3)

运行您在Windows 7上显示的确切代码,我无法重现您在Windows 7 screnshot中显示的相同对话框定位。 MessageDlgPos窗口以与Windows 8屏幕截图相同的方式向上和向左偏移:

screenshot

话虽如此,我注意到您将MessageDlg窗口相对于按钮的客户区定位:

screenshot

如果您希望对话框相对于其实际底边定位,则需要在按钮ClientToScreen()上调用Parent而不是按钮本身:

p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top+Button3.Height));

screenshot

最终结果大致相同:

screenshot

现在,为什么重叠发生在第一位?因为窗口的位置使得其非客户区域的左上角落在指定的坐标处:

screenshot

您可以调整窗口坐标来考虑:

p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top + Button3.Height));
Inc(p.X, GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CXBORDER));
Inc(p.Y, GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYBORDER));

让你更接近所需的位置:

screenshot

请注意,Aero会稍微“调整”系统指标,因此您可能需要使用DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS)和/或GetThemeSysSize()等内容来获取更准确的指标。

答案 1 :(得分:1)

在你的回答和评论以及一些额外的研究之后,我找到了这个解决方案。在Windows 8,7和Aero上测试,7没有Aero和XP。我希望有一些更简单和稳定的东西......但

uses DwmApi;

type
  TNonClientMetricsX = packed record
    cbSize: UINT;
    iBorderWidth: Integer;       iScrollWidth: Integer;
    iScrollHeight: Integer;      iCaptionWidth: Integer;
    iCaptionHeight: Integer;     lfCaptionFont: TLogFontA;
    iSmCaptionWidth: Integer;    iSmCaptionHeight: Integer;
    lfSmCaptionFont: TLogFontA;  iMenuWidth: Integer;
    iMenuHeight: Integer;        lfMenuFont: TLogFontA;
    lfStatusFont: TLogFontA;     lfMessageFont: TLogFontA;
    iPaddedBorderWidth: Integer; // not defined in Delphi 2007
  end;

function GetExtendedFrameOffset(BorderStyle: TFormBorderStyle): integer;
var
  IsEnabled: BOOL;
  NCM: TNonClientMetricsX;
begin
  Result := 0;
  if (DwmIsCompositionEnabled(IsEnabled) = S_OK) and IsEnabled and
     (BorderStyle in [bsdialog, bsSingle, bsToolWindow]) then
  begin
    NCM.cbSize := SizeOf(NCM);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(NCM), @NCM, 0);
    Result := NCM.iBorderWidth + NCM.iPaddedBorderWidth;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var p: TPoint; offset: integer;
begin
  p := Button3.ClientToScreen(Point(0, Button3.Height));
  offset := GetExtendedFrameOffset(bsDialog);
  MessageDlgPos('', mtInformation, [mbOK], 0, p.X + offset, p.Y + offset);
end;

enter image description here

更新:D2007包含DwmApi,因此无需使用LoadLibrary