乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      VC++6.0中實現(xiàn)將應用程式的圖標加入到視窗系統(tǒng)的系統(tǒng)托盤中

       冉亮 2010-09-05
      摘要
        本文對怎么將應用程式的圖標加入到視窗系統(tǒng)的系統(tǒng)托盤中做了較為周詳?shù)慕榻B,
        然后給出了一個C++類以方便的實現(xiàn)該功能,并在VC++6.0中給出了一個應用程式
        實例來體現(xiàn)其具體實現(xiàn)過程。同時該應用程式實例還講解了怎么在托盤中實現(xiàn)動
        畫圖標及在程式中關(guān)閉計算機的技術(shù)。

        關(guān)鍵詞:系統(tǒng)托盤 動畫圖標

        視窗系統(tǒng)98桌面的系統(tǒng)托盤位于任務欄的右側(cè),即視窗系統(tǒng)98桌面的右下方。他常
        用來顯示一些系統(tǒng)的狀態(tài)。如:系統(tǒng)時間,音量控制及其他的一些圖標(依個
        人機器安裝的軟件而不定),如下圖為筆者的視窗系統(tǒng)98系統(tǒng)托盤。(圖略)

        常常能見到一些優(yōu)秀的軟件在運行后會將其應用程式圖標加入到系統(tǒng)托盤中,如
        金山詞霸。如果能將自己編寫的應用程式的圖標也加入到系統(tǒng)托盤中,將會使你
        的程式顯得非常有專業(yè)水準。

        其實這并不困難,和系統(tǒng)托盤通信的函數(shù)只有一個:

      Shell_NotifyIcon (UINT message, NOTIFYICONDATA &m_nid);

        首先看一下該函數(shù)的兩個參數(shù)。
        第一個參數(shù)message能取以下值:

      NIM_ADD     向托盤中加入一個圖標;
      NIM_MODIFY   修改托盤中的圖標
      NIM_DELETE   從托盤中刪除一個圖標

        第二個參數(shù)m_nid是NOTIFYICONDATA結(jié)構(gòu)的一個引用。該結(jié)構(gòu)的原型如下:
      typedef struct _NOTIFYICONDATA
      {
      DWORD cbSize;// 結(jié)構(gòu)的大小,必須在程式中給出
      HWND hWnd;
      //是你程式中將要接收托盤消息的窗口句柄
      UINT uID;
      // 應用程式中定義的托盤圖標ID,此參數(shù)用作標識
      UINT uFlags;
      //設(shè)置屬性,低三位有意義,0--7,如下:
      //第一位//#define NIF_MESSAGE 0x1
      // uCallbackMessage參數(shù)有效

      //第二位//#define NIF_ICON  0x2 // hIcon參數(shù)有效
      //第三位//#define NIF_TIP  0x4 // szTip參數(shù)有效
                
      UINT uCallbackMessage;  
      // 自定義的消息ID值,一定不要和以有的消息ID相重。  
      HICON hIcon;
      //顯示在系統(tǒng)托盤上的Icon的句柄,能為系統(tǒng)的 IDI_WINLOGO等
      CHAR szTip[64]; // 用于圖標顯示的提示字符串
      } NOTIFYICONDATA;

        為了接收到來自托盤的通知消息你能將uCallbackMessage設(shè)定為你所定義的消息
        ID值,同時設(shè)定NIF_MESSAGE標志。這樣當用戶在你的托盤圖標上移動或按下鼠標
        時,視窗系統(tǒng)將發(fā)出消息:該消息的 messageID是你在uCallbackMessage中定義的
        值;wParam是你定義的uID值;而lParam是鼠標事件(如WM_LBUTTONDOWN),這樣你
        的應用程式就能響應該事件了。
        因此,為了將自己的應用程式加入到系統(tǒng)托盤中,首先得建立一處理托盤通知消息
        的窗口對象,然后將窗口對象和你自己的托盤通知消息聯(lián)系起來并建立相應的托盤
        通知消息映射機制,以便你的窗口對象能處理相應的事件。

        能看到結(jié)構(gòu)體NOTIFYICONDATA中,其成員變量hWnd,uID,uFlags均用于在窗口對
        象和你自己的托盤通知消息之間建立聯(lián)系,而成員變量uCallbackMessage則必須是
        對應于你的窗口對象的托盤通知消息ID值。

        于是要完成的工作有:

        (1)建立一處理托盤通知消息的窗口對象;
        (2)建立一結(jié)構(gòu)體NOTIFYICONDATA變量,并給變量的相應域賦值以在托盤通知消
             息和窗口對象之間建立聯(lián)系;
        (3)建立相應的托盤通知消息映射機制;
        (4)調(diào)用Shell_NotifyIcon函數(shù)以在系統(tǒng)托盤中加入、修改或刪除圖標;
        (5)當然別忘了在你的窗口對象中編寫相應的事件響應函數(shù)。

        因此,能編寫一C++類來實現(xiàn)以上功能以簡化編程同時提高代碼的可重用性。以
        下為該類代碼:

      class CTrayIcon : public CCmdTarget {
      protected:
        DECLARE_DYNAMIC(CTrayIcon)
        NOTIFYICONDATA m_nid;    
      // Shell_NotifyIcon 函數(shù)中的結(jié)構(gòu)參數(shù)

      public:
        CTrayIcon(UINT uID);
        ~CTrayIcon();

        // 通過調(diào)用該成員函數(shù)來接收托盤通知消息
        void SetNotificationWnd(CWnd* pNotifyWnd,
        UINT uCbMsg);

        // SetIcon 函數(shù)用來在系統(tǒng)托盤中加入、改動及刪除圖標。
        //要刪除圖標這樣調(diào)用:SetIcon(0)
        BOOL SetIcon(UINT uID);
        BOOL SetIcon(HICON hicon, LPCSTR lpTip);
        BOOL SetIcon(LPCTSTR lpResName, LPCSTR lpTip)
        {
           return SetIcon(lpResName ?
           AfxGetApp()->LoadIcon(lpResName):NULL,lpTip);
        }
        
        BOOL SetStandardIcon(LPCTSTR lpszIconName,LPCSTR lpTip)
        {
           return SetIcon(::LoadIcon(NULL,lpszIconName),lpTip);
        }

        virtual LRESULT OnTrayNotification(WPARAM uID, LPARAM lEvent);
      };

      CTrayIcon::CTrayIcon(UINT uID)
      {
        //初始化NOTIFYICONDATA結(jié)構(gòu)變量
        memset(&m_nid, 0 , sizeof(m_nid));
        m_nid.cbSize = sizeof(m_nid);
        m_nid.uID = uID;
        AfxLoadString(uID, m_nid.szTip, sizeof
        (m_nid.szTip));
      }

      CTrayIcon::~CTrayIcon()
      {
        SetIcon(0); // 從系統(tǒng)托盤中刪除圖標
      }

      // 設(shè)定通知窗口,該窗口必須已被創(chuàng)建
      void CTrayIcon::SetNotificationWnd(CWnd* pNotifyWnd, UINT uCbMsg)
      {
          ASSERT(pNotifyWnd==NULL || ::IsWindow(pNotifyWnd->GetSafeHwnd()));

          m_nid.hWnd = pNotifyWnd->GetSafeHwnd();

      ASSERT(uCbMsg==0 || uCbMsg>=WM_USER);
      m_nid.uCallbackMessage = uCbMsg;
      }

      BOOL CTrayIcon::SetIcon(UINT uID)
      {
        HICON hicon=NULL;
        if (uID) {
         AfxLoadString(uID, m_nid.szTip, sizeof(m_nid.szTip));
         hicon = AfxGetApp()->LoadIcon(uID);
        }
        return SetIcon(hicon, NULL);
      }

      //////////////////
      //
      BOOL CTrayIcon::SetIcon(HICON hicon, LPCSTR lpTip)
      {
        UINT msg;
        m_nid.uFlags = 0;

        // 設(shè)定圖標
        if (hicon) {
         // 判斷是要在系統(tǒng)托盤中增加還是要刪除圖標
         msg = m_nid.hIcon ? NIM_MODIFY : NIM_ADD;
         m_nid.hIcon = hicon;
         m_nid.uFlags |= NIF_ICON;
        } else { // 刪除圖標
         if (m_nid.hIcon==NULL)
           return TRUE;   //已被刪除
         msg = NIM_DELETE;
        }
        if (lpTip)
         strncpy(m_nid.szTip, lpTip, sizeof(m_nid.szTip));
        if (m_nid.szTip[0])
         m_nid.uFlags |= NIF_TIP;

        if (m_nid.uCallbackMessage && m_nid.hWnd)
         m_nid.uFlags |= NIF_MESSAGE;

        BOOL bRet = Shell_NotifyIcon(msg, &m_nid);
        if (msg==NIM_DELETE || !bRet)
         m_nid.hIcon = NULL;
        return bRet;
      }

      // 缺省事件處理程式,該程式處理鼠標右擊及雙擊事件。
      LRESULT CTrayIcon::OnTrayNotification(WPARAM wID,
      LPARAM lEvent)
      {
        if (wID!=m_nid.uID ||
         (lEvent!=WM_RBUTTONUP && lEvent!=WM_LBUTTONDBLCLK))
         return 0;

        // 使用和托盤圖標擁有同樣ID號的菜單作為右鍵彈出菜單
        // 并將菜單上的第一項作為缺省命令使用,
        // 缺省命令在WM_LBUTTONDBLCLK事件發(fā)生時被擊發(fā)
        //
        CMenu menu;
        if (!menu.LoadMenu(m_nid.uID))
         return 0;
        CMenu* pSubMenu = menu.GetSubMenu(0);
        if (!pSubMenu)
         return 0;

        if (lEvent==WM_RBUTTONUP) {

         //使菜單第一項為缺省項 (表現(xiàn)為粗體)
         ::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 // 雙擊事件: 執(zhí)行菜單第一項
         ::SendMessage(m_nid.hWnd, WM_COMMAND, pSubMenu->
         GetMenuItemID(0), 0);

        return 1; // 表示事件已被處理
      }

        以下以在VC++6.0中具體實現(xiàn)的程式為例。該程式將擁有以下功能:程式被執(zhí)行
        后,首先顯示一對話框表示程式開始執(zhí)行,然后該對話框消失。接著程式圖標
        被加入到系統(tǒng)托盤中,能看到,該圖標將是一動畫圖標。當鼠標在該系統(tǒng)托
        盤上右擊時,將彈出一菜單。如圖所示(略)。其第一項為缺省項命令,單擊
        將顯示應用程式。為簡化編程,該應用程式只是顯示一應用程式主窗口。而單擊
        菜單第二項將關(guān)閉機器,單擊菜單第三項將結(jié)束本程式。當并且當用戶雙擊時,
        CTrayIcon將執(zhí)行菜單上的第一項:顯示服務程式,這將擊活(顯示)TrayDemo
        (正常情況下,他是隱藏的)。而要終止TrayDemo,你得選擇結(jié)束本程式。當你
        執(zhí)行File Exit或關(guān)掉TrayDemo主窗口時,TrayDemo并沒有真正的關(guān)掉,他只不過
        隱藏起來了而已。TrayDemo 重載了Cmainframe::OnClose函數(shù)以執(zhí)行該項功能。
        首先在VC++6.0中生成用應用程式向?qū)梢粏挝募こ蘐rayDemo,然后在工程中
        加入以上的CTrayIcon類。

        要使用CTrayIcon類,你首先得實例化一個CTrayIcon類對象,TrayDemo在視圖中
        完成此項工作。以下是對應代碼:

      class CTrayDemoView : public CView {
      protected: CTrayIcon m_trayIcon;
                // my tray icon
                 .
                 .
                 .
      };

        當你實例化一個CTrayIcon類對象之后,你必須分配給其一個ID號。該ID號是此圖
        標在其生命周期內(nèi)使用的唯一一個ID號,即使在以后你改動了實際顯示的圖標。此
        ID號是當鼠標事件發(fā)生時你獲得的ID。他能不必是圖標的資源ID;在TrayDemo
        中,其值是IDR_TRAYICON,由CTrayDemoView構(gòu)造函數(shù)所初始化。
      CTrayDemoView::CTrayDemoView() :
      m_trayIcon(IDR_TRAYICON){
                 .
                 .
                 .
      }

      要增加圖標,可調(diào)用SetIcon重載函數(shù)之一
      m_trayIcon.SetIcon(IDI_MYICON); //參數(shù)為資源ID
      m_trayIcon.SetIcon("myicon");  //參數(shù)為資源名
      m_trayIcon.SetIcon(hicon); //參數(shù)為HICON句柄
      m_trayIcon.SetStandardIcon(IDI_WINLOGO);
      //加入系統(tǒng)圖標

        除了SetIcon(UINT uID)函數(shù)需要一個同樣擁有uID號的字符串資源作為提示字符串
        以外,所有這些函數(shù)都有一個可選的指向提示字符串的LPCSTR參數(shù)。例如,在
        TRAYTEST中有以下行:
      // (In TrayDemoView.cpp)
      m_trayIcon.SetIcon(IDI_RED);

        該語句在增加圖標的同時同樣設(shè)定了提示字符串,因為TrayDemo有一個同樣ID的字
        符串:如果你想改動圖標,只需再次調(diào)用其中的一個SetIcon函數(shù),只不過需要不
        同的ID或HICON。CTrayIcon類知道響應NIM_MODIFY消息而不是NIM_ADD消息。同樣
        的函數(shù)甚至能去掉圖標:
      m_trayIcon.SetIcon(0);//removeicon

        CtrayIcon類會將其解釋為NIM_DELETE事件。這么多的代碼和標志只用一個簡單的
        重載函數(shù)就予以完成,這是C++的偉大之處。
        如果要顯示動畫圖標,只需設(shè)置一定時器,然后在定時器的響應事件中調(diào)用
        SetIcon成員函數(shù)就能了。如:

      int CTrayDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
      {
      m_timerID = this->SetTimer(99,200,NULL);

      }

      void CTrayDemoView::OnTimer(UINT nIDEvent)
      {
      uChangeIcon++;
      if(uChangeIcon-IDI_RED>2)
        uChangeIcon=IDI_RED;
      m_trayIcon.SetIcon(uChangeIcon);
      CView::OnTimer(nIDEvent);
      }

        在示例程式中,有3個圖標,其ID為IDI_RED,IDI_YELLO,IDI_GREEN,且其ID值是相
        連的,因而UINT型變量uChangeIcon用來依次輪換三個圖標。這樣程式執(zhí)行以后,你
        將會看到紅、黃、綠三個交通指示燈依次閃爍。
        那么怎樣處理托盤通知呢?

        要處理托盤通知,需要在你設(shè)定圖標之前調(diào)用CTrayIcon::SetNotificationWnd函
        數(shù),當然你必須已創(chuàng)建了窗口。最適當?shù)牡胤绞窃贠nCreate函數(shù)中,在TrayDemo
        中也是這樣做的。用ClassWizard在CtrayDemoView類中加入WM_CREATE消息響應函
        數(shù)OnCreate(),并加入以下代碼:

      // Private message used for tray notifications
      #define WM_MY_TRAY_NOTIFICATION WM_USER+0
      int CTrayDemoView::OnCreate(LPCREATESTRUCT lpCreateStruct)
                  .
                  .
                  .
      m_trayIcon.SetNotificationWnd(this,WM_MY_TRAY_NOTIFICATION);
      m_trayIcon.SetIcon(IDI_RED);
      return 0;
      }

        然后進行消息注冊(REGISTER),一旦注冊以后,你就能用正常的消息映射方式
        處理托盤通知。
      BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
      ON_MESSAGE(WM_MY_TRAY_NOTIFICATION,OnTrayNotification)
      // (or ON_REGISTERED_MESSAGE)
      END_MESSAGE_MAP()

      當然不要忘了在TrayDemoView.h中加入以下語句:
      afx_msg LRESULT OnTrayNotification(WPARAM wp, LPARAM lp);

        當你的處理程式得到在托盤圖標上的鼠標事件的控制以后,WPARAM參數(shù)是你在創(chuàng)建
        CTrayIcon類時定義的ID;LPARAM是鼠標事件(如,WM_LBUTTONDOWN)。當捕捉到
        通知后你能做所有你想做的事情;記得最后要調(diào)用
        CTrayIcon::OnTrayNotification函數(shù)以完成一些缺省的處理。該虛函數(shù)完成前面
        所提到的一些缸省的UI行為。特別的,他處理WM_LBUTTONDBLCLK和WM-RBUTTONUP事
        件。CTrayIcon類尋找和圖標擁有同樣ID的菜單(如,IDR_TRAYICON)。如果擁有
        該ID的菜單存在,CTrayIcon類將在用戶右擊圖標的時候顯示此菜單;而當用戶雙
        擊時,CTrayIcon將執(zhí)行菜單上的第一個命令。

      LRESULT CTrayDemoView::OnTrayNotification(WPARAM wp, LPARAM lp)
      {          
         return m_trayIcon.OnTrayNotification(wp, lp);
      }

        只有兩件事需要進一步解釋。在顯示菜單之前,CTrayIcon類使得第一項為缸省項,
        因此他看起來是大寫的。但怎樣使得一個菜單項大寫呢?使用函數(shù)
        GSetMenuDefaultItem。
      // Make first menu item the default (bold font)
      ::SetMenuDefaultItem(pSubMenu->m_hMenu, 0, TRUE);

        這里的0便指定了第一個菜單項,TRUE表示通過位置而不是ID來確定菜單項。
        對CTrayIcon::OnTrayNotification,我們關(guān)心的第二項是為了顯示相關(guān)菜單,他干
        了些什么?

      ::SetForegroundWindow(m_nid.hWnd);
      ::TrackPopupMenu(pSubMenu->m_hMenu, ...);

        為了使TrackPopupMenu函數(shù)在托盤環(huán)境中工作正常,你必須首先在擁有該彈出菜單
        的窗口中調(diào)用SetForegroundWindow函數(shù)。否則,當用戶按下Esc鍵或在菜單以外單
        擊鼠標時該菜單將不會消失。正如你看到的那樣,CTrayIcon類使得托盤圖標的編
        程非常簡單。為了使托盤菜單生效,在TrayDemo中所做的只是實現(xiàn)一個通知程式,在
        該程式中調(diào)用了CTrayIcon::OnTrayNotification,對了別忘了還要提供一個和
        CTrayIcon類擁有同樣ID的菜單。TrayDemo程式中是在菜單編輯器內(nèi)加入一ID為
        IDR_TRAYICON的如下菜單:
        然后,用ClassWizard在視圖類中分別為三個菜單命令加入如下的響應函數(shù):

      void CTrayDemoView::OnDisplayProgram()
      {
      CWnd* pWnd;
      pWnd=AfxGetApp()->m_pMainWnd;
      pWnd->ShowWindow(SW_NORMAL);
        pWnd->SetForegroundWindow();
      }

      void CTrayDemoView::OnCloseProgram()
      {
      m_bShutdown = TRUE;   // really exit
      CWnd* pWnd;
      pWnd=AfxGetApp()->m_pMainWnd;
        pWnd->SendMessage(WM_CLOSE);
      }

      void CTrayDemoView::OnShutoff()
      {
      Exit視窗系統(tǒng)Ex(EWX_SHUTDOWN,0);
      }

        其中,在OnShutoff函數(shù)中,Exit視窗系統(tǒng)Ex(EWX_SHUTDOWN,0)用來關(guān)閉計算機。限
        于篇幅,這里不作周詳介紹,讀者能查看MSDN來獲得更周詳?shù)馁Y料。
        最后,還要重載Cmainframe::OnClose函數(shù)如下:

      void CMainFrame::OnClose()
      {
      CTrayDemoView *pView =
        (CTrayDemoView *)GetActiveView();
      if (pView->m_bShutdown)
         CFrameWnd::OnClose();
        else
         ShowWindow(SW_HIDE);
      }

        提醒一點,為使框架程式識別視圖類,還要在MainFrm.cpp中加入如下兩句:
      #include "TrayDemoDoc.h"
      #include "TrayDemoView.h"

        如果有興趣,還能對將本程式繼續(xù)擴充,使之能監(jiān)視系統(tǒng)的狀態(tài):當鼠標和鍵
        盤在超過一設(shè)定的時間后,仍沒有動作,則程式將自動執(zhí)行關(guān)機命令。
        以上程式在視窗系統(tǒng)98,VC++6.0中調(diào)試通過。

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多