【发布时间】:2011-07-19 20:47:47
【问题描述】:
我有一个 Delphi 应用程序,它使用 TOpenDialog 让用户选择一个文件。默认情况下,打开的对话框显示在当前监视器的中心,现在可以“英里”远离应用程序的窗口。我希望对话框以 TOpenDialog 的所有者控件为中心显示,如果失败,我会选择应用程序的主窗口。
下面的代码是可行的,它来自 TJvOpenDialog,它给了我一些关于如何做的提示:
type
TMyOpenDialog = class(TJvOpenDialog)
private
procedure SetPosition;
protected
procedure DoFolderChange; override;
procedure WndProc(var Msg: TMessage); override;
end;
procedure TMyOpenDialog.SetPosition;
begin
var
Monitor: TMonitor;
ParentControl: TWinControl;
Res: LongBool;
begin
if (Assigned(Owner)) and (Owner is TWinControl) then
ParentControl := (Owner as TWinControl)
else if Application.MainForm <> nil then
ParentControl := Application.MainForm
else begin
// this code was already in TJvOpenDialog
Monitor := Screen.Monitors[0];
Res := SetWindowPos(ParentWnd, 0,
Monitor.Left + ((Monitor.Width - Width) div 2),
Monitor.Top + ((Monitor.Height - Height) div 3),
Width, Height,
SWP_NOACTIVATE or SWP_NOZORDER);
exit; // =>
end;
// this is new
Res := SetWindowPos(GetParent(Handle), 0,
ParentControl.Left + ((ParentControl.Width - Width) div 2),
ParentControl.Top + ((ParentControl.Height - Height) div 3),
Width, Height,
SWP_NOACTIVATE or SWP_NOZORDER);
end;
procedure TMyOpenDialog.DoFolderChange
begin
inherited DoFolderChange; // call inherited first, it sets the dialog style etc.
SetPosition;
end;
procedure TMyOpenDialog.WndProc(var Msg: TMessage);
begin
case Msg.Msg of
WM_ENTERIDLE: begin
// This has never been called in my tests, but since TJVOpenDialog
// does it I figured there may be some fringe case which requires
// SetPosition being called from here.
inherited; // call inherited first, it sets the dialog style etc.
SetPosition;
exit;
end;
end;
inherited;
end;
“作品种类”表示对话框第一次打开时,以所有者窗体为中心显示。但是,如果我随后关闭对话框,移动窗口并再次打开对话框,SetWindowPos 似乎没有任何效果,即使它确实返回 true。对话框将在与第一次相同的位置打开。
这是在 Windows XP 上运行的 Delphi 2007,目标框也在运行 Windows XP。
【问题讨论】:
-
这感觉像是错误的解决方案。您不应该像普通对话框那样四处闲逛。我知道更现代的 Delphi 版本已经改进了他们常用对话框的代码来解决这样的问题。我不确定这些更改出现在哪个版本的 Delphi 中,但我认为这对您来说可能是个问题。当系统通用对话框被正确使用(而 VCL 并不总是这样做)时,它们会出现在合理的位置,甚至会记住它们在以前会话中的大小和位置。
-
您是否将 HWndOwner 传递给 OpenDialog.Execute? D2007(我认为它甚至是更早添加的)有一个重载版本的 Execute,它接受父窗口的句柄来帮助解决这个问题。
-
查看我的旧对话框的代码,我发现在将消息传递给默认窗口过程之前,我已经完成了对“WM_SHOWWINDOW”消息的响应。
-
见
TMyOpenDialog.WndProc:注意with的邪恶:with **Msg** do case **Msg** of提示:不要使用with !如果你认为你已经找到了一个合适的地方来使用它——你还没有! /endrant PS:您应该始终确保您正确设置Msg.Result- 否则您可能会遇到意外行为。 -
@Sertac 使用 IFileDialog 大概拿起 WM_SHOWWINDOW 有点困难?
标签: delphi windows-xp delphi-2007