本指南将实现 MFC 应用程序在关闭时最小化系统托盘的功能,并左键和右键系统托盘图标进行交互。
目标:
- 左键点击托盘图标:恢复对话框窗口。
- 右键点击托盘图标:弹出右键菜单,提供 恢复窗口 和 退出程序 两个选项。
- 退出时删除托盘图标,并关闭对话框。
步骤详解:
1. 定义托盘图标的 ID 和所需资源
定义托盘图标的菜单项 ID,例如:
#define ID_TRAY_RESTORE 1001 // 恢复窗口
#define ID_TRAY_EXIT 1002 // 退出程序
2. 定义成员变量和消息映射
在 CDlgMFCApplicationDlg
类的头文件中,定义托盘图标的数据结构和处理方法。
private:
NOTIFYICONDATA m_trayIconData; // 托盘图标数据
UINT m_nTrayIconID; // 托盘图标ID
BOOL m_bTrayIconCreated; // 标记托盘图标是否创建成功
protected:
afx_msg void OnClose(); // 关闭窗口时的处理
afx_msg LRESULT OnTrayIconClick(WPARAM wParam, LPARAM lParam); // 托盘图标点击事件
afx_msg void OnTrayRestore(); // 恢复窗口
afx_msg void OnTrayExit(); // 退出应用
通过 ON_COMMAND
映射来处理菜单项的选择:
BEGIN_MESSAGE_MAP(CDlgMFCApplicationDlg, CDialogEx)
ON_WM_CLOSE()
ON_MESSAGE(WM_USER + 1, &CDlgMFCApplicationDlg::OnTrayIconClick) // 托盘图标点击事件
ON_COMMAND(ID_TRAY_RESTORE, &CDlgMFCApplicationDlg::OnTrayRestore) // 恢复窗口
ON_COMMAND(ID_TRAY_EXIT, &CDlgMFCApplicationDlg::OnTrayExit) // 退出程序
END_MESSAGE_MAP()
在 OnInitDialog()
中初始化托盘图标数据:
m_trayIconData.cbSize = sizeof(NOTIFYICONDATA); // 设置托盘图标数据结构的大小
m_trayIconData.hWnd = m_hWnd; // 设置窗口句柄
m_trayIconData.uID = m_nTrayIconID; // 设置托盘图标 ID
m_trayIconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; // 设置托盘图标的标志(图标、消息、提示文本)
m_trayIconData.uCallbackMessage = WM_USER + 1; // 设置回调消息(WM_USER + 1)
m_trayIconData.hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); // 加载托盘图标
lstrcpy(m_trayIconData.szTip, _T("MFC Tray App")); // 设置托盘提示文本
// 添加托盘图标
Shell_NotifyIcon(NIM_ADD, &m_trayIconData);
m_bTrayIconCreated = TRUE;
3. 处理托盘图标点击事件
通过 OnTrayIconClick()
来响应托盘图标的点击事件。根据 lParam
的值判断是左键点击还是右键点击。
LRESULT CDlgMFCApplicationDlg::OnTrayIconClick(WPARAM wParam, LPARAM lParam) {
if (wParam == m_nTrayIconID) {
if (LOWORD(lParam) == WM_LBUTTONUP) {
// 左键点击恢复窗口
ShowWindow(SW_SHOW);
SetForegroundWindow();
} else if (LOWORD(lParam) == WM_RBUTTONUP) {
// 右键点击弹出菜单
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(MF_STRING, ID_TRAY_RESTORE, _T("Restore"));
menu.AppendMenu(MF_STRING, ID_TRAY_EXIT, _T("Exit"));
// 获取鼠标当前位置,并显示菜单
POINT pt;
GetCursorPos(&pt);
menu.TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this);
}
}
return 0;
}
4. 实现右键菜单项处理方法
- 恢复窗口:
void CDlgMFCApplicationDlg::OnTrayRestore() {
ShowWindow(SW_SHOW); // 恢复窗口
SetForegroundWindow(); // 将窗口置于前端
}
- 退出程序:
void CDlgMFCApplicationDlg::OnTrayExit() {
Shell_NotifyIcon(NIM_DELETE, &m_trayIconData); // 删除托盘图标
PostMessage(WM_CLOSE); // 关闭窗口并退出应用
}
5. 实现关闭窗口
在 OnClose()
中,询问用户是否希望将应用最小化到系统托盘,如果选择是,则隐藏窗口并保留托盘图标;否则直接退出。
void CDlgMFCApplicationDlg::OnClose() {
int nResult = AfxMessageBox(_T("Do you want to minimize the application to the system tray?"), MB_YESNO | MB_ICONQUESTION);
if (nResult == IDYES) {
ShowWindow(SW_HIDE); // 隐藏窗口
} else {
Shell_NotifyIcon(NIM_DELETE, &m_trayIconData); // 删除托盘图标
CDialogEx::OnClose(); // 关闭对话框
}
}
6. 清理托盘图标
在 OnTrayExit
或 OnClose
中删除托盘图标,并释放资源:
Shell_NotifyIcon(NIM_DELETE, &m_trayIconData); // 删除托盘图标
总结:
通过以上步骤,已经实现了以下功能:
- 当用户关闭窗口时,询问是要最小化到系统托盘还是退出应用程序。
- 左键单击托盘图标以恢复窗口。
- 右键单击托盘图标以显示上下文菜单,允许用户恢复窗口或退出应用程序。