vc开始隐藏界面

有很多应用程序要求一起动就隐藏起来,这些程序多作为后台程序运行,希望不影响其他窗口,往往只在托盘区显示一个图标。这些程序通常都是对话框程序,而对话框在初始化的过程上与SDI、MDI的初始化是不同的,对话框只需要DoModule或者是CreateDialog等等对话框函数调用一次便可,SDI、MDI则要好几步才行。这样看来,对话框在使用方法上面是隐藏了不少细节的,其中就没有SDI、MDI所要求的ShowWindow(nCmdShow)这一步。因此对话框要想一运行就隐藏,并不是很直接的。有一些方法可以做到这一点,下面我们就来看看几种方案。   


    


1.定时器 
最直观,又是最无奈的一个方法就是使用定时器。既然我们在对话框开始显示之前不能用ShowWindow(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::OnCreate()里面加入下代码:   


if(!dlg.Create(IDD_MYDIALOG,   this))   


{   


          return   –1;   


}   


dlg.ShowWindow(SW_HIDE);   


在要显示对话框的地方用dlg.ShowWindow(SW_SHOW);即可。注意,主窗口一定要隐藏,否则对话框可能会闪现一下。 
 
通过分析MFC   调用模式对话框的方法向大家展示一种简单,合理,完满的解决方案。 


  首先,用MFC   生成的一个基于对话框的应用程序框架,然后修改对话框资源的Visible属性使之成为不可见(在属性页的MoreStyle中),接着按下F5   来运行这个程序,我们会发现,它并不象我们期望的那样一开始就被隐藏。而是被显示了出来。那么为什么会这样呢?特别是精通SDK的朋友们,会对此百思不得其解。 


  其实,MFC框架为了显示对话框很多工作,它并不简简单单地调用 DialogBox 显示对话框,而是使用了相对复杂的方法。现在,我就来引导大家对此探个究竟。 


  在生成的应用程序框架中(名称为Test),你会看到CTestApp和CTestDlg   两个类,在 CTestApp 的 InitInstance 方法中有如下语句: 


          CTestDlg   dlg; 
          m_pMainWnd   =   &dlg; 
          int   nResponse   =   dlg.DoModal();                 //   此处将创建并显示对话框 


DoModal   是一个虚函数,MFC允许用户编写自己的调用对话框方式来替代原来的方式。但是,MS 实在令人失望。如果,你打开   DlgCore.Cpp   (MFC   Source   目录下)并复制 DoModal    的代码到你自己的类中,你会发现无法编译成功。原因在于MS在 DoModal 中使用了两个非输出函数 AfxHookWindowCreate   和 AfxUnhookWindowCreate。(这两个函数的作用超出了本文所讨论的范围,因此不作详细论述。)由于无法编译,所以 MS    要求用户的   DoModal   必须调用 CDialog 的 DoModal 来显示对话框。这样,控制隐藏就无法通过重载 DoModal 实现了。那么 MS 在 DoModal 中干了什么呢?下面就是一部分代码。 


int   CDialog::DoModal() 

    ......   读入资源,并作一些设置 
    if   (CreateDlgIndirect(lpDialogTemplate, 
                        CWnd::FromHandle(hWndParent),   hInst))  //创建无模式对话框 
        { 
            if   (m_nFlags   &   WF_CONTINUEMODAL) 
            { 
                //   enter   modal   loop 
                DWORD   dwFlags   =   MLF_SHOWONIDLE;  //罪魁祸首就是他 
                if   (GetStyle()   &   DS_NOIDLEMSG) 
                    dwFlags   |=   MLF_NOIDLEMSG; 
                VERIFY(RunModalLoop(dwFlags)   ==   m_nModalResult); //进入消息循环 
            } 


  ....... 
        } 
    } 
    ......   释放资源等 



原来,DoModal   并不使用   DialogBox   直接调出对话框,而是通过创建无模式对话框并维护消息循环的方式(RunModalLoop)来模拟模式对话框的效果。(看起来好像有点像DialogBox   的内部作业方式)MLF_SHOWONIDLE   是什么?看英文的意思是在Idle   的时候ShowWindow。那么是不是这样呢?好吧,为了探个究竟,让我们进入RunModalLoop。RunModalLoop在WinCore.CPP中定义。打开WinCore.CPP   并找到   RunModalLoop,   会看到以下的语句 


BOOL   bShowIdle   =   (dwFlags   &   MLF_SHOWONIDLE)   &&   !(GetStyle()   &   WS_VISIBLE); 


条件 dwFlags   &   MLF_SHOWONIDLE   始终为TRUE。   而 !(GetStyle()   &   WS_VISIBLE)只有在WS_VISIBLE属性没有设置的时候才会为   TRUE。这样,当我们去掉Visible   属性后 bShowIdle 就为   TRUE   了。再往下,就会看到以下的调用 


    while   (bIdle   && 
      !::PeekMessage(pMsg,   NULL,   NULL,   NULL,   PM_NOREMOVE)) 
    { 
      ASSERT(ContinueModal()); 


      //   show   the   dialog   when   the   message   queue   goes   idle 
      if   (bShowIdle)              //   找到了 
      { 
        ShowWindow(SW_SHOWNORMAL); 
        UpdateWindow(); 
        bShowIdle   =   FALSE;  // 指示下一次Idle   时不用显示对话框了 
      } 
While   里的条件是消息队列里再也没有任何消息了。此时,由于 bShowIdle 为 TRUE ,就会调用 ShowWindow 来显示对话框。由于 ShowWindow 只执行一次,所以如果能截获第一次WM_SHOWWINDOW消息,   就能控制了隐藏了。 


是的。在 CTestDlg 处理   WM_SHOWWINDOW 并添上以下代码 


void   CTestDlg::OnShowWindow(BOOL   bShow,   UINT   nStatus) 



  if(   GetStyle()   &   WS_VISIBLE   )   { 
    CDialog::OnShowWindow(bShow,   nStatus); 
  }   else   { 
    long   Style   =   ::GetWindowLong(*this,   GWL_STYLE); 
    ::SetWindowLong(*this,   GWL_STYLE,   Style   |   WS_VISIBLE); 
    CDialog::OnShowWindow(SW_HIDE,   nStatus); 
  } 

再运行一下,哈哈,对话框不见了,连闪都不闪一下。细心的读者也许会问为什么使用SetWindowLong,而不是   ModifyStyle,   其实是为了加快速度,因为 ModifyStyle 内部还要调用 GetWindowLong 和 SetWindowPos。到此为止,一个简单,完满的解决方法已经展现在大家面前了。 


其实,本来 MS 可以做的更好,比如把 GetStyle() 声明为虚函数,使得我们能返回WS_VISIBLE   来控制 bShowIdle 成为   FALSE,   或者把 


                DWORD   dwFlags   =   MLF_SHOWONIDLE; 


改成 


  DWORD   dwFlags   =     ShowOnIdle();     //   声明为虚函数 




希望MS能在以后的版本中考虑这个问题。 
 
 




//在app中加一对话框指针   
        CTest01Dlg   *m_pMainDlg;   
          
        //修改app的InitInstance()不要用domodal()显示对话框   
        BOOL   CTest01App::InitInstance()   
        {   
          AfxEnableControlContainer();   
          
        #ifdef   _AFXDLL   
          Enable3dControls();   //   Call   this   when   using   MFC   in   a   shared   DLL   
        #else   
          Enable3dControlsStatic();   //   Call   this   when   linking   to   MFC   statically   
        #endif   
          
          m_pMainDlg   =   new   CTest01Dlg();   //   Zxm   
          m_pMainWnd   =   m_pMainDlg;   
          if   (!m_pMainDlg-> Create(IDD_TEST01_DIALOG))   
          return   FALSE;   
          m_pMainDlg-> ShowWindow(SW_MINIMIZE);   
          m_pMainDlg-> ShowWindow(SW_HIDE);   
          m_pMainDlg-> UpdateWindow();   
          
          return   TRUE;   
        }   
        //释放指针   
        int   CTest01App::ExitInstance()   //   Zxm   
        {   
          delete   m_pMainDlg;   
          
          return   CWinApp::ExitInstance();   
        }   
        //在对话框退出时要destorywindow   
        void   CTest01Dlg::OnOK()   
        {   
          CDialog::OnOK();   
          DestroyWindow();   //   Zxm   
        }   
          
        void   CTest01Dlg::OnCancel()   
        {   
          CDialog::OnCancel();   
          DestroyWindow();   //   Zxm   
        }   
 
 




 vc开始隐藏界面
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值