一、需求
本文实现程序系统托盘。
二、界面
主界面为对话框,有最小化、最大化、关闭等功能。
三、原理
利用系统托盘类NOTIFYICONDATA,响应自定义消息,处理托盘鼠标事件。
四、编码
4.1 消息定义
定义消息ID,必须大于WM_USER,为方便起见,可在stdafx.h中定义:
1
| #define WM_SHOWTASK (WM_USER+1) // 系统托盘事件
|
在对话框头文件声明消息响应函数:
1 2 3 4
| afx_msg LRESULT OnSystemtray(WPARAM wParam, LPARAM lParam); afx_msg void OnSize(UINT nType, int cx, int cy); afx_msg void OnDestroy();
|
在对话框实现文件,添加消息与响应函数的关联:
1 2 3 4 5 6 7 8 9
| BEGIN_MESSAGE_MAP(CMyTestDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() // ... ON_MESSAGE(WM_SHOWTASK, OnSystemtray) // 托盘 ON_WM_SIZE() ON_WM_DESTROY() // 销毁 END_MESSAGE_MAP()
|
4.2 变量声明
在类中声明
1 2 3
| private: NOTIFYICONDATA m_nid; BOOL m_fMainWinShow; // 托盘 双击左键显示/隐藏窗口
|
4.3 初始化
在OnInitDialog函数中初始化:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| // 系统托盘 m_nid.cbSize = (DWORD)sizeof(NOTIFYICONDATA); m_nid.hWnd = this->m_hWnd; m_nid.uID = IDR_MAINFRAME; m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO; m_nid.uCallbackMessage = WM_SHOWTASK; // 自定义的消息名称 m_nid.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME)); wcscpy_s(m_nid.szTip, L"主程序"); // 提示程序名称 Shell_NotifyIcon(NIM_ADD, &m_nid); // 在托盘区添加图标
// 如此实现,任务栏没有图标,但窗口没有最小化按钮 #if 0 //ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); // 不在任务栏中显示 // ShowWindow(SW_MINIMIZE); #endif //ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW); // 不在任务栏中显示
// 可以实现,但界面会闪烁 ShowWindow(SW_MINIMIZE); // 不能使用SW_HIDE PostMessage(WM_SYSCOMMAND, SC_MINIMIZE, 0);
m_fMainWinShow = FALSE;
|
同一文件,实现WM_SHOWTASK消息的响应,包括鼠标左键、右键的处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| LRESULT CMyTestDlg::OnSystemtray(WPARAM wParam, LPARAM lParam) { if (wParam != IDR_MAINFRAME) return 1; switch (lParam) { case WM_RBUTTONUP: // 右键起来时弹出菜单 { LPPOINT lpoint = new tagPOINT; GetCursorPos(lpoint); // 得到鼠标位置 CMenu menu; menu.CreatePopupMenu(); // 声明一个弹出式菜单 menu.AppendMenu(MF_STRING, WM_DESTROY, L"退出"); SetForegroundWindow(); menu.TrackPopupMenu(TPM_LEFTALIGN, lpoint->x, lpoint->y, this); HMENU hmenu = menu.Detach(); menu.DestroyMenu(); delete lpoint; } break; case WM_LBUTTONDBLCLK: // 双击左键的处理 { if (!m_fMainWinShow) { ShowWindow(SW_SHOWNORMAL); // 显示主窗口 SetForegroundWindow(); m_fMainWinShow = TRUE; } else { ShowWindow(SW_HIDE); // 隐藏主窗口 SetForegroundWindow(); m_fMainWinShow = FALSE; } } break; } return 0; }
|
4.4 响应最小化、窗口销毁事件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void CMyTestDlg::OnSize(UINT nType, int cx, int cy) { CDialogEx::OnSize(nType, cx, cy);
if (nType == SIZE_MINIMIZED) { ShowWindow(SW_HIDE); // 当最小化时,隐藏主窗口 } }
void CMyTestDlg::OnDestroy() { CDialogEx::OnDestroy();
// 在托盘区删除图标 Shell_NotifyIcon(NIM_DELETE, &m_nid); }
|
本文实现的系统托盘,右键只有“退出”一个选项,可酌情添加。
另外,在启动时最小化,窗口会有瞬间闪烁的现象,在可接受范围,故不解决。