如何用MFC开发类似日期组件的后台任务栏CPU使用率显示程序
MFC实现后台任务栏CPU监控程序
要实现后台运行、在任务栏通知区域(托盘)显示CPU使用率的MFC程序,核心分为系统托盘集成、CPU使用率获取、定期更新显示三个部分,具体步骤如下:
1. 创建后台MFC应用
新建MFC对话框应用,在OnInitDialog中隐藏主窗口,确保程序后台运行:
ShowWindow(SW_HIDE); // 可选:修改窗口样式,避免主窗口在任务栏显示 ModifyStyleEx(WS_EX_APPWINDOW, WS_EX_TOOLWINDOW);
2. 集成系统托盘图标
系统托盘功能依赖Windows API的Shell_NotifyIcon,步骤如下:
2.1 定义托盘数据结构
在对话框类头文件中声明NOTIFYICONDATA变量和自定义消息:
#include <shellapi.h> #pragma comment(lib, "shell32.lib") #define WM_MY_NOTIFY WM_USER + 100 class CCPUMonitorDlg : public CDialogEx { // ... 其他成员 private: NOTIFYICONDATA m_nid; afx_msg LRESULT OnNotifyIcon(WPARAM wParam, LPARAM lParam); afx_msg void OnTimer(UINT_PTR nIDEvent); afx_msg void OnDestroy(); DECLARE_MESSAGE_MAP() };
2.2 初始化托盘图标
在OnInitDialog中完成托盘图标初始化:
ZeroMemory(&m_nid, sizeof(m_nid)); m_nid.cbSize = sizeof(NOTIFYICONDATA); m_nid.hWnd = m_hWnd; m_nid.uID = IDI_MYAPP_ICON; // 替换为你的资源图标ID m_nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; m_nid.uCallbackMessage = WM_MY_NOTIFY; m_nid.hIcon = AfxGetApp()->LoadIcon(IDI_MYAPP_ICON); _tcscpy_s(m_nid.szTip, _T("CPU使用率监控")); // 添加托盘图标 Shell_NotifyIcon(NIM_ADD, &m_nid);
2.3 处理托盘事件
实现自定义消息响应函数,处理右键菜单(比如退出选项):
LRESULT CCPUMonitorDlg::OnNotifyIcon(WPARAM wParam, LPARAM lParam) { if (wParam == IDI_MYAPP_ICON && lParam == WM_RBUTTONUP) { CMenu menu; menu.LoadMenu(IDR_MENU1); // 加载自定义右键菜单 CMenu* pSubMenu = menu.GetSubMenu(0); POINT pt; GetCursorPos(&pt); pSubMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, pt.x, pt.y, this); } return 0; }
3. 获取系统CPU使用率
使用Windows性能计数器(PDH)获取CPU使用率,步骤如下:
3.1 初始化计数器
在类中声明PDH句柄,添加初始化函数:
#include <pdh.h> #pragma comment(lib, "pdh.lib") class CCPUMonitorDlg : public CDialogEx { // ... 其他成员 private: PDH_HQUERY m_hQuery; PDH_HCOUNTER m_hCounter; BOOL InitCPUCounter(); float GetCPUUsage(); };
实现初始化和获取函数:
BOOL CCPUMonitorDlg::InitCPUCounter() { if (PdhOpenQuery(NULL, 0, &m_hQuery) != ERROR_SUCCESS) return FALSE; if (PdhAddCounter(m_hQuery, _T("\\Processor(_Total)\\% Processor Time"), 0, &m_hCounter) != ERROR_SUCCESS) { PdhCloseQuery(m_hQuery); return FALSE; } // 第一次采样,用于后续计算差值 PdhCollectQueryData(m_hQuery); return TRUE; } float CCPUMonitorDlg::GetCPUUsage() { PDH_FMT_COUNTERVALUE counterVal; // 第二次采样 if (PdhCollectQueryData(m_hQuery) != ERROR_SUCCESS) return 0.0f; if (PdhGetFormattedCounterValue(m_hCounter, PDH_FMT_FLOAT, NULL, &counterVal) == ERROR_SUCCESS) return counterVal.fValue; return 0.0f; }
在OnInitDialog中调用InitCPUCounter()完成初始化。
4. 定期更新托盘显示
使用MFC定时器定期获取CPU使用率并更新托盘:
4.1 设置定时器
在OnInitDialog中启动定时器(每秒更新一次):
SetTimer(1, 1000, NULL);
4.2 实现定时器回调
在OnTimer函数中更新托盘的提示文字或动态生成带文字的图标:
void CCPUMonitorDlg::OnTimer(UINT_PTR nIDEvent) { if (nIDEvent == 1) { float cpuUsage = GetCPUUsage(); CString strStatus; strStatus.Format(_T("CPU: %.1f%%"), cpuUsage); // 更新托盘提示文字 m_nid.uFlags = NIF_TIP; _tcscpy_s(m_nid.szTip, strStatus); Shell_NotifyIcon(NIM_MODIFY, &m_nid); // 可选:动态生成带文字的托盘图标 HICON hNewIcon = CreateIconWithText(strStatus); if (hNewIcon) { m_nid.uFlags = NIF_ICON; DestroyIcon(m_nid.hIcon); // 释放旧图标 m_nid.hIcon = hNewIcon; Shell_NotifyIcon(NIM_MODIFY, &m_nid); } } CDialogEx::OnTimer(nIDEvent); }
4.3 动态生成带文字的图标
实现CreateIconWithText函数,将CPU使用率绘制到图标上:
HICON CCPUMonitorDlg::CreateIconWithText(CString strText) { HDC hDC = GetDC()->m_hDC; HDC hMemDC = CreateCompatibleDC(hDC); HBITMAP hBmp = CreateCompatibleBitmap(hDC, 16, 16); // 托盘图标标准尺寸 HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDC, hBmp); // 填充背景 RECT rect = {0, 0, 16, 16}; FillRect(hMemDC, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH)); // 设置字体和文字颜色 SetTextColor(hMemDC, RGB(255, 255, 255)); SetBkMode(hMemDC, TRANSPARENT); LOGFONT lf; ZeroMemory(&lf, sizeof(lf)); lf.lfHeight = 12; lf.lfWeight = FW_BOLD; _tcscpy_s(lf.lfFaceName, _T("Arial")); HFONT hFont = CreateFontIndirect(&lf); HFONT hOldFont = (HFONT)SelectObject(hMemDC, hFont); // 居中绘制文字 DrawText(hMemDC, strText, strText.GetLength(), &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); // 创建图标 ICONINFO ii; ii.fIcon = TRUE; ii.hbmColor = hBmp; ii.hbmMask = CreateBitmap(16, 16, 1, 1, NULL); HICON hIcon = CreateIconIndirect(&ii); // 清理资源 SelectObject(hMemDC, hOldFont); DeleteObject(hFont); SelectObject(hMemDC, hOldBmp); DeleteObject(hBmp); DeleteDC(hMemDC); ReleaseDC(NULL); DeleteObject(ii.hbmMask); return hIcon; }
5. 程序退出清理
在OnDestroy中移除托盘图标并释放资源:
void CCPUMonitorDlg::OnDestroy() { Shell_NotifyIcon(NIM_DELETE, &m_nid); if (m_hQuery) PdhCloseQuery(m_hQuery); CDialogEx::OnDestroy(); }
内容的提问来源于stack exchange,提问作者Shellong
相关产品推荐
相关产品推荐

