最近需要做一個主窗體常態隱藏的程序,類似360衛士那樣,只有托盤圖標常顯示。本以為隱藏主窗體很簡單,但遇到了意想不到的情況。
無效的做法
最初的想法是設置主對話框資源的 Visiable 屬性為 false, 並在OnInitDialog函數里調用 ShowWindow(SW_HIDE) ,發現這些操作根本沒有作用,對話框還是好好的顯示在那里。開始還以為是改錯了項目,或者當前啟動項目設置錯了,檢查了一遍,確認沒錯,只好開始百度。
最初發現的解決方法是在OnInitDialog函數中執行以下代碼:
SetWindowPos(&wndNoTopMost,0,0,0,0,SWP_HIDEWINDOW); ModifyStyleEx(WS_EX_APPWINDOW,WS_EX_TOOLWINDOW);//移除任務欄圖標顯示 ShowWindow(SW_HIDE);
結果是窗體的大部分隱藏了,還剩了點沒隱藏,就是下圖這個要死不活的樣子

既然還剩了一部分,那我就把對話框資源的 Caption 屬性為空,SystemMenu屬性設置為false,結果文字和關閉按鈕確實都不見了,但還是剩下了一些東西,就是下圖中的小長條

只能繼續研究。
有效的做法
1 將界面像素置為0,移動界面至屏幕角落
int nFullWidth = GetSystemMetrics(SM_CXSCREEN); int nFullHeight = GetSystemMetrics(SM_CYSCREEN); SetWindowPos(NULL, nFullWidth, nFullHeight, 0, 0, SWP_NOZORDER); //設置0像素,移到最角落 或者:MoveWindow(0,0,0,0); ShowWindow(SW_HIDE); ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); //移除任務欄圖標顯示
這種做法只是將上述的小長條移到了不易看到的地方,用戶一旦操作界面的任一部位,窗口都會因為失活而不再顯示,達到了隱藏界面的目的。但是這種做法明顯屬於湊合,而且一旦需要顯示主界面,還需要將對話框的類型改回來,不能為工具窗口,否則任務欄不顯示。
2 采用定時器,在窗口初始化完成后馬上隱藏
在OnInitDialog中創建一個定時器SetTimer(1,1,NULL);
然后在OnTimer函數中調用ShowWindow(SW_HIDE)
這種做法的缺點就是窗口會閃爍一次,而且這種手法太野路子,不優雅。
3 響應WM_NCPAINT消息
在第一次處理WM_NCPAINT消息是,調用ShowWindow(SW_HIDE)方法,之所以只調用一次,是為了之后可以將主窗口再顯示出來。
這種方法比較優雅,推薦采用
void CMFCApplication1Dlg::OnNcPaint() { // TODO: 在此處添加消息處理程序代碼 static bool bNotPaint = true; if (bNotPaint) { ShowWindow(SW_HIDE); bNotPaint = false; } else { CDialogEx::OnNcPaint(); } }
4 改變主窗體的創建方式
將 C***App::InitInstance() 函數中的代碼
CMFCApplication1Dlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal();
替換為
CMFCApplication1Dlg dlg; m_pMainWnd = &dlg; //INT_PTR nResponse = dlg.DoModal(); INT_PTR nResponse = dlg.Create(CMFCApplication1Dlg::IDD); dlg.ShowWindow(SW_HIDE); dlg.RunModalLoop();
同樣比較優雅,推薦使用
綜上所述,由於CDialog的創建隱藏了太多細節,只有弄清楚基於Dialog的窗體的創建方式、繪制時機、消息循環方式才能夠優雅的實現功能,當然,我還沒有弄明白。
