弹出模态窗体的应用程序隐藏和恢复显示的问题解决


    主程序是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;

 上面代码的加粗部分即是关键代码部分。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值