利用任務欄上的圖標與用戶交互
發表于:2007-07-14來源:作者:點擊數:
標簽:
作者:李奔 我們有時需要編制一些僅在后臺監控的程序,為了不干擾前臺程序的運行界面和不顯示不必要的窗口,應使其運行時的主窗口不可見。同時,應該讓用戶知道該程序正在運行,并且達到與用戶進行交互的目的。將一個圖標顯示在任務欄右端靜態通告區中并響應
作者:李奔
我們有時需要編制一些僅在后臺監控的程序,為了不干擾前臺程序的運行界面和不顯示不必要的窗口,應使其運行時的主窗口不可見。同時,應該讓用戶知道該程序正在運行,并且達到與用戶進行交互的目的。將一個圖標顯示在任務欄右端靜態通告區中并響應用戶的鼠標動作是當前非常流行的方法,它體現了
Windows 95友好的界面風格。下面以一個SDI(單文檔界面)程序為例,講述采用Microsoft Visual C++ 5.0
開發這類程序的主要步驟。
首先,要使程序的主窗口不可見,并且不在任務欄上出現任務按鈕,要做到這兩點,需分別設置主邊框窗口的風格和擴展風格:
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style =WS_POPUP;//使主窗口不可見
cs.dwExStyle |=WS_EX_TOOLWINDOW;//不顯示任務按鈕
return CFrameWnd::PreCreateWindow(cs);
}
其次,利用系統函數Shell_NotifyIcon將一個圖標顯示在任務欄的通告區中。該函數的原型為:
WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA pnid
);
下例中被顯示的是主邊框窗口的圖標,實際上可以顯示任何圖標:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
…
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_LIBEN;
tnd.hIcon=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_MAINFRAME));
strcpy(tnd.szTip,"提示信息");
Shell_NotifyIcon(NIM_ADD,&tnd);
…
}
在調用該函數之前,需要確定其參數的取值,其中之一為一個具有NOTIFYICONDATA類型的結構。其原型為:
typedef struct _NOTIFYICONDATA { // nid
DWORD cbSize;
HWND hWnd;
UINT uID;
UINT uFlags;
UINT uCallbackMessage;
HICON hIcon;
charszTip[64]; }
NOTIFYICONDATA, *PNOTIFYICONDATA;
在該結構的成員中,cbSize為該結構所占的字節數,hWnd為接受該圖標所發出的消息的窗口的句柄,uID為被顯示圖標的ID,uFlags指明其余的幾個成員(hIcon、uCallBackMessage和szTip)的值是否有效,uCallbackMessage為一個自定義的消息,當用戶在該圖標上作用一些鼠標動作時,將向hWnd成員中指定的窗口發出該消息,可以定義該消息為WM_USER+100。hIcon為被顯示圖標的句柄,szTip為一字符數組,當鼠標停留在該圖標上時,將其內容顯示在浮動的提示信息框中。Shell_NotifyIcon函數的另一個參數是一個預定義的消息,可以取如下值之一:NIM_ADD、NIM_DELETE或NIM_MODIFY,分別表示添加圖標、刪除圖標或修改圖標。
最后,要與用戶進行交互,也就是當用戶在該圖標上單擊或雙擊鼠標左鍵或右鍵時要執行相應的操作,至少也要響應用戶終止該程序的意愿。上面已經提到,當用戶在圖標上進行鼠標動作時,將向hWnd成員中指定的窗口發出自定義的消息,該消息由uCallbackMessage成員指定(在上例中為WM_LIBEN,取值為WM_USER+100)。因此,我們的任務就是在hWnd窗口中響應該自定義消息:
void CMainFrame::OnLiben(WPARAM wParam,LPARAM lParam)
{
UINT uID;//發出該消息的圖標的ID
UINT uMouseMsg;//鼠標動作
POINT pt;
uID=(UINT) wParam;
uMouseMsg=(UINT) lParam;
if(uMouseMsg==WM_RBUTTONDOWN)//如果是單擊右鍵
{
switch(uID)
{
case IDR_MAINFRAME://如果是我們的圖標
GetCursorPos(&pt);//取得鼠標位置
…//執行相應操作
break;
…
default:
…
}
}
return;
}
需要注意的是,首先要在該窗口類的頭文件中給出該消息映射函數的原型說明:
afx_msg void OnLiben(WPARAM wParam,LPARAM lParam);
并且要在CPP文件中的消息映射中加入相應的條目,注意一定要加在//{{AFX_MSG_MAP(CMainFrame)和//}}AFX_MSG_MAP之外:
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_COMMAND(ID_APP_EXIT, OnAppExit)
//}}AFX_MSG_MAP
ON_MESSAGE(WM_LIBEN,OnLiben)
END_MESSAGE_MAP()
當程序結束時,需要刪去通告區中的圖標,這時同樣應該調用Shell_NotifyIcon函數,只不過第一個參數是表示刪除圖標的NIM_DELETE了:
void CMainFrame::OnAppExit()
{
// TODO: Add your command handler code here
NOTIFYICONDATA tnid;
tnid.cbSize=sizeof(NOTIFYICONDATA);
tnid.hWnd=this->m_hWnd;
tnid.uID=IDR_MAINFRAME;//保證刪除的是我們的圖標
Shell_NotifyIcon(NIM_DELETE,&tnid);
AfxPostQuitMessage(0);
}
通過類似的步驟,讀者可以響應其他的消息,完成更加高級的交互功能,這里不再贅述。上文所述是筆者經驗所得,肯定有不到之處,歡迎指正。
原文轉自:http://www.anti-gravitydesign.com