The GetSaveFileName
API function, which is what TSaveDialog
is a wrapper form, doesn't provide any way to control the position of the dialog box, so you need to intercept an early message to the dialog and adjust the position there, as other solutions you've seen have done.
You want the dialog box to be centered over your form, so solutions that provide Top
and Left
properties for the dialog won't work very well since they don't take the window's size into account, and they also require you to calculate new coordinates before you call Execute
every time.
Here's a different idea. It will still require overriding WndProc
.
type
TCenterSaveDialog = class(TSaveDialog)
private
FCenterForm: TCustomForm;
protected
procedure WndProc(var Message: TMessage); override;
public
// When this property is assigned, the dialog will center
// itself over the given form each time the dialog appears.
property CenterForm: TCustomForm read FCenterForm write FCenterForm;
end;
procedure TCenterSaveDialog.WndProc(var Message: TMessage);
var
lpOfNotify: POFNotify;
FormRect, DialogRect: TRect;
NewLeft, NewTop: Integer;
begin
inherited;
if (Message.Msg = wm_Notify) and Assigned(CenterForm) then begin
lpOfNotify := POFNotify(Message.LParam);
if lpOfNotify.hdr.code = cdn_InitDone then begin
GetWindowRect(CenterForm.Handle, FormRect);
GetWindowRect(lpOfNotify.hdr.hwndFrom, DialogRect);
NewLeft := FormRect.Left
+ (FormRect.Right - FormRect.Left) div 2
- (DialogRect.Right - DialogRect.Left) div 2;
NewTop := FormRect.Top
+ (FormRect.Bottom - FormRect.Top) div 2
- (DialogRect.Bottom - DialogRect.Top) div 2;
SetWindowPos(lpOfNotify.hdr.hwndFrom, 0,
NewLeft, NewTop, 0, 0,
swp_NoActivate or swp_NoOwnerZOrder or swp_NoSize or swp_NoZOrder);
end;
end;
end;
See also: cdn_InitDone