弹出模态窗体的应用程序隐藏和恢复显示的问题解决
2008-03-04 19:53
549 查看
主程序是MDI风格的,在弹出很多子窗体并同时有个模态窗体的情况下,实现定时锁屏功能,锁屏后,要使得整个应用程序都最小化,当输入所凭密码后再恢复显示成最初的状态。
这个过程会有几个问题点需要解决:
1、主窗体包括子窗体可以用frmMain.Hide来隐藏
2、是否有弹出来模态窗体需要进行检测,如果有则需要抓出模态窗体的句柄Handle,通过对模态窗体的发消息,隐藏模态窗体
3、恢复主窗体用frmMain.Show来显示
4、如果模态窗体句柄存在,则恢复显示模态窗体,同样用对指定句柄发消息来实现
5、对应用程序进行restore,此步骤很关键,没有此步骤,则会导致锁屏多次后,主窗体的【最小化】按钮不起作用,这时窗体可以操作、可以最大化、可以关闭,却再也不能最小化了!这就是引用消息机制的副作用,即使你的wndproc里面含有inherited也没用,就是不最小化,原因是这样的:
在进程中,主窗体的WM_SYSCOMMAND 消息是被传递给Application 类处理的,当CmdType 为SC_MINIMIZE的时候,Application 会调用Minimize 方法:
procedure TApplication.Minimize;
begin
if not IsIconic(FHandle) then
begin
NormalizeTopMosts;
SetActiveWindow(FHandle);
if (MainForm <> nil) and (ShowMainForm or MainForm.Visible)
and IsWindowEnabled(MainForm.Handle) then
begin
SetWindowPos(FHandle, MainForm.Handle, MainForm.Left, MainForm.Top,
MainForm.Width, 0, SWP_SHOWWINDOW);
DefWindowProc(FHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
end else
ShowWinNoAnimate(FHandle, SW_MINIMIZE);
if Assigned(FOnMinimize) then FOnMinimize(Self);
end;
end;
注意这个IsIconic(FHandle),它就是问题原因的冰山一角。IsIconic 是用来检测窗体是否处于最小化状态的API。我发现,第二实例将前一实例的主窗体置前之后,这个窗体最小化调用这个方法时,每次IsIconic(FHandle) 都是True。也就是说,Application 一直认为自己是最小化的(所以不能怪wndproc里面的inherited,因为inherited起作用了)。
于是问题就比较清楚了:我们在将主窗体强行置到最前的时候,Application 并没有恢复原状态。于是在Minimize 方法中主窗体就得不到最小化的命令了。
难怪在VC 开发的程序中不会有这样的问题!因为不存在Application 的这个因素。
于是我们只要将主窗体强行置前之前,首先将Application 恢复:
if IsIconic(Application.Handle) then
begin
DefWindowProc(Application.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
end;
或者自己调用Application.Restore;来恢复。这样就好了。
具体程序关键代码片段如下:
--------------------------------------------
procedure TfrmMain.acLockExecute(Sender: TObject); //锁屏动作
var
tHandle:HWND;
function ApplicationHasModalForm:HWND; //找到模态窗体
var
i:integer;
begin
result:=0;
for i:=0 to Screen.FormCount-1 do
begin
if Screen.Forms[i] is TForm then
begin
if fsModal in Screen.Forms[i].FormState then
begin
result:=Screen.Forms[i].Handle;
break;
end;
end;
end;
end;
begin
if LockForm <> nil then
Exit;
cnMain.Pause := True;
frmMain.Hide; //隐藏主程序
tHandle:=ApplicationHasModalForm;//获得模态窗体句柄
if tHandle>0 then
ShowWindow(tHandle,SW_HIDE); //隐藏模态窗体
LockForm := TLockForm.Create(Application);
LockForm.ShowModal;
LockForm.Free;
LockForm := nil;
dwLastInputTick := GetTickCount;
cnMain.Pause := False;
frmMain.Show; //显示主程序
if tHandle>0 then
ShowWindow(tHandle,SW_SHOW); //显示模态窗体
Application.Restore; //恢复窗体状态,否则"最小化"可能失败
if acNavigate.Checked then
begin
ShowDockForm(frmNavigate);
end;
end;
上面代码的加粗部分即是关键代码部分。
这个过程会有几个问题点需要解决:
1、主窗体包括子窗体可以用frmMain.Hide来隐藏
2、是否有弹出来模态窗体需要进行检测,如果有则需要抓出模态窗体的句柄Handle,通过对模态窗体的发消息,隐藏模态窗体
3、恢复主窗体用frmMain.Show来显示
4、如果模态窗体句柄存在,则恢复显示模态窗体,同样用对指定句柄发消息来实现
5、对应用程序进行restore,此步骤很关键,没有此步骤,则会导致锁屏多次后,主窗体的【最小化】按钮不起作用,这时窗体可以操作、可以最大化、可以关闭,却再也不能最小化了!这就是引用消息机制的副作用,即使你的wndproc里面含有inherited也没用,就是不最小化,原因是这样的:
在进程中,主窗体的WM_SYSCOMMAND 消息是被传递给Application 类处理的,当CmdType 为SC_MINIMIZE的时候,Application 会调用Minimize 方法:
procedure TApplication.Minimize;
begin
if not IsIconic(FHandle) then
begin
NormalizeTopMosts;
SetActiveWindow(FHandle);
if (MainForm <> nil) and (ShowMainForm or MainForm.Visible)
and IsWindowEnabled(MainForm.Handle) then
begin
SetWindowPos(FHandle, MainForm.Handle, MainForm.Left, MainForm.Top,
MainForm.Width, 0, SWP_SHOWWINDOW);
DefWindowProc(FHandle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
end else
ShowWinNoAnimate(FHandle, SW_MINIMIZE);
if Assigned(FOnMinimize) then FOnMinimize(Self);
end;
end;
注意这个IsIconic(FHandle),它就是问题原因的冰山一角。IsIconic 是用来检测窗体是否处于最小化状态的API。我发现,第二实例将前一实例的主窗体置前之后,这个窗体最小化调用这个方法时,每次IsIconic(FHandle) 都是True。也就是说,Application 一直认为自己是最小化的(所以不能怪wndproc里面的inherited,因为inherited起作用了)。
于是问题就比较清楚了:我们在将主窗体强行置到最前的时候,Application 并没有恢复原状态。于是在Minimize 方法中主窗体就得不到最小化的命令了。
难怪在VC 开发的程序中不会有这样的问题!因为不存在Application 的这个因素。
于是我们只要将主窗体强行置前之前,首先将Application 恢复:
if IsIconic(Application.Handle) then
begin
DefWindowProc(Application.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);
end;
或者自己调用Application.Restore;来恢复。这样就好了。
具体程序关键代码片段如下:
--------------------------------------------
procedure TfrmMain.acLockExecute(Sender: TObject); //锁屏动作
var
tHandle:HWND;
function ApplicationHasModalForm:HWND; //找到模态窗体
var
i:integer;
begin
result:=0;
for i:=0 to Screen.FormCount-1 do
begin
if Screen.Forms[i] is TForm then
begin
if fsModal in Screen.Forms[i].FormState then
begin
result:=Screen.Forms[i].Handle;
break;
end;
end;
end;
end;
begin
if LockForm <> nil then
Exit;
cnMain.Pause := True;
frmMain.Hide; //隐藏主程序
tHandle:=ApplicationHasModalForm;//获得模态窗体句柄
if tHandle>0 then
ShowWindow(tHandle,SW_HIDE); //隐藏模态窗体
LockForm := TLockForm.Create(Application);
LockForm.ShowModal;
LockForm.Free;
LockForm := nil;
dwLastInputTick := GetTickCount;
cnMain.Pause := False;
frmMain.Show; //显示主程序
if tHandle>0 then
ShowWindow(tHandle,SW_SHOW); //显示模态窗体
Application.Restore; //恢复窗体状态,否则"最小化"可能失败
if acNavigate.Checked then
begin
ShowDockForm(frmNavigate);
end;
end;
上面代码的加粗部分即是关键代码部分。
相关文章推荐
- 解决js常见的模态窗体显示报错的问题
- 模态窗体弹出显示运行时间出问题
- 非模态窗体中控件不显示的问题解决
- 解决select2在bootstrap模态框中下拉框隐藏的问题
- Android完美解决输入框EditText隐藏密码打勾显示密码问题
- 解决swiper在标签页里面 先隐藏后显示 之后 的一系列问题
- 解决VS2005在窗体设计界面中数据源窗口灰化不显示数据源的问题
- C#不规则窗体制作(已经解决24位色以上不能正常显示问题)
- iOS解决隐藏导航栏后,打开照片选择器后导航栏不显示的问题以及更换导航栏背景色
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- Datagrid中弹出新窗体出现的含有[object]空白页面问题的解决
- C# winform中不规则窗体制作的解决方案(已经解决24位色以上不能正常显示问题)
- 表格中tr的隐藏与显示问题使用tbody解决
- Visual Studio 2008项目中WinForm窗体图标显示为类图标,只能打开代码而无法打开视图问题解决
- 如何解决Bootstrap的模态框在Framework7中使用出现遮罩无法显示的问题?
- Delphi中模态窗口切换时隐藏问题的解决办法
- 弹出div上点击按钮div会自动隐藏问题,已解决
- 解决Winform中弹出WPF窗体不能在文本框中输入的问题
- z-index解决弹出层遮罩层覆盖子div不能显示输出的问题
- 解决在查看里无法设置“显示所有文件和文件夹”及“隐藏受保护的操作系统文件”的问题