[搬家帖]VC系統托盤編程指南

來源:互聯網
上載者:User

    現在比較流行的軟體都會在系統托盤上顯示一個表徵圖,左鍵點擊該表徵圖時可以顯示/隱藏軟體主介面,節省工作列的空間;右鍵點擊該表徵圖會出現一個菜單,顯示一些常用的功能。那麼這是怎麼實現的呢?其實很簡單,只需要一個API函數就搞定了,跟我一起看吧~
    首先看一個結構體:
    typedef struct _NOTIFYICONDATA {
        DWORD cbSize;
        HWND hWnd;
        UINT uID;
        UINT uFlags;
        UINT uCallbackMessage;
        HICON hIcon;
        TCHAR szTip[64];
        DWORD dwState; //Version 5.0
        DWORD dwStateMask; //Version 5.0
        TCHAR szInfo[256]; //Version 5.0
        union {
            UINT  uTimeout; //Version 5.0
            UINT  uVersion; //Version 5.0
        } DUMMYUNIONNAME;
        TCHAR szInfoTitle[64]; //Version 5.0
        DWORD dwInfoFlags; //Version 5.0
    } NOTIFYICONDATA, *PNOTIFYICONDATA;
    使用該結構指定托盤表徵圖的相關資訊,其中Version 5.0的部分表示的是Shell DLL的版本號碼,可以用DllGetVersion獲得當前系統的DLL版本。出於相容的考慮,該部分很少使用。
    cbSize: NOTIFYICONDATA結構的大小,sizeof(NOTIFYICONDATA)
    hWnd:接收托盤通知的視窗控制代碼
    uID:托盤表徵圖的ID號,該ID與hWnd一起唯一標識了一個托盤表徵圖的身份,因此該ID號不能重複,一般使用與該表徵圖相關聯的菜單的ID
    uFlags:為下列值的組合
    NIF_ICON:表示結構中的hIcon有效 
    NIF_MESSAGE:表示結構中的uCallbackMessage有效
    NIF_TIP:表示結構中的szTip有效
    NIF_STATE:表示結構中的dwState和dwStateMask有效
    NIF_INFO:使用氣球型的托盤提示代替傳統的方框型托盤提示.結構中的szInfo, uTimeout, szInfoTitle,和dwInfoFlags有效
    uCallbackMessage:托盤訊息,當托盤地區有滑鼠事件(如滑鼠移動,單擊等)產生時,會向接收視窗發送該訊息,進行相應的處理
    hIcon:托盤表徵圖控制代碼
    szTip:托盤提示字元

    好了,就介紹這麼多,下面接收這個API函數Shell_NotifyIcon:
    BOOL Shell_NotifyIcon(
        DWORD dwMessage,
        PNOTIFYICONDATA pnid
    );
    dwMessage:為下列值之一
        NIM_ADD:添加托盤表徵圖
        NIM_DELETE:刪除圖盤表徵圖
        NIM_MODIFY:修改托盤表徵圖
        NIM_SETFOCUS:Version 5.0
        NIM_SETVERSION:Version 5.0
        pnid:NOTIFYICONDATA結構的指標

    好了,下面言歸正傳,開始著手編程了~
    我們分為以下幾步逐步分析:
        初始化
        添加/修改/移除表徵圖
        添加托盤訊息響應函數
        添加菜單訊息處理函數
    (1)初始化
    首先要聲明一個NOTIFYICONDATA成員變數:
    NOTIFYICONDATA m_nid;
    然後在資源面板中添加一個菜單資源IDR_TRAYMENU和一個表徵圖資源IDI_RED
由於我們要處理滑鼠訊息,因此先定義一個使用者自訂訊息:
    #define UM_ TRAYNOTIFICATION (WM_USER+100)
    然後對該結構的成員進行初始化:
    void InitTray()
    {
          //初始化m_nid
          m_nid.cbSize = sizeof(NOTIFYICONDATA);
          m_nid.hWnd = this->m_hWnd;
          m_nid.uID = IDR_TRAYMENU;
          m_nid.uFlags = NIF_ICON|NIF_TIP|NIF_MESSAGE;
          m_nid.hIcon = AfxGetApp()->LoadIcon(IDI_RED);
          strcpy (m_nid.szTip, "我的托盤聽我的");
          m_nid.uCallbackMessage = UM_TRAYNOTIFICATION;
    }
    上面的程式我就不多說了,相信大家都能看懂。
    (2)添加/修改/移除表徵圖
    這個更簡單,直接調用Shell_NotifyIcon函數就可以了:
    //向托盤添加表徵圖
    void AddTray()
    {
          Shell_NotifyIcon(NIM_ADD, &m_nid);
    }
    //移除托盤表徵圖,在程式退出時一定要記得調用,否則表徵圖會殘留在托盤上
    void RemoveTray()
    {
          Shell_NotifyIcon(NIM_DELETE, &m_nid);
    }
    //修改表徵圖,QQ登陸時托盤上的動態效果不用我教了吧
    void ModifyTray(UINT uId)//參數為要顯示的Icon的ID號
    {
          m_nid.hIcon = AfxGetApp()->LoadIcon(uId);
          Shell_NotifyIcon(NIM_MODIFY, &m_nid);
    }
    (3)添加托盤訊息響應函數
    這個其實就是響應自訂訊息,忘了?好,那我們一起複習一下吧~
    首先定義訊息標識符(第1步已經定義過了):
    #define UM_ TRAYNOTIFICATION (WM_USER+100)
    然後在標頭檔的DECLARE_MESSAGE_MAP()之前定義訊息響應函數:
    afx_msg LRESULT OnTrayNotification(WPARAM wId, LPARAM lEvent);
    其中兩個參數分別為表徵圖ID號和滑鼠事件
    最後在cpp檔案裡實現該函數:
    LRESULT CXXXDlg::OnTrayNotification(WPARAM wId, LPARAM lEvent)
    {
          if(wId!=m_nid.uID
           || (lEvent!=WM_LBUTTONUP && lEvent!=WM_RBUTTONUP))
           return 0;

          //載入菜單
          CMenu menu;
          if(!menu.LoadMenu(wId))
               return 0;
          //擷取快顯功能表
          CMenu *pSubMenu = menu.GetSubMenu(0);
          if(!pSubMenu)
               return 0;

          if(lEvent == WM_RBUTTONUP)
          {
                //設定預設功能表項目
                ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);

                //擷取滑鼠位置
                CPoint mouse;
                GetCursorPos(&mouse);

                //設定捷徑功能表
                ::SetForegroundWindow(m_nid.hWnd);
                ::TrackPopupMenu(pSubMenu->m_hMenu, 0, mouse.x, mouse.y, 0, m_nid.hWnd, NULL);
          }
          else
          {
                ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->GetMenuItemID(0), 0);
          }

          return 1; 
    }
    下面逐句解釋上面這段代碼:
    首先判斷髮送該訊息的表徵圖的ID是否等於m_nid中的ID號,再判斷接收到的滑鼠訊息是否為左鍵單擊訊息WM_LBUTTONUP或按右鍵訊息WM_RBUTTONUP,如果不是則不對該訊息進行響應。
    然後載入菜單,按右鍵時顯示該菜單。先用LoadMenu()載入頂層菜單,再用GetSubMenu()獲得一級子功能表。
當滑鼠事件為按右鍵時,顯示菜單,否則(即左鍵單擊時)用::SendMessage()向接收視窗發送命令訊息,進行相應的處理。::SetMenuDefaultItem()用於設定菜單的預設選擇項,以粗體顯示。最後用::TrackPopupMenu()函數顯示右鍵菜單。該菜單可能不會像通常那樣馬上消失,這是因為從快顯功能表接收訊息的視窗必須是前景視窗。調用::SetForegroundWindow()函數就可以糾正該錯誤。
    (4)添加菜單訊息處理函數
    在右鍵菜單中選擇一項後,就會發送命令訊息WM_COMMAND,在ClassWizard裡添加WM_COMMAND的訊息處理函數:
    BOOL CZYJReportDlg::OnCommand(WPARAM wParam, LPARAM lParam)
    {
          // TODO: Add your specialized code here and/or call the base class
          switch(LOWORD(wParam))
          {
          case ID_SHOWHIDE:
                ShowWindow(m_bShow?SW_HIDE:SW_SHOW);
                m_bShow = !m_bShow;
                break;
          case ID_EXIT:
                RemoveTray();
                PostQuitMessage(0);
                break;
          case ID_ABOUT:
                CAboutDlg about;
                about.DoModal();
                break;
          }

          return CDialog::OnCommand(wParam, lParam);
    }
    其中第一個參數wParam的低位元組LOWORD(wParam)標識了所選子功能表的ID,根據所選的功能表項目執行相應的程式。
     OK,以上介紹了寫托盤程式的完整過程,是不是很簡單呢?當然托盤編程的內容還遠不止這些,比如Version 5.0的部分,還可以添加很多漂亮的效果,歡迎大家跟我一起探討!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.