首页 > C/C++开发工具专区 > VC技术 > 对话框隐藏的几种方法
2010
01-25

对话框隐藏的几种方法

作者:A   Kun   (a_kun@etang.com)    
  有很多应用程序要求一起动就隐藏起来,这些程序多作为后台程序运行,希望不影响其他窗口,  
   
  往往只在托盘区显示一个图标。这些程序通常都是对话框程序,而对话框在初始化的过程上与SDI  
   
  、MDI的初始化是不同的,对话框只需要DoModule或者是CreateDialog等等对话框函数调用一次便  
   
  可,SDI、MDI则要好几步才行。这样看来,对话框在使用方法上面是隐藏了不少细节的,其中就  
   
  没有SDI、MDI所要求的ShowWindow(nCmdShow)这一步。因此对话框要想一运行就隐藏,并不是很  
   
  直接的。有一些方法可以做到这一点,下面我们就来看看几种方案。    
   
  1.定时器  
  最直观,又是最无奈的一个方法就是使用定时器。既然我们在对话框开始显示之前不能用ShowWin  
   
  dow(SW_HIDE)将其隐藏,那就给一个时间让它显示,完了我们在隐藏它。  
   
  方法:  
   
  1.在OnInitDialog()函数里设置定时器:(WINDOWS   API里面响应消息WM_INITDIALOG)  
   
  SetTimer(1,   1,   NULL);  
   
  2.添加处理WM_TIMER的消息处理函数OnTimer,添加代码:  
   
  if(nIDEvent   ==   1)  
   
  {  
   
  DeleteTimer(1);  
   
  ShowWindow(SW_HIDE);  
   
  }  
   
  这种方法的缺点是显而易见的,使用定时器,使得程序的稳定性似乎打一个折扣;窗口是要先显  
   
  示出来的,那么效果就是窗口闪了一下消失。    
   
  2.改变对话框显示状况  
  在对话框初始化时改变其显示属性可以让它隐藏起来。方法是调用SetWindowPlacement函数:  
   
   
  BOOL   CDialogExDlg::OnInitDialog()  
   
  {  
   
  CDialog::OnInitDialog();  
   
  //DO   something  
   
   
  WINDOWPLACEMENT   wp;  
   
  wp.length=sizeof(WINDOWPLACEMENT);  
   
  wp.flags=WPF_RESTORETOMAXIMIZED;  
   
  wp.showCmd=SW_HIDE;  
   
  SetWindowPlacement(&wp);  
   
  return   TRUE;  
   
  }  
   
     
   
  在需要显示时(通常是响应热键或者托盘图标的鼠标消息):  
   
   
  WINDOWPLACEMENT   wp;  
   
  wp.length=sizeof(WINDOWPLACEMENT);  
   
  wp.flags=WPF_RESTORETOMAXIMIZED;  
   
  wp.showCmd=SW_SHOW;  
   
  SetWindowPlacement(&wp);  
   
   
  这样的效果很不理想:窗口显示在屏幕的左上角,并且是只有标题栏,要正常显示,还需加上如  
   
  下代码:  
   
  定义一个成员变量CRect   rect;  
   
  在OnInitDialog()里面:  
   
  GetWindowRect(&rect);  
   
  在需要显示的地方:  
   
  SetWindowPos(&wndNoTopMost,   wndRc.left,   wndRc.top,   wndRc.right,   wndRc.bottom,    
   
  SWP_SHOWWINDOW);  
   
  CenterWindow();  
   
  即使这样,效果还是很差。  
   
  这种方法还有一个弊端是当程序开始运行并且隐藏起来后,原来激活的窗口变成了非激活状态了  
   
  ,而当对话框显示出来后,对话框自身也是非激活状态的。  
   
   
  3.不绘制窗口  
  当对话框显示时将要响应消息WM_PAINT绘制客户区,相应消息WM_NCPAINT绘制窗口边框。我们在  
   
  窗口第一次自绘自身时隐藏窗口,可以收到比较良好的效果。由于窗口是先画窗口边框,所以我  
   
  们仅需处理WM_NCPAINT即可。代码如下:  
   
  添加WM_NCPAINT处理函数。  
   
  void   CMyDialog::OnNcPaint()  
   
  {  
   
  static   int   i   =   2;  
   
  if(i   >   0)  
   
  {  
   
  i   –;  
   
  ShowWindow(SW_HIDE);  
   
  }  
   
  else  
   
  CDialog::OnNcPaint();  
   
  }  
   
  这里有个问题:为什么要定义静态变量i而且设其值为2呢?  
   
  我们只要窗口隐藏第一次,所以定义这个变量可以判断是否时首次显示窗口。当程序开始运行时  
   
  ,系统发送(SendMessage)WM_NCPAINT消息,此时程序的窗口边框应该被显示,但是此时我们没  
   
  有作任何显示的操作,而是将窗口隐藏,ShowWindow(SW_HIDE)将把窗口的WS_VISIBLE属性去掉,  
   
  继续执行,程序将检查WS_VISIBLE属性,如果没有则显示窗口,所以又发送了一个WM_NCPAINT消  
   
  息。所以我们要处理两次WM_NCPAINT消息。  
   
  在需要窗口显示时,调用ShowWindow(SW_SHOW)即可。  
   
  程序执行的结果是,原来处于激活状态的窗口可能会闪动两下,然后仍然处于激活状态。这种处  
   
  理方式比上面的方式要优越得多。  
   
   
  4.将对话框作为子窗口  
  这种方法是采用SDI框架,主窗口始终隐藏,对话框作为主窗口的成员变量,在CMainFrame::OnCr  
   
  eate()里面加入下代码:  
   
  if(!dlg.Create(IDD_MYDIALOG,   this))  
   
  {  
   
  return   –1;  
   
  }  
   
  dlg.ShowWindow(SW_HIDE);  
   
  在要显示对话框的地方用dlg.ShowWindow(SW_SHOW);即可。注意,主窗口一定要隐藏,否则对话  
   
  框可能会闪现一下。    
   
  隐藏状态栏窗口  
  上面介绍了几种检查对话框的方法,大家如果试过的话可能已经注意到系统状态栏里在程序启动  
   
  时会有程序的图标闪过,在隐藏对话框的时候这个也是要隐藏的,方法很简单:  
   
  在OnInitDialog()函数里面加上ModifyStyleEx(WS_EX_APPWINDOW,   WS_EX_TOOLWINDOW);即可。在  
   
  要显示窗口的地方加上代码ModifyStyleEx(WS_EX_TOOLWINDOW,   WS_EX_APPWINDOW);即将窗口的扩  
   
  展样式改回来。  
   
   
  以上是我的一点经验总结,有错误或不完善的地方还望大家提出指正。欢迎大家与我联系。


对话框隐藏的几种方法》有 1 条评论

  1. coolker 说:

    作者:A   Kun   (a_kun@etang.com)    
      有很多应用程序要求一起动就隐藏起来,这些程序多作为后台程序运行,希望不影响其他窗口,  
       
      往往只在托盘区显示一个图标。这些程序通常都是对话框程序,而对话框在初始化的过程上与SDI  
       
      、MDI的初始化是不同的,对话框只需要DoModule或者是CreateDialog等等对话框函数调用一次便  
       
      可,SDI、MDI则要好几步才行。这样看来,对话框在使用方法上面是隐藏了不少细节的,其中就  
       
      没有SDI、MDI所要求的ShowWindow(nCmdShow)这一步。因此对话框要想一运行就隐藏,并不是很  
       
      直接的。有一些方法可以做到这一点,下面我们就来看看几种方案。    
       
      1.定时器  
      最直观,又是最无奈的一个方法就是使用定时器。既然我们在对话框开始显示之前不能用ShowWin  
       
      dow(SW_HIDE)将其隐藏,那就给一个时间让它显示,完了我们在隐藏它。  
       
      方法:  
       
      1.在OnInitDialog()函数里设置定时器:(WINDOWS   API里面响应消息WM_INITDIALOG)  
       
      SetTimer(1,   1,   NULL);  
       
      2.添加处理WM_TIMER的消息处理函数OnTimer,添加代码:  
       
      if(nIDEvent   ==   1)  
       
      {  
       
      DeleteTimer(1);  
       
      ShowWindow(SW_HIDE);  
       
      }  
       
      这种方法的缺点是显而易见的,使用定时器,使得程序的稳定性似乎打一个折扣;窗口是要先显  
       
      示出来的,那么效果就是窗口闪了一下消失。    
       
      2.改变对话框显示状况  
      在对话框初始化时改变其显示属性可以让它隐藏起来。方法是调用SetWindowPlacement函数:  
       
       
      BOOL   CDialogExDlg::OnInitDialog()  
       
      {  
       
      CDialog::OnInitDialog();  
       
      //DO   something  
       
       
      WINDOWPLACEMENT   wp;  
       
      wp.length=sizeof(WINDOWPLACEMENT);  
       
      wp.flags=WPF_RESTORETOMAXIMIZED;  
       
      wp.showCmd=SW_HIDE;  
       
      SetWindowPlacement(&wp);  
       
      return   TRUE;  
       
      }  
       
         
       
      在需要显示时(通常是响应热键或者托盘图标的鼠标消息):  
       
       
      WINDOWPLACEMENT   wp;  
       
      wp.length=sizeof(WINDOWPLACEMENT);  
       
      wp.flags=WPF_RESTORETOMAXIMIZED;  
       
      wp.showCmd=SW_SHOW;  
       
      SetWindowPlacement(&wp);  
       
       
      这样的效果很不理想:窗口显示在屏幕的左上角,并且是只有标题栏,要正常显示,还需加上如  
       
      下代码:  
       
      定义一个成员变量CRect   rect;  
       
      在OnInitDialog()里面:  
       
      GetWindowRect(&rect);  
       
      在需要显示的地方:  
       
      SetWindowPos(&wndNoTopMost,   wndRc.left,   wndRc.top,   wndRc.right,   wndRc.bottom,    
       
      SWP_SHOWWINDOW);  
       
      CenterWindow();  
       
      即使这样,效果还是很差。  
       
      这种方法还有一个弊端是当程序开始运行并且隐藏起来后,原来激活的窗口变成了非激活状态了  
       
      ,而当对话框显示出来后,对话框自身也是非激活状态的。  
       
       
      3.不绘制窗口  
      当对话框显示时将要响应消息WM_PAINT绘制客户区,相应消息WM_NCPAINT绘制窗口边框。我们在  
       
      窗口第一次自绘自身时隐藏窗口,可以收到比较良好的效果。由于窗口是先画窗口边框,所以我  
       
      们仅需处理WM_NCPAINT即可。代码如下:  
       
      添加WM_NCPAINT处理函数。  
       
      void   CMyDialog::OnNcPaint()  
       
      {  
       
      static   int   i   =   2;  
       
      if(i   >   0)  
       
      {  
       
      i   –;  
       
      ShowWindow(SW_HIDE);  
       
      }  
       
      else  
       
      CDialog::OnNcPaint();  
       
      }  
       
      这里有个问题:为什么要定义静态变量i而且设其值为2呢?  
       
      我们只要窗口隐藏第一次,所以定义这个变量可以判断是否时首次显示窗口。当程序开始运行时  
       
      ,系统发送(SendMessage)WM_NCPAINT消息,此时程序的窗口边框应该被显示,但是此时我们没  
       
      有作任何显示的操作,而是将窗口隐藏,ShowWindow(SW_HIDE)将把窗口的WS_VISIBLE属性去掉,  
       
      继续执行,程序将检查WS_VISIBLE属性,如果没有则显示窗口,所以又发送了一个WM_NCPAINT消  
       
      息。所以我们要处理两次WM_NCPAINT消息。  
       
      在需要窗口显示时,调用ShowWindow(SW_SHOW)即可。  
       
      程序执行的结果是,原来处于激活状态的窗口可能会闪动两下,然后仍然处于激活状态。这种处  
       
      理方式比上面的方式要优越得多。  
       
       
      4.将对话框作为子窗口  
      这种方法是采用SDI框架,主窗口始终隐藏,对话框作为主窗口的成员变量,在CMainFrame::OnCr  
       
      eate()里面加入下代码:  
       
      if(!dlg.Create(IDD_MYDIALOG,   this))  
       
      {  
       
      return   –1;  
       
      }  
       
      dlg.ShowWindow(SW_HIDE);  
       
      在要显示对话框的地方用dlg.ShowWindow(SW_SHOW);即可。注意,主窗口一定要隐藏,否则对话  
       
      框可能会闪现一下。    
       
      隐藏状态栏窗口  
      上面介绍了几种检查对话框的方法,大家如果试过的话可能已经注意到系统状态栏里在程序启动  
       
      时会有程序的图标闪过,在隐藏对话框的时候这个也是要隐藏的,方法很简单:  
       
      在OnInitDialog()函数里面加上ModifyStyleEx(WS_EX_APPWINDOW,   WS_EX_TOOLWINDOW);即可。在  
       
      要显示窗口的地方加上代码ModifyStyleEx(WS_EX_TOOLWINDOW,   WS_EX_APPWINDOW);即将窗口的扩  
       
      展样式改回来。  
       
       
      以上是我的一点经验总结,有错误或不完善的地方还望大家提出指正。欢迎大家与我联系。

留下一个回复