CPU / Memory Monitor 手搓手册
source:成品答案在
app/04-system-tools/cpu-memory-monitor/(做完对照)· related:app 栏系统工具类整机成品
⚠️ Windows 路径尚未验证
本手册所有 Windows 路径(GlobalMemoryStatusEx / GetSystemTimes)的描述均基于代码逻辑推断,未实跑验证——offscreen 环境跑不了 Windows。如果你在 Linux/WSL 上跟着搓,验证的是 /proc 路径;Windows 路径代码照写、编译用 #ifdef Q_OS_WIN 隔离,但需要 Windows 实机复验。详见 troubleshooting。
这是「手搓手册」
不是参考手册(查完走),是 workbook(跟着搓)。每个 step 给目标 → 提示 → 检查点,成品 repo 当答案钥匙——卡住了去对照,别整段复制。
0. 你将学到
搓完这个系统监控,你会打通这几样 Qt 能力(每样后面都有教程深挖,这里先用起来):
- 跨平台系统读取:
#ifdef Q_OS_LINUX / Q_OS_WIN分发,Linux 读/proc文本、Windows 调 Win32 API,未覆盖平台 fallback - QFile 文本读取:
QFile+QTextStream逐行扫/proc/meminfo、split解析/proc/stat数字 - 两次采样差值:理解为什么 CPU 占用率不能单次直读(开机累计值 vs 瞬时占用),用基线 + 差值算
- QPainter 自绘曲线:
QPainterPath画折线 + 半透明面积填充 + 参考网格 + 滚动窗口 - QTimer 节拍刷新:
timeout信号驱动周期采样,采样间隔与精度的权衡 - QProgressBar 进度条:
setRange(0,100)+ 数值另用 label 显示(已用/总量更直观) - 无效态降级:平台不支持或读取失败时显示 N/A、曲线留缺口,不崩不留哑数据
- QMainWindow 整机装配:QVBoxLayout + QGroupBox 分组(Memory/CPU)+ 状态栏
1. 起点
先有个能读 /proc/meminfo 并打印到终端的小程序。最小 Qt 工程(Core 即可,先不画 UI):
#include <QCoreApplication>
#include <QFile>
#include <QTextStream>
#include <QDebug>
int main(int argc, char* argv[]) {
QCoreApplication app(argc, argv);
QFile f("/proc/meminfo");
if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&f);
qDebug().noquote() << in.readLine(); // 第一行 "MemTotal: ..."
}
return 0;
}能打印出 MemTotal: 16384000 kB = /proc 读取通了。QFile 不熟先看 文件与 IO,QObject/状态机不熟看 QObject 与元对象系统。
注意:工程链
Qt6::Widgets(后面要画 UI);Windows 分支系统调用只在Q_OS_WIN时才#include <windows.h>,Linux 编译时整段被#ifdef剔掉。CMakeLists.txt的target_link_libraries加Qt6::Core Qt6::Gui Qt6::Widgets,Windows 额外加if(WIN32) target_link_libraries(... kernel32) endif()。
2. 任务清单
分 3 步(一文件/一阶段一步),每步:目标 → 提示 → 检查点。卡住翻 卡住怎么办。
| Step | 目标 | 进 |
|---|---|---|
| 1 | 跨平台系统读取(内存 /proc/meminfo + Windows GlobalMemoryStatusEx)+ CPU 两次采样差值(CpuSampler 状态机) | 01 |
| 2 | 自绘 CPU 历史曲线(滚动窗口 + QPainter 折线 + 面积填充 + 参考网格 + 无效点断开留缺口) | 02 |
| 3 | 主窗口装配(QProgressBar + QGroupBox 分组)+ QTimer 1s 节拍刷新 + 无效态降级 + Windows kernel32 链接 | 03 |
成品对照:app/04-system-tools/cpu-memory-monitor/(按 成品导览 的「怎么读」顺序对照)。
3. 进阶挑战(可选)
搓完基础版想再深一层:
- 每核 CPU:现在读
/proc/stataggregate(所有核合计)。提示:往下读cpu0/cpu1/... 每行,每个核一个CpuSampler,曲线画成多层堆叠。 - 磁盘/网络 IO:提示:Linux 读
/proc/diskstats(磁盘)、/proc/net/dev(网络),同样两次采样差值算速率,曲线复用CpuHistoryView换皮。 - 进程列表:提示:Linux 遍历
/proc/[pid]/读stat/status/cmdline,QTableWidget 展示 top-N 进程。 - macOS 支持:现在 macOS 走 fallback 显示 N/A。提示:加
#elif Q_OS_DARWIN,用host_statistics64(mach/mach_host.h)读内存、host_processor_info读 CPU。 - Windows 实机复验:⚠️ 现在最大的技术债——Windows 路径代码写好未跑。提示:在 Windows 实机编译运行,验证
GlobalMemoryStatusEx(dwLength必须先设)和GetSystemTimes(busy = kernel - idle + user),把实测结果回填文档。 - 采样精度自适应:现在固定 1s。提示:UI 提供档位(500ms / 1s / 2s),动态
setInterval,看不同档位下曲线平滑度差异。 - 数据持久化:提示:把历史采样存 CSV/SQLite,下次启动可回放历史曲线(参考 sqlite-browser 的数据建模)。
- 下一站:app 栏的 serial-tool / network-tool——换皮复用「周期采样 + 自绘曲线 + QTimer 节拍」骨架,但数据源换成 QSerialPort / QTcpSocket。