Windows中,,任務(wù)欄的右邊(托盤(pán))常駐有幾個(gè)圖標(biāo),,如輸入法切換圖標(biāo)、音量控制圖標(biāo)等系統(tǒng)圖標(biāo),,而一些在后臺(tái)執(zhí)行實(shí)時(shí)監(jiān)控或其他任務(wù)的
軟件如金山詞霸,、瑞星殺毒軟件等也只是在托盤(pán)上放一個(gè)小小的圖標(biāo),幾乎不占用本來(lái)就擁擠不堪的桌面,,而且必要時(shí)我們還可以通過(guò)用鼠標(biāo)點(diǎn)擊圖標(biāo)對(duì)其進(jìn)行菜單
操作或激活其主窗口,。如果在我們編制的一些類似的在后臺(tái)工作的實(shí)時(shí)監(jiān)控軟件里加入上述功能,無(wú)疑會(huì)使程序顯得很有專業(yè)水準(zhǔn),。雖然有不少介紹系統(tǒng)托盤(pán)方面編
程的文章,,但大多是講述如何在SDK下用Windows
API編寫(xiě)的,,這樣做顯然是非常煩瑣的,本文以一個(gè)SDI(單文檔界面)程序?yàn)槔?,講述了在MFC框架程序中此類程序的實(shí)現(xiàn)過(guò)程,。 [喝小酒的網(wǎng)摘]http://blog./a/1117.htm 二、 程序的設(shè)計(jì)思路 在編制此類程序時(shí),,為了不干擾前臺(tái)程序的運(yùn)行界面和不顯示不必要的窗口,,應(yīng)使其運(yùn)行時(shí)的主窗口不可見(jiàn)。同時(shí),,又要讓用戶知道該程序正在運(yùn)行,,并且能達(dá)到與 用戶進(jìn)行交互的目的。將一個(gè)圖標(biāo)顯示在任務(wù)欄右端系統(tǒng)托盤(pán)區(qū)中并響應(yīng)用戶的鼠標(biāo)動(dòng)作是當(dāng)前非常流行的方法,。要使程序的主窗口不可見(jiàn),,并且不在任務(wù)欄上出現(xiàn) 任務(wù)按鈕,需要分別設(shè)置主邊框窗口的風(fēng)格和擴(kuò)展風(fēng)格,;另外,,利用系統(tǒng)函數(shù)Shell_NotifyIcon可以將一個(gè)圖標(biāo)顯示在任務(wù)欄的通告區(qū)中。剩下的 任務(wù)就是如何通過(guò)這個(gè)圖標(biāo)來(lái)響應(yīng)用戶的操作,,可以象其他軟件如WinAmp 一樣通過(guò)彈出式菜單來(lái)完成同用戶的交互。 三,、 程序的具體實(shí)現(xiàn) (一) 主界面的隱藏 前面已經(jīng)提過(guò),,要求程序運(yùn)行開(kāi)始時(shí)主窗口不可見(jiàn),同時(shí)也不出現(xiàn)在任務(wù)欄中,,在SDK下是通過(guò)修改入口函數(shù)WinMain中的API函數(shù) CreatWindow的參數(shù)來(lái)實(shí)現(xiàn)的,,在MFC下已經(jīng)對(duì)其進(jìn)行了封裝,使我們無(wú)法直接對(duì)WinMain函數(shù)內(nèi)部進(jìn)行訪問(wèn)與修改,,不過(guò)可以通過(guò)MFC提供 的另外一個(gè)接口--在主框架類的預(yù)創(chuàng)建窗口函數(shù)中設(shè)定主框架窗口的風(fēng)格和擴(kuò)展風(fēng)格來(lái)實(shí)現(xiàn)之: BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; cs.style=WS_POPUP; cs.dwExStyle |=WS_EX_TOOLWINDOW; return TRUE; } 其中,,CREATESTRUCT結(jié)構(gòu)中的style成員變量設(shè)定了主框架窗口的風(fēng)格,在此設(shè)定為WS_POPUP,;而dwExStyle成員變量則對(duì)主框 架窗口的擴(kuò)展風(fēng)格做了描述,,只需在原有基礎(chǔ)上為其再增添一種WS_EX_TOOLWINDOW擴(kuò)展屬性即可使其不會(huì)出現(xiàn)在任務(wù)條上。 (二) 將圖標(biāo)放置到托盤(pán)區(qū) 將圖標(biāo)放到托盤(pán)之前必須先將圖標(biāo)裝載到內(nèi)存中,,可用API函數(shù)LoadIcon實(shí)現(xiàn),。之后就可以用系統(tǒng)函數(shù)Shell_NotifyIcon將一個(gè)圖標(biāo)顯 示到任務(wù)欄的托盤(pán)區(qū)中了。該函數(shù)的原型為:WINSHELLAPI BOOL WINAPI Shell_NotifyIcon( DWORD dwMessage, PNOTIFYICONDATA pnid)其第一個(gè)參數(shù)用以指定動(dòng)作,,如NIM_ADD將圖標(biāo)裝載到托盤(pán)中,NIM_DELETE可將裝載到托盤(pán)中的圖標(biāo)刪除掉,;其第二個(gè)參數(shù)是一個(gè)具有 NOTIFYICONDATA類型的結(jié)構(gòu)指針,。該結(jié)構(gòu)的原型為: typedef struct _NOTIFYICONDATA { // nid DWORD cbSize; HWND hWnd; UINT uID; UINT uFlags; UINT uCallbackMessage; HICON hIcon; charszTip[64]; }NOTIFYICONDATA, *PNOTIFYICONDATA; 在該結(jié)構(gòu)的成員中,,hWnd為接受該圖標(biāo)所發(fā)出的消息的窗口的句柄,,可以將主框架類的m_hWnd變量傳給它;uID 為被顯示圖標(biāo)的ID,;uFlags指明其余的幾個(gè)成員(hIcon,、uCallBackMessage和szTip)的值是否有 效,;uCallbackMessage為一個(gè)自定義的消息,當(dāng)用戶在該圖標(biāo)上作用一些鼠標(biāo)動(dòng)作時(shí),,將向hWnd 成員中指定的窗口發(fā)出該消息,可以定義該消息WM_TRAY為WM_USER+100,;hIcon為被顯示圖標(biāo)的句柄即前面的LoadIcon的返回 值,;szTip為一字符數(shù)組,當(dāng)鼠標(biāo)停留在該圖標(biāo)上時(shí),,將其內(nèi)容顯示在浮動(dòng)的提示信息框中,。顯然,上述工作必須在程序一開(kāi)始執(zhí)行時(shí)就完成,,所以在主框架類 的OnCreate函數(shù)中修改如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { …… m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); …… NOTIFYICONDATA tnd; tnd.cbSize=sizeof(NOTIFYICONDATA); tnd.hWnd=this->m_hWnd; tnd.uID=IDR_MAINFRAME; tnd.uFlags=NIF_MESSAGE|NIF_ICON|NIF_TIP; tnd.uCallbackMessage=WM_TRAY; tnd.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME)); strcpy(tnd.szTip,"托盤(pán)演示軟件"); Shell_NotifyIcon(NIM_ADD,&tnd); return 0; } (三) 彈出式菜單的添加及激活 顯然,,在添加到托盤(pán)中的圖標(biāo)上使用彈出式菜單是用戶同程序交互的再合適不過(guò)的手段,,許多此類知名軟件也多使用這種方法同用戶相交互,。彈出式菜單不能象通常 菜單那樣在ResourceView中對(duì)其進(jìn)行編輯,而要通過(guò)編輯軟件對(duì)*.rc的資源文件進(jìn)行手工編輯,,如果沒(méi)有接觸過(guò)SDK 編程,,那么此步會(huì)有些困難。首先找到原有菜單IDR_MAINFRAME MENU 的定義區(qū),,添加如下對(duì)菜單的描述: IDR_BEGINMENU MENU DISCARDABLE BEGIN POPUP "" BEGIN MENUITEM "技術(shù)支持", ID_SUPPORT MENUITEM SEPARATOR MENUITEM "主界面", ID_MAIN MENUITEM SEPARATOR MENUITEM "退出程序", ID_EXIT END END 其中SEPARATOR為菜單中的分割符,。之后還應(yīng)當(dāng)在Resource.h中添加ID_SUPPORT、ID_MAIN和ID_EXIT的定義,。該菜單 的激活只有通過(guò)自定義消息WM_TRAY的響應(yīng)函數(shù)這一條途徑來(lái)實(shí)現(xiàn),,因?yàn)楫?dāng)用戶在該圖標(biāo)上作用一些鼠標(biāo)動(dòng)作時(shí),只會(huì)發(fā)出這個(gè)消息,,可以通過(guò)判斷消息的低 位參數(shù)lParma來(lái)決定是鼠標(biāo)的何種動(dòng)作,,下面代碼使當(dāng)鼠標(biāo)右鍵按下時(shí)在鼠標(biāo)當(dāng)前位置彈出上述菜單: …… uID=(UINT) wParam; uMouseMsg=(UINT) lParam; CMenu menu; if(uMouseMsg==WM_RBUTTONDOWN)//如果是單擊右鍵 { switch(uID) { case IDR_MAINFRAME://如果是我們的圖標(biāo) GetCursorPos(&pt);//取得鼠標(biāo)位置 //執(zhí)行相應(yīng)操作 menu.LoadMenu(IDR_BEGINMENU); pMenu=menu.GetSubMenu(0); ASSERT(pMenu!=0); pMenu->TrackPopupMenu (0,pt.x,pt.y,this); break; default: break; } } …… (四) 菜單項(xiàng)及圖標(biāo)對(duì)外界激勵(lì)的響應(yīng) 為使人機(jī)界面更友好,與用戶更好的進(jìn)行交互,,使用戶在該圖標(biāo)上雙擊鼠標(biāo)左鍵時(shí)能彈出程序主界面,,再次雙擊則隱藏之,。可以繼續(xù)在自定義消息WM_TRAY 的響應(yīng)函數(shù)里加入對(duì)左鍵的處理過(guò)程: …… if(uMouseMsg==WM_LBUTTONDBLCLK)//如果是左鍵雙擊 { static bool isMax=false; switch(uID) { case IDR_MAINFRAME: if(isMax==false) { //顯示主窗口 ModifyStyle(WS_POPUP,WS_OVERLAPPEDWINDOW); ModifyStyleEx(WS_EX_TOOLWINDOW,WS_EX_TOPMOST); ShowWindow(SW_SHOWMAXIMIZED); isMax=true; } else { ShowWindow(SW_HIDE);//隱藏主窗口 ModifyStyle(WS_CAPTION|FWS_PREFIXTITLE|WS_SYSMENU| WS_MINIMIZEBOX|WS_MAXIMIZEBOX,WS_POPUP); ModifyStyleEx(WS_EX_TOPMOST,WS_EX_TOOLWINDOW); isMax=false; } break; default: break; } } …… 另外,,當(dāng)用右鍵彈出菜單時(shí),,對(duì)其菜單項(xiàng)的響應(yīng)需要用到自定義消息的響應(yīng),這種自定義消息的響應(yīng)過(guò)程不能象其他的系統(tǒng)消息一樣通過(guò)ClassWizard來(lái)添加,,仍需要一步步地手工添加,,首先在頭文件里添加響應(yīng)函數(shù)的聲明: …… //{{AFX_MSG(CMainFrame) …… afx_msg void OnMainWindow(); afx_msg void OnExit(); afx_msg void OnSupport(); …… //}}AFX_MSG DECLARE_MESSAGE_MAP() …… 然后,在源文件里添加消息映射: …… BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd) //{{AFX_MSG_MAP(CMainFrame) …… ON_COMMAND(ID_MAIN,OnMainWindow) ON_COMMAND(ID_EXIT, OnExit) ON_COMMAND(ID_SUPPORT, OnSupport) //}}AFX_MSG_MAP END_MESSAGE_MAP() …… 最后在其各自的實(shí)現(xiàn)函數(shù)中加入與其菜單項(xiàng)相對(duì)應(yīng)的功能即可: …… void CMainFrame::OnMainWindow() { //顯示程序主框架 ModifyStyle(WS_POPUP,WS_OVERLAPPEDWINDOW); ModifyStyleEx(WS_EX_TOOLWINDOW,WS_EX_TOPMOST); ShowWindow(SW_SHOWMAXIMIZED); } void CMainFrame::OnSupport() { …… } void CMainFrame::OnExit() { //退出程序之前用NIM_DELETE屬性指定刪除掉加入到托盤(pán)的圖標(biāo) NOTIFYICONDATA tnid; tnid.cbSize=sizeof(NOTIFYICONDATA); tnid.hWnd=this->m_hWnd; tnid.uID=IDR_MAINFRAME;//保證刪除的是我們的圖標(biāo) Shell_NotifyIcon(NIM_DELETE,&tnid); //退出程序 AfxPostQuitMessage(0); } 小結(jié): 本程序?qū)ο到y(tǒng)托盤(pán)的MFC編程做了較詳細(xì)的介紹,,同時(shí)也對(duì)彈出菜單及自定義消息等技術(shù)也做了適當(dāng)?shù)恼f(shuō)明,,在理解了本程序的編程思路和實(shí)現(xiàn)方法的前提下,可 以修改,、添加部分代碼,,進(jìn)一步完善程序,使之跟自己的程序更好的融合在一起,。本程序在Windows 98下,,由Microsoft Visual C++6.0編譯通過(guò)。[喝小酒的網(wǎng)摘]http://blog./a/1117.htm |
|