此对话框显示正好在按钮下,但在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;
更新: 如果我们打开Form而不是Dialog,如果该Form有BorderStyle bsSizeable或bsSizeToolWin,那么一切都OK。否则(bsDialog,bsSingle,bsToolWindow),Form打开从上面的示例中转换为Dialog。
答案 0 :(得分:3)
运行您在Windows 7上显示的确切代码,我无法重现您在Windows 7 screnshot中显示的相同对话框定位。 MessageDlgPos
窗口以与Windows 8屏幕截图相同的方式向上和向左偏移:
话虽如此,我注意到您将MessageDlg
窗口相对于按钮的客户区定位:
如果您希望对话框相对于其实际底边定位,则需要在按钮ClientToScreen()
上调用Parent
而不是按钮本身:
p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top+Button3.Height));
最终结果大致相同:
现在,为什么重叠发生在第一位?因为窗口的位置使得其非客户区域的左上角落在指定的坐标处:
您可以调整窗口坐标来考虑:
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));
让你更接近所需的位置:
请注意,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;
更新:D2007包含DwmApi,因此无需使用LoadLibrary