#include "mainwindow.h"
|
#include "ui_mainwindow.h"
|
|
#include <QFile>
|
#include <QTextStream>
|
#include <QDateTimeAxis>
|
#include <QValueAxis>
|
#include <QBarCategoryAxis>
|
#include <QChartView>
|
#include <QVBoxLayout>
|
#include <QSharedMemory>
|
#include <QSystemSemaphore>
|
#include <QMessageBox>
|
#include <QtCharts/QBarSet>
|
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),
|
m_timer(new QTimer(this))
|
{
|
// 检查是否已有实例运行
|
if (isAlreadyRunning()) {
|
QMessageBox::warning(nullptr, "Warning", "Another instance is already running");
|
exit(0);
|
}
|
|
// 初始化数据库
|
if (!initDatabase()) {
|
QMessageBox::warning(this, "Warning", "Failed to connect to database");
|
}
|
|
// 设置主窗口
|
setWindowTitle("System Monitor");
|
resize(800, 600);
|
|
// 创建CPU图表
|
m_cpuChart = new QChart();
|
m_cpuChart->setTitle("CPU Usage (%)");
|
m_cpuSeries = new QLineSeries();
|
m_cpuChart->addSeries(m_cpuSeries);
|
|
QDateTimeAxis *cpuAxisX = new QDateTimeAxis();
|
cpuAxisX->setFormat("hh:mm:ss");
|
m_cpuChart->addAxis(cpuAxisX, Qt::AlignBottom);
|
m_cpuSeries->attachAxis(cpuAxisX);
|
|
QValueAxis *cpuAxisY = new QValueAxis();
|
cpuAxisY->setRange(0, 100);
|
m_cpuChart->addAxis(cpuAxisY, Qt::AlignLeft);
|
m_cpuSeries->attachAxis(cpuAxisY);
|
|
// 创建磁盘图表
|
m_diskChart = new QChart();
|
m_diskChart->setTitle("Disk I/O (KB/s)");
|
m_diskSeries = new QBarSeries();
|
m_diskChart->addSeries(m_diskSeries);
|
|
QBarCategoryAxis *diskAxisX = new QBarCategoryAxis();
|
m_diskChart->addAxis(diskAxisX, Qt::AlignBottom);
|
m_diskSeries->attachAxis(diskAxisX);
|
|
QValueAxis *diskAxisY = new QValueAxis();
|
m_diskChart->addAxis(diskAxisY, Qt::AlignLeft);
|
m_diskSeries->attachAxis(diskAxisY);
|
|
// 设置布局
|
QWidget *centralWidget = new QWidget(this);
|
QVBoxLayout *layout = new QVBoxLayout(centralWidget);
|
|
QChartView *cpuChartView = new QChartView(m_cpuChart);
|
cpuChartView->setRenderHint(QPainter::Antialiasing);
|
layout->addWidget(cpuChartView);
|
|
QChartView *diskChartView = new QChartView(m_diskChart);
|
diskChartView->setRenderHint(QPainter::Antialiasing);
|
layout->addWidget(diskChartView);
|
|
centralWidget->setLayout(layout);
|
setCentralWidget(centralWidget);
|
|
// 启动定时器
|
m_timer->start(1000); // 每秒更新一次
|
connect(m_timer.get(), &QTimer::timeout, this, &MainWindow::updateSystemStats);
|
}
|
|
MainWindow::~MainWindow()
|
{
|
if (m_db.isOpen()) {
|
m_db.close();
|
}
|
}
|
|
bool MainWindow::initDatabase()
|
{
|
m_db = QSqlDatabase::addDatabase("QMYSQL");
|
m_db.setHostName("localhost");
|
m_db.setDatabaseName("system_monitor");
|
m_db.setUserName("monitor_user");
|
m_db.setPassword("monitor_pass");
|
|
if (!m_db.open()) {
|
return false;
|
}
|
|
// 创建表(如果不存在)
|
QSqlQuery query;
|
query.exec("CREATE TABLE IF NOT EXISTS cpu_usage ("
|
"id INT AUTO_INCREMENT PRIMARY KEY, "
|
"usage DOUBLE NOT NULL, "
|
"timestamp DATETIME NOT NULL)");
|
|
query.exec("CREATE TABLE IF NOT EXISTS disk_stats ("
|
"id INT AUTO_INCREMENT PRIMARY KEY, "
|
"device VARCHAR(50) NOT NULL, "
|
"read_bytes BIGINT NOT NULL, "
|
"write_bytes BIGINT NOT NULL, "
|
"timestamp DATETIME NOT NULL)");
|
|
return true;
|
}
|
|
bool MainWindow::isAlreadyRunning()
|
{
|
QSharedMemory sharedMem("MainWindow");
|
if (sharedMem.attach()) {
|
return true;
|
}
|
return !sharedMem.create(1);
|
}
|
|
void MainWindow::updateSystemStats()
|
{
|
QDateTime timestamp = QDateTime::currentDateTime();
|
|
// 1. 获取CPU使用率
|
QFile cpuFile("/proc/stat");
|
if (cpuFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
QTextStream in(&cpuFile);
|
QString line = in.readLine();
|
cpuFile.close();
|
|
QStringList list = line.split(' ', QString::SkipEmptyParts);
|
if (list.size() >= 5) {
|
qint64 user = list[1].toLong();
|
qint64 nice = list[2].toLong();
|
qint64 system = list[3].toLong();
|
qint64 idle = list[4].toLong();
|
|
qint64 total = user + nice + system + idle;
|
qint64 deltaTotal = total - m_lastTotal;
|
qint64 deltaIdle = idle - m_lastIdle;
|
|
m_lastTotal = total;
|
m_lastIdle = idle;
|
|
if (deltaTotal > 0) {
|
double usage = (deltaTotal - deltaIdle) * 100.0 / deltaTotal;
|
|
// 更新CPU图表
|
static QList<QDateTime> timePoints;
|
timePoints.append(timestamp);
|
|
if (timePoints.size() > 60) {
|
timePoints.removeFirst();
|
m_cpuSeries->removePoints(0, 1);
|
}
|
|
m_cpuSeries->append(timestamp.toMSecsSinceEpoch(), usage);
|
|
// 存储到数据库
|
if (m_db.isOpen()) {
|
QSqlQuery query;
|
query.prepare("INSERT INTO cpu_usage (usage, timestamp) VALUES (?, ?)");
|
query.addBindValue(usage);
|
query.addBindValue(timestamp);
|
query.exec();
|
}
|
}
|
}
|
}
|
|
// 2. 获取磁盘I/O
|
QFile diskFile("/proc/diskstats");
|
if (diskFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
QTextStream in(&diskFile);
|
QMap<QString, qint64> currentReadBytes;
|
QMap<QString, qint64> currentWriteBytes;
|
|
while (!in.atEnd()) {
|
QString line = in.readLine();
|
QStringList parts = line.split(' ', QString::SkipEmptyParts);
|
|
if (parts.size() >= 14) {
|
QString device = parts[2];
|
if (device.startsWith("loop") || device.startsWith("ram")) {
|
continue;
|
}
|
|
qint64 readBytes = parts[5].toLongLong() * 512; // sectors to bytes
|
qint64 writeBytes = parts[9].toLongLong() * 512;
|
|
currentReadBytes[device] = readBytes;
|
currentWriteBytes[device] = writeBytes;
|
}
|
}
|
diskFile.close();
|
|
// 计算增量并更新
|
for (auto it = currentReadBytes.begin(); it != currentReadBytes.end(); ++it) {
|
const QString &device = it.key();
|
qint64 readBytes = it.value();
|
qint64 writeBytes = currentWriteBytes[device];
|
|
if (m_lastDiskStats.contains(device + "_read")) {
|
qint64 deltaRead = readBytes - m_lastDiskStats[device + "_read"];
|
qint64 deltaWrite = writeBytes - m_lastDiskStats[device + "_write"];
|
|
double readKB = deltaRead / 1024.0;
|
double writeKB = deltaWrite / 1024.0;
|
|
// 更新磁盘图表
|
if (!m_diskBarSets.contains(device + "_read")) {
|
QBarSet *readSet = new QBarSet(device + " Read");
|
QBarSet *writeSet = new QBarSet(device + " Write");
|
m_diskBarSets[device + "_read"] = readSet;
|
m_diskBarSets[device + "_write"] = writeSet;
|
m_diskSeries->append(readSet);
|
m_diskSeries->append(writeSet);
|
|
QStringList categories;
|
for (const QString &key : m_diskBarSets.keys()) {
|
if (key.endsWith("_read")) {
|
categories << QString(key).replace("_read", "");
|
}
|
}
|
qobject_cast<QBarCategoryAxis*>(m_diskChart->axes(Qt::Horizontal).first())
|
->setCategories(categories);
|
}
|
|
m_diskBarSets[device + "_read"]->replace(0, readKB);
|
m_diskBarSets[device + "_write"]->replace(0, writeKB);
|
|
// 存储到数据库
|
if (m_db.isOpen()) {
|
QSqlQuery query;
|
query.prepare("INSERT INTO disk_stats (device, read_bytes, write_bytes, timestamp) "
|
"VALUES (?, ?, ?, ?)");
|
query.addBindValue(device);
|
query.addBindValue(deltaRead);
|
query.addBindValue(deltaWrite);
|
query.addBindValue(timestamp);
|
query.exec();
|
}
|
}
|
|
m_lastDiskStats[device + "_read"] = readBytes;
|
m_lastDiskStats[device + "_write"] = writeBytes;
|
}
|
}
|
}
|