1. 程式人生 > >最小化後右下角(托盤)小圖示的實現

最小化後右下角(托盤)小圖示的實現

1.想要實現這樣的效果

2.我參考了“如何實現最小化後出現右下角圖示”http://www.cnblogs.com/weiqubo/archive/2010/12/25/1917013.html

  "讓一個程式托盤顯示,並且右鍵托盤圖示可以彈出選單"http://www.cnblogs.com/chenkunyun/archive/2012/03/17/2403002.html

3.這個效果實現的主要核心是   NOTIFYICONDATA 結構 ,然後通過Shell_NotifyIcon( NIM_ADD, &m_tnd );

和 Shell_NotifyIcon( NIM_DELETE, &m_tnd );這兩個函式來實現對右下角圖示的顯示和消除。

4.NOTIFYICONDATA這個結構中的各個值定義了我們這個右下角小圖示的種種屬性。

詳細介紹的MSDN連結https://msdn.microsoft.com/zh-cn/vstudio/bb773352

typedef struct _NOTIFYICONDATA {
  DWORD cbSize;      //結構長度 sizeof( NOTIFYICONDATA )
  HWND  hWnd;    //呼叫該結構的控制代碼
  UINT  uID;    // 一個唯一標識的ID,用來標識操作哪一個圖示
  UINT  uFlags;    //比如NIF_MESSAGE | NIF_ICON | NIF_TIP,用來標識該結構中hIcon,uCallbackMessage,szTip中的值為有效值,其他以此類推
UINT  uCallbackMessage; // 自定義一個訊息,WM_XXXXXX,我們點選小圖示的時候,種種操作將以這個訊息的形式傳送 HICON hIcon; // 很明顯,這是小圖示控制代碼 TCHAR szTip[64]; //放入一個字串,滑鼠放在圖示上的時候會出現一個小氣泡顯示這陣列內的字串,支援轉義字元 DWORD dwState; DWORD dwStateMask; TCHAR szInfo[256]; union { UINT uTimeout; UINT uVersion; }; TCHAR szInfoTitle[64]; DWORD dwInfoFlags; GUID  guidItem; HICON hBalloonIcon; } NOTIFYICONDATA, *PNOTIFYICONDATA;
5. 先講下個人理解的思路,順便梳理下NOTIFYICONDATA中的種種關係,程式碼是次要的。

我是在MFC下做的,將這個NOTIFYCONDATA結構變數我是定義在CFrame類中的,NOTIFYICONDATA  m_tnd。

在Frame初始化的時候,在OnCreate中完成NOTIFYCONDATA結構的初始化以及圖示的顯示。

通過呼叫Shell_NotifyIcon( NIM_ADD, &m_tnd );

我們在小圖示上的右鍵啊,雙擊之類的動作,將通過uCallbackMessage中定義的訊息傳送給hWnd。由於是CFrame呼叫的,我們將在CFrame中新增關於我們所自定義的uCallbackMessage這個訊息的響應函式,這個Message和我們平時的WM_SYSCOMMAND一樣,有wParam和lParam。

它的wParam就是我們在NOTIFYICONDATA結構中設定的uID,lParam則是在圖示上做的操作,以訊息的形式給出,如WM_RBUTTONDOWN。

6.具體實現:

  • 在資原始檔中#define WM_TRAYICON (WM_USER+1),WM_TRAYICON就是我們在結構中自定義的訊息。
  • 在CFrame類中新增一個NOTIFYICONDATA成員。
  • 在CFrame類的OnCreate和OnDestroy函式中分別完成NOTIFYICONDATA結構填寫、圖示顯示和圖示刪除。顯示和刪除使用Shell_NotifyIcon函式。
  • 在CFrame類的class wizard-》訊息有個新增自定義訊息,新增我們定義的那個uCallbackMessage,並在其中填寫lParam中或是左鍵雙擊或是右鍵的訊息的處理
  • 新增WM_SYSCOMMAND的處理訊息,點選最小化的時候,是的視窗hide。
7.為了簡潔我只複製了新增程式碼,程式碼給出的順序與第6點鐘給出的順序一致
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){
	SetupTrayIcon(m_hWnd);
}
BOOL CMainFrame::SetupTrayIcon(HWND hwnd)
{
    m_tnd.cbSize              = sizeof( NOTIFYICONDATA );
    m_tnd.hWnd              = hwnd;//
    m_tnd.uID              = 1123583721;   //只是為了說明UID是個數字ID,隨意不重複即可,第2節中兩篇文章用的”IDR_MAINFRAME“圖個方便
    m_tnd.uFlags              = NIF_MESSAGE | NIF_ICON | NIF_TIP;
    m_tnd.uCallbackMessage = WM_TRAYICON;  
    m_tnd.hIcon                 = AfxGetApp()->LoadIconA(IDR_MAINFRAME)
    strcpy_s(m_tnd.szTip,_T("MFC\nhello\n 88"));  //這裡是為了驗證轉義字元是否有效,顯示多行,像qq一樣
    return Shell_NotifyIcon( NIM_ADD, &m_tnd );
}
void CMainFrame::OnDestroy()
{
	CFrameWnd::OnDestroy();
	RemoveTrayIcon();
}
BOOL CMainFrame::RemoveTrayIcon()
{
    return Shell_NotifyIcon( NIM_DELETE, &m_tnd );
}
afx_msg LRESULT CMainFrame::OnTrayicon(WPARAM wParam, LPARAM lParam)
{  if (wParam==1123583721)
    {
        switch (lParam)
        {
        case WM_RBUTTONDOWN:
            {
                新增右鍵選單
            }
            break;
        case WM_LBUTTONDBLCLK:
       		雙擊顯示程式視窗
            break;
        }
    }
	return 0;
}
void CMainFrame::OnSysCommand(UINT nID, LPARAM lParam)
{
	if( nID == SC_MINIMIZE)
		ShowWindow(SW_HIDE);
	else
		CFrameWnd::OnSysCommand(nID, lParam);
}

8.效果
9.小問題:
在實現右鍵選單的時候,兩篇文章程式碼中都有這麼一句話
 SetForegroundWindow();//這一行程式碼很重要,否則右鍵選單工作//不正常。
我認為這是個把視窗放到最前端的函式,而右鍵的時候一般視窗還在隱藏階段,我就把這行程式碼刪除了。執行結果看起來也並沒有什麼大礙。
幾次測試後,發現右鍵選單彈出後點擊螢幕別的地方選單不能夠自動消失。除非我們在視窗未被最小化的時候,右鍵小圖示顯示選單,然後在客戶區內點選,選單才會自動消失。恍然大悟,把這行又加了回去。
10.遺留:
可以嘗試這去像qq一樣,右鍵選單然後改變這個右下角圖示。