Reputation: 107
This dialog shows exactly under button, but in Windows 8 dialog is shifted to the left and upward. How to get the same results in all Windows versions?
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;
update: In case we open Form instead of Dialog, and if that Form has BorderStyle bsSizeable or bsSizeToolWin, then everything is OK. Otherwise (bsDialog, bsSingle, bsToolWindow), Form opens shifted as Dialog from the example above.
Upvotes: 1
Views: 464
Reputation: 107
After your answers and comments and some additional research, I came to this solution. Tested on Windows 8, 7 with Aero, 7 without Aero and XP. I was hoping for something more simple and stable but ...
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;
update: D2007 includes DwmApi, so no need for complications with LoadLibrary
Upvotes: 1
Reputation: 597081
Running the exact code you have shown on Windows 7, I am not able to reproduce the same dialog positioning you have shown in your Windows 7 screnshot. The MessageDlgPos
window is offset up and to the left in the same manner as your Windows 8 screenshot:
That being said, I notice you are positioning your MessageDlg
window relative to the button's client area:
If you want the dialog positioned relative to its actual bottom edge, you need to call ClientToScreen()
on the button's Parent
rather than on the button itself:
p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top+Button3.Height));
The end result is about the same, though:
Now, why is the overlap occurring in the first place? Because the window is being positioned such that the top-left corner of its non-client area falls at the specified coordinates:
You can adjust the window coordinates to account for that:
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));
Which gets you much closer to the desired position:
Note that Aero "tweaks" system metrics a bit, so you might need to use things like DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS)
and/or GetThemeSysSize()
to get more accurate metrics.
Upvotes: 3