MFC窗口程序啓動時最小化到托盤、不在任務欄中顯示、顯示時在右小角

轉自:http://www.cnblogs.com/watchdatalearn2012620/archive/2013/04/17/3025482.html

原文地址: http://hi.baidu.com/biboheart/item/5d17f8068c1c8a9c3c42e2dc

第一步:窗口最小化到托盤,顯示圖標。

       這一步在網上一搜,真的很多文章,基本上都可以用吧。有的是在OnSize中最化時畫圖標,隱藏窗口;有的是在初始化時畫圖標,在OnSysCommand中判斷最大化和最小化時進行窗口顯示隱藏。我選擇了後者。一開始在後面的步驟遇到了麻煩,最後第二種方法完成了。諒沒再去試第一種方法。在OnSysCommand中顯示隱藏,效果挺好的。

       我的開發環境是VS2008,創建一個對話框應用程序,選中包含最小化框(因爲要最小化到托盤)。因爲我的程序只是設計成在屏幕右小角顯示一個小窗口來開啓、停止、配置服務的一些操作。所以不要最大化功能。

       1、XXXDlg.h中聲明一個方法用作顯示托盤圖標。void _fnToTray();

             XXXDlg.cpp中實現如下

             //在桌面右下角顯示托盤圖標 
             void CXXXDlg::_fnToTray() 
             { 
                    NOTIFYICONDATA nid; 
                    nid.cbSize = sizeof( NOTIFYICONDATA ); 
                    nid.hWnd = m_hWnd; 
                    nid.uID = IDR_MAINFRAME; 
                    nid.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP; 
                    nid.uCallbackMessage = WM_SYSTEMTRAY; 
                    nid.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
                    wcscpy_s(nid.szTip, _T("服務管理器")); 
                    ::Shell_NotifyIcon(NIM_ADD,&nid ); 
             }

       2、修改CXXXDlg::OnSysCommand(UINT nID, LPARAM lParam)方法,橙色爲增加的代碼

             void CXXXDlg::OnSysCommand(UINT nID, LPARAM lParam) 
             { 
                    if ((nID & 0xFFF0) == IDM_ABOUTBOX) 
                    { 
                            CAboutDlg dlgAbout; 
                            dlgAbout.DoModal(); 
                    } 
else if(nID == SC_MAXIMIZE) //最大化 
                    { 
                            this->ShowWindow(SW_SHOW); 
                    } 
                    else if(nID == SC_MINIMIZE) //最小化,把他隱藏起來 
                    { 
                            this->ShowWindow(SW_HIDE); 
                    } 
                    else 
                    { 
                            CDialog::OnSysCommand(nID, lParam); 
                    } 
             }

      3、在資源中新建一個菜單資源,我這裏爲IDR_MENU1,在菜單中添加一個子菜單,設ID爲ID_EXIT,文字爲

          “退出”。

      4、在targetver.h文件中,最後添加一行#define  WM_SYSTEMTRAY WM_USER+1

      5、在XXXDlg.h文件中,添加方法聲明:

            afx_msg LRESULT OnSystemTray(WPARAM wParam, LPARAM lParam);

      6、在XXXDlg.cpp文件中,BEGIN_MESSAGE_MAP(CXXXDlg,CDialog)和END_MESSAGE_MAP()之間增加

            ON_MESSAGE(WM_SYSTEMTRAY,OnSystemTray)

      7、在XXXDlg.cpp文件中,實現方法:

            LRESULT CXXXDlg::OnSystemTray(WPARAM wParam, LPARAM lParam) 
            { 
                   if ( wParam = IDR_MAINFRAME ) 
                   { 
                            switch( lParam ) 
                            { 
                            case WM_LBUTTONDOWN:            //左鍵點擊托盤圖標顯示窗口 
                                     this->ShowWindow(SW_NORMAL); 
                                     break; 
                            case WM_RBUTTONDOWN:           //右鍵點擊托盤圖標顯示菜單 
                                     CMenu menu; 
                                     menu.LoadMenu(IDR_MENU1); 
                                     POINT pt; 
                                     ::GetCursorPos(&pt); 
                                     menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTALIGN, pt.x, pt.y, this); 
                                     break; 
                            } 
                   } 
                   return 1; 
            }

8、聲明右鍵菜單:在XXXDlg.h中聲明afx_msg void OnExit();

       9、在XXXDlg.cpp中BEGIN_MESSAGE_MAP(CXXXDlg,CDialog)和END_MESSAGE_MAP()之間增加

             ON_COMMAND(ID_EXIT,OnExit)

       10、在XXXDlg.cpp中實現退出

               void CXXXDlg::OnExit() 
               { 
                        this->PostMessageW(WM_QUIT); 
               }

       11、在程序的OnDestroy()消息中移除圖標



               void CXXXDlg::OnDestroy() 
               { 
                        CDialog::OnDestroy();

                        // TODO: 在此處添加消息處理程序代碼 
                        NOTIFYICONDATA nid; 
                        nid.cbSize = sizeof( NOTIFYICONDATA ); 
                        nid.hWnd = m_hWnd; 
                        nid.uID = IDR_MAINFRAME; 
                        nid.uFlags = 0; 
                        ::Shell_NotifyIcon( NIM_DELETE,&nid ); 
               }

        12、一切準備好了。在CXXXDlg::OnInitDialog()中添加

                _fnToTray();

//-----------------------氣泡窗體-----------------------------------

void CTimingDlg::ShowInfo() 

m_Htnd.cbSize = sizeof(NOTIFYICONDATA); 
m_Htnd.hWnd = GetSafeHwnd(); 
m_Htnd.uFlags = NIF_INFO; 
m_Htnd.uID=IDR_MAINFRAME; 
m_Htnd.dwInfoFlags=1; 
m_Htnd.uTimeout = 3000; 
wcscpy(m_Htnd.szInfoTitle,_T("氣泡標題")); 
wcscpy(m_Htnd.szInfo,_T("氣泡內容")); 
Shell_NotifyIcon(NIM_MODIFY,&m_Htnd); 
}

//-----------------------------------------------------------------

第二步:在屏幕右下角顯示窗口

       這步代碼很少,實現起來簡單。

       1、在CXXXDlg.h中聲明一個方法void _fnShowRBOfWindow();

       2、實現在CXXXDlg.cpp中

//在桌面右下角顯示 
void CCCRFIDServiceManagerDlg::_fnShowRBOfWindow() 

 // 獲得桌面大小 
 CRect rectWorkArea; 
 SystemParametersInfo(SPI_GETWORKAREA,0,&rectWorkArea,SPIF_SENDCHANGE); 
 // 獲得對話框大小 
 CRect rectDlg; 
 GetWindowRect(&rectDlg); 
 int nW = rectDlg.Width(); 
 int nH = rectDlg.Height(); 
 // 將窗口設置到右下角 
 SetWindowPos(NULL,rectWorkArea.right-nW,rectWorkArea.bottom-nH,nW,nH,SWP_NOSIZE); 
}

        3、在CXXXDlg::OnInitDialog()中添加

_fnShowRBOfWindow();

這樣就實現了程序窗口顯示在桌面右下角

第三步:實現程序啓動時無窗口、任務欄不顯示。只有在托盤顯示了一個圖標。

       這一步如果只是在CXXXDlg.cpp的某處調用ShowWindow(SW_HIDE),不容易實現,實現了也不能得到好的效果,有的會閃一下。最後試下以下方法,運行起來效果挺好。

       1、在CXXXApp.h中添加一個變量:CWnd m_wndOwner;

       2、在CXXXApp.cpp::InitInstance()中修改添加(橙色爲修改內容):

BOOL CCCRFIDServiceManagerApp::InitInstance() 

 // 如果一個運行在 Windows XP 上的應用程序清單指定要 
 // 使用 ComCtl32.dll 版本 6 或更高版本來啓用可視化方式, 
 //則需要 InitCommonControlsEx()。否則,將無法創建窗口。 
 INITCOMMONCONTROLSEX InitCtrls; 
 InitCtrls.dwSize = sizeof(InitCtrls); 
 // 將它設置爲包括所有要在應用程序中使用的 
 // 公共控件類。 
 InitCtrls.dwICC = ICC_WIN95_CLASSES; 
 InitCommonControlsEx(&InitCtrls);

CWinApp::InitInstance();

AfxEnableControlContainer();

// 標準初始化 
 // 如果未使用這些功能並希望減小 
 // 最終可執行文件的大小,則應移除下列 
 // 不需要的特定初始化例程 
 // 更改用於存儲設置的註冊表項 
 // TODO: 應適當修改該字符串, 
 // 例如修改爲公司或組織名 
 SetRegistryKey(_T("應用程序嚮導生成的本地應用程序"));

if ( m_wndOwner.m_hWnd == NULL ) 
 { 
  LPCTSTR pstrOwnerClass = AfxRegisterWndClass(0);

  if ( !m_wndOwner.CreateEx(0, pstrOwnerClass, _T(""),  //創建一個隱藏的彈出樣式的窗口 
         WS_POPUP, CW_USEDEFAULT, 
         CW_USEDEFAULT, 
         CW_USEDEFAULT, 
         CW_USEDEFAULT, 
         NULL, 0) ) 
  return FALSE; 
 }

CXXXDlg dlg(&m_wndOwner); 
 m_pMainWnd = &dlg; 
 INT_PTR nResponse = dlg.DoModal(); 
 if (nResponse == IDOK) 
 { 
  // TODO: 在此放置處理何時用 
  //  “確定”來關閉對話框的代碼 
 } 
 else if (nResponse == IDCANCEL) 
 { 
  // TODO: 在此放置處理何時用 
  //  “取消”來關閉對話框的代碼 
 } 
 if (m_wndOwner.m_hWnd != NULL) 
 { 
  m_wndOwner.DestroyWindow(); 
 }

// 由於對話框已關閉,所以將返回 FALSE 以便退出應用程序, 
 //  而不是啓動應用程序的消息泵。 
 return FALSE; 
}

       3、編輯CXXX.rc()查看代碼編輯。找到EXSTYLE WS_EX_APPWINDOW刪除。

       4、在CXXXDlg.cpp::OnInitDialog()中添加(在CXXXDlg.h中添加變量WINDOWPLACEMENT m_wp)

m_wp.length = sizeof(WINDOWPLACEMENT); 
 GetWindowPlacement(&m_wp);  //恢復時用 
 WINDOWPLACEMENT wp; 
 wp.length = sizeof(WINDOWPLACEMENT); 
 wp.flags = WPF_RESTORETOMAXIMIZED; 
 wp.showCmd = SW_HIDE; 
 SetWindowPlacement(&wp);

在第一步中的OnSystemTray(WPARAM wParam, LPARAM lParam)修改如下:

LRESULT CCCRFIDServiceManagerDlg::OnSystemTray(WPARAM wParam, LPARAM lParam) 

    if ( wParam = IDR_MAINFRAME ) 
    { 
        switch( lParam ) 
        { 
        case WM_LBUTTONDOWN: 
            this->ShowWindow(SW_NORMAL); 
SetWindowPlacement(&m_wp); 
            break; 
        case WM_RBUTTONDOWN: 
            CMenu menu; 
            menu.LoadMenu(IDR_MENU_RBUTTON); 
            POINT pt; 
            ::GetCursorPos(&pt); 
            menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTALIGN, pt.x, pt.y, this); 
            break; 
        } 
    } 
    return 1; 
}


發佈了51 篇原創文章 · 獲贊 14 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章