對話框托盤程序實現

對於不需要佔據太多屏幕資源的後臺程序,最好的處理方法就是使用系統的托盤,在托盤顯示一個圖標,必要時通過其激活主窗口。本文介紹對話框托盤圖表的實現方法並附源碼。
      托盤程序的設計主要滿足以下幾個需求:
             (1)程序啓動時主窗口隱藏,只在托盤顯示圖標;
             (2)主窗口隱藏時,在任務欄沒有圖標顯示;
             (3)在托盤圖標點擊右鍵彈出,菜單用來恢復、隱藏、退出程序。
實現托盤程序主要涉及一個shell函數Shell_NotifyIcon和一個用來描述托盤圖標信息的結構體NOTIFYICONDATA。
 
Shell_NotifyIcon函數

  函數Shell_NotifyIcon()用於在托盤上增加、刪除或修改圖標。其原型爲:
WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage,PNOTIFYICONDATA pnid);

Pnid是一個指向NOTIFYICONDATA結構的指針。
dwMessage是被傳遞的消息,可以是以下消息之一:
NIM_ADD:      在托盤上添加圖標 ;
NIM_DELETE:刪除托盤上的圖標;
NIM_MODIFY:修改托盤上的圖標 。
NOTIFYICONDATA結構

   NOTIFYICONDATA結構包含了系統用來處理托盤圖標的信息,它包括選擇的圖標、回調消息、提示消息和圖標對應的窗口等內容。其定義爲:
typedef struct  _NOTIFYICONDATA
{
      DWORD cbSize;               //以字節爲單位的這個結構的大小
      HWND hWnd;                  //接收托盤圖標通知消息的窗口句柄
      UINT uID;                         //應用程序定義的該圖標的ID號
      UINT uFlags;                    //設置該圖標的屬性
      UINT uCallbackMessage;    //應用程序定義的消息ID號,此消息傳遞給hWnd
      HICON hIcon;                       //用來添加、刪除、修改圖標的句柄
      char szTip[64];                    //鼠標停留在圖標上顯示的提示信息
} NOTIFYICONDATA, *PNOTIFYICONDATA;
該結構中,成員uFlags可以是下列的組合或其中之一:
                               NIF_ICON:設置成員hIcon有效
                              NIF_MESSAGE:設置成員uCallbackMessage有效
                              NIF_TIP:設置成員szTip有效

對話框托盤圖標程序

   在IcoTrayDlg.h 中定義返回消息ID, #define MYWM_NOTIFYICON WM_USER+100。在CIcoTrayDlg類中加入NOTIFYICONDATA結構的成員變量m_NotiIcon。並在其OnInitDialog函數中加入初始化該結構體的代碼:
        m_NotiIcon.cbSize=sizeof(NOTIFYICONDATA);
        m_NotiIcon.hWnd=this->m_hWnd;
        m_NotiIcon.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP;
       m_NotiIcon.uCallbackMessage=MYWM_NOTIFYICON;   //用戶定義的回調消息
       CString szToolTip =_T("托盤實例");
       _tcscpy(m_NotiIcon.szTip, szToolTip);
      m_NotiIcon.uID=IDR_MAINFRAME;
      HICON  hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
      m_NotiIcon.hIcon=hIcon;
      ::Shell_NotifyIcon(NIM_ADD,&m_NotiIcon);
      if(hIcon)::DestroyIcon(hIcon);   
      
消息響應  
      
     添加了以上的代碼之後我們完成了在托盤上添加圖標。但是單擊圖標對話框沒有相應的響應。這是因爲我們還沒有處理我們定義的返回消息。爲了處理圖標返回的左鍵雙擊鼠標消息和右鍵單擊鼠標消息,我們需要重載WindowProc()函數。以及爲了不讓對話框最小化時圖標不在任務欄上出現,我們還需要在在此函數中處理最小化的系統消息。
  在IcoTrayDlg.h 中添加重載定義LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
在IcoTrayDlg.cpp中定義
LRESULT CIcoTrayDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
  switch(message)
  {
     case MYWM_NOTIFYICON://如果是用戶定義的消息
    if(lParam==WM_LBUTTONDBLCLK)
       {       //鼠標雙擊時主窗口出現
     AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);
     }
    else if(lParam==WM_RBUTTONDOWN)
    { //鼠標右鍵單擊彈出選單
      CMenu menu;
      menu.LoadMenu(IDR_RIGHT_MENU); //載入事先定義的選單
      CMenu* pMenu=menu.GetSubMenu(0);
      CPoint pos;
      GetCursorPos(&pos);
      pMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,pos.x,pos.y,
                                               AfxGetMainWnd() );
    }
    break;
    case WM_SYSCOMMAND://如果是系統消息
    if(wParam==SC_MINIMIZE)
    {
     //接收到最小化消息時主窗口隱藏
     AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);
     return 0;
    }
    break;
 }
 return CWnd::WindowProc(message, wParam, lParam);
}
     
右鍵菜單
   
在此之前我們還需要添加一個ID爲IDR_RIGHT_MENU的菜單,這個菜單應該包括:打開、隱藏、退出等基本功能。在ClclTrayDlg中添加事件響應。
//右鍵菜單消息事件處理函數
void CIcoTrayDlg::OnAppOpen()
{
     AfxGetApp()->m_pMainWnd->ShowWindow(SW_SHOW);  //點擊"打開"時顯示對話框
}
void CIcoTrayDlg::OnAppHide()
{
  AfxGetApp()->m_pMainWnd->ShowWindow(SW_HIDE);  //在點擊“隱藏”時隱藏對話框
}
void CIcoTrayDlg::OnAppExit()
{
  ::PostMessage(m_hWnd,WM_QUIT,0,0); //在點擊“退出”時退出程序
}
      爲使應用程序退出時去掉托盤上的圖標,我們需要映射WM_DESTROY消息並在其響應函數在OnDestroy()函數中加入:
::Shell_NotifyIcon(NIM_DELETE,&&m_tnid);
啓動隱藏對話框     
     
     一般的後臺程序程序啓動時不需要彈出對話框,只有在用戶需要時候才雙擊托盤圖標彈出對話框。啓動隱藏對話框的方法有多種這裏使用了比較簡單的一種即不繪製窗口。當對話框顯示時將要響應消息WM_PAINT繪製客戶區,相應消息WM_NCPAINT繪製窗口邊框。我們在窗口第一次自繪自身時隱藏窗口,可以收到比較良好的效果。由於窗口是先畫窗口邊框,所以我們僅需處理WM_NCPAINT即可。代碼如下:
//隱藏窗口
void CIcoTrayDlg::OnNcPaint()
{
     CDialog::OnNcPaint()
     static int i = 2;
     if(i > 0)
    {
        i --;
       ShowWindow(SW_HIDE);
    }
    else
   {
     CDialog::OnNcPaint();
    }
}
爲什麼要定義靜態變量i而且設其值爲2呢?
     我們只要窗口隱藏第一次,所以定義這個變量可以判斷是否時首次顯示窗口。當程序開始運行時,系統發送SendMessageWM_NCPAINT消息,此時程序的窗口邊框應該被顯示,但是此時我們沒有作任何顯示的操作,而是將窗口隱藏,ShowWindow(SW_HIDE)將把窗口的 WS_VISIBLE屬性去掉,繼續執行,程序將檢查WS_VISIBLE屬性,如果沒有則顯示窗口,所以又發送了一個WM_NCPAINT消息。所以我們要處理兩次WM_NCPAINT消息。在需要窗口顯示時,調用ShowWindow(SW_SHOW)即可。程序執行的結果是,原來處於激活狀態的窗口可能會閃動兩下,然後仍然處於激活狀態。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章