Congratulations on visiting the 【JueDingGe Programming】 WeChat public account 【Knowledge Repository】, specially customized for everyoneQt C++ Architect Series – Project Practice Episode 126:This issue focuses on a practical and challenging technical topic – 【QTableView + QAbstractTableModel + Custom Delegate Project Technology: Disk Heartbeat Monitoring Performance Analyzer】.Whether you are a beginner who has just mastered the Qt cross-platform framework and Linux C/C++ backend server development, or a developer who wants to delve into the research of C/C++ system architecture, this technology will open a door to deep learning for you.
【Development Environment】: Win10/11 x64, Qt version 6.8 ;
【Daily sharing of quality projects and cutting-edge technical programming content!】
【Follow the UP master and join the QQ group】: 【895876809 Download project source code (for research and study)】.
1: 【Project】📁 Source Structure

2: 【Project】🚀 Running Results

3: 【Project】🏗️ Project Overview and Features
1: Project Overview
A cross-platform (verified on Windows 10+) disk usage monitoring tool based on Qt Widgets. It uses a high-performance table drawn with QTableView + QAbstractTableModel + custom delegate, supporting system tray icons, threshold alarms, and persistent settings.
2: Features
Disk Volume Information: Displays the device name, mount point, file system, total capacity, used, remaining, and usage rate for each volume.
High Performance: QTableView + QAbstractTableModel + QStyledItemDelegate draws progress bars, avoiding frequent creation of child controls.
Statistics Card: Top overview (number of volumes, total space, used, remaining), updated in real-time with refresh.
Refresh and Status Bar: Supports manual “Refresh Now” refresh, with the bottom status bar displaying the last update time and overall usage rate.
Settings Dialog: Configurable refresh interval, Warning/Critical thresholds, and whether to enable notifications; settings are persisted via QSettings.
Threshold Alarm: Notifies through the system tray when exceeding thresholds; maintains the last alarm level for each volume to avoid repeated notifications.
System Tray: Minimizes to tray, with tray menu supporting Show / Quit.
Borderless rounded window: Custom title bar and drag movement, modern appearance.
4: 【Project】📋 Source Code Analysis
1: main.cpp File
#include "diskmonitor.h"
#include <QApplication>
#include <QIcon>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QCoreApplication::setOrganizationName("DiskTools");
QCoreApplication::setApplicationName("DiskMonitorPro");
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
app.setWindowIcon(QIcon(":/images/logo.ico"));
DiskMonitor monitor;
monitor.setWindowTitle("Disk Storage Core Performance Analyzer");
monitor.setWindowIcon(QIcon(":/images/logo.ico"));
monitor.show();
return app.exec();
}
2: diskmodel.h File
#pragma once
#include <QAbstractTableModel>
#include <QList>
#include <QStorageInfo>
#include <QString>
class DiskModel : public QAbstractTableModel {
Q_OBJECT
public:
enum Columns {
Column_Device = 0,
Column_MountPoint,
Column_FileSystem,
Column_Total,
Column_Used,
Column_Free,
Column_Usage,
Column_Count
};
enum Roles {
RoleUsagePercent = Qt::UserRole + 1
};
explicit DiskModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
void updateFromVolumes(const QList<QStorageInfo> &volumes,
qint64 &totalBytesOut,
qint64 &usedBytesOut,
qint64 &freeBytesOut);
private:
struct DiskRow {
QString deviceDisplayName;
QString mountPoint;
QString fileSystem;
qint64 totalBytes = 0;
qint64 usedBytes = 0;
qint64 freeBytes = 0;
double usagePercent = 0.0; // 0-100
};
QList<DiskRow> rows;
static QString formatSize(qint64 bytes);
};
3: diskmodel.cpp File
#include "diskmodel.h"
#include <QIcon>
#include <QString>
#include <QVariant>
#include <QModelIndex>
DiskModel::DiskModel(QObject *parent)
: QAbstractTableModel(parent) {}
int DiskModel::rowCount(const QModelIndex &parent) const {
if (parent.isValid()) return 0;
return rows.size();}
int DiskModel::columnCount(const QModelIndex &parent) const {
if (parent.isValid()) return 0;
return Column_Count;}
QVariant DiskModel::data(const QModelIndex &index, int role) const {
if (!index.isValid()) return QVariant();
const DiskRow &r = rows.at(index.row());
if (role == Qt::DisplayRole) {
switch (index.column()) {
case Column_Device: return r.deviceDisplayName;
case Column_MountPoint: return r.mountPoint;
case Column_FileSystem: return r.fileSystem;
case Column_Total: return formatSize(r.totalBytes);
case Column_Used: return formatSize(r.usedBytes);
case Column_Free: return formatSize(r.freeBytes);
case Column_Usage: return QString::number(r.usagePercent, 'f', 1) + "%";
default: return QVariant();
}
}
if (role == Qt::TextAlignmentRole) {
if (index.column() == Column_Device || index.column() == Column_MountPoint || index.column() == Column_FileSystem) {
return Qt::AlignCenter; // for visual consistency with original
}
return Qt::AlignCenter;
}
if (role == RoleUsagePercent && index.column() == Column_Usage) {
return r.usagePercent;
}
if (role == Qt::DecorationRole && index.column() == Column_Device) {
return QIcon(":/disk.png");
}
return QVariant();}
QVariant DiskModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case Column_Device: return "Device";
case Column_MountPoint: return "Mount Point";
case Column_FileSystem: return "File System";
case Column_Total: return "Total";
case Column_Used: return "Used";
case Column_Free: return "Free";
case Column_Usage: return "Usage";
default: return QVariant();
}
}
return QAbstractTableModel::headerData(section, orientation, role);}
Qt::ItemFlags DiskModel::flags(const QModelIndex &index) const {
if (!index.isValid()) return Qt::NoItemFlags;
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;}
void DiskModel::updateFromVolumes(const QList<QStorageInfo> &volumes,
qint64 &totalBytesOut,
qint64 &usedBytesOut,
qint64 &freeBytesOut) {
QList<DiskRow> newRows;
totalBytesOut = usedBytesOut = freeBytesOut = 0;
for (const QStorageInfo &v : volumes) {
if (!v.isValid() || (v.isRoot() && !v.isReady())) continue;
const qint64 total = v.bytesTotal();
if (total <= 0) continue;
const qint64 freeB = v.bytesFree();
const qint64 usedB = total - freeB;
const double usage = total > 0 ? (double)usedB / (double)total * 100.0 : 0.0;
DiskRow r;
r.deviceDisplayName = v.displayName().isEmpty() ? QString::fromUtf8(v.device()).split('/').last() : v.displayName();
r.mountPoint = v.rootPath();
r.fileSystem = QString::fromUtf8(v.fileSystemType());
r.totalBytes = total;
r.usedBytes = usedB;
r.freeBytes = freeB;
r.usagePercent = usage;
newRows.push_back(r);
totalBytesOut += total;
usedBytesOut += usedB;
freeBytesOut += freeB;
}
beginResetModel();
rows.swap(newRows);
endResetModel();}
QString DiskModel::formatSize(qint64 bytes) {
constexpr qint64 TB = 1024LL * 1024LL * 1024LL * 1024LL;
constexpr qint64 GB = 1024LL * 1024LL * 1024LL;
constexpr qint64 MB = 1024LL * 1024LL;
if (bytes >= TB) return QString::number((double)bytes / TB, 'f', 1) + " TB";
if (bytes >= GB) return QString::number((double)bytes / GB, 'f', 1) + " GB";
if (bytes >= MB) return QString::number((double)bytes / MB, 'f', 1) + " MB";
return QString::number(bytes) + " bytes";
}
4: diskmonitor.h File
#pragma once
#include <QWidget>
#include <QPoint>
#include <QString>
#include <QPaintEvent>
#include <QMouseEvent>
class QTableView;
class QLabel;
class QTimer;
class QSystemTrayIcon;
class QHBoxLayout;
class QPushButton;
class QPaintEvent;
class QMouseEvent;
class QSortFilterProxyModel;
class DiskModel;
class UsageProgressDelegate;
class SettingsDialog;
class DiskMonitor : public QWidget {
Q_OBJECT
public:
explicit DiskMonitor(QWidget *parent = nullptr);
private slots:
void updateDiskInfo();
private:
void applyStyle();
QWidget* createStatBox(const QString &title, const QString &value,
const QString &iconName, const QString &color);
void updateStatBoxText(int index, const QString &value);
QPushButton* createControlButton(const QString &text);
void createSystemTray();
protected:
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
QString formatSize(qint64 bytes);
private:
QTableView *tableView;
QLabel *statusLabel;
QWidget *statBoxes[4];
QLabel *valueLabels[4];
int valueLabelCount = 0;
QTimer *timer;
QSystemTrayIcon *trayIcon;
QPoint dragPosition;
QHBoxLayout *statusBarLayout;
DiskModel *diskModel;
QSortFilterProxyModel *proxyModel;
UsageProgressDelegate *usageDelegate;
SettingsDialog *settingsDialog;
int refreshIntervalMs = 3000;
int warnThresholdPercent = 75;
int criticalThresholdPercent = 90;
bool notificationsEnabled = true;
QHash<QString, int> lastAlertLevelByVolume; // 0=none,1=warn,2=critical
};
5: diskmonitor.cpp File
#include "diskmonitor.h"
#include <QApplication>
#include <QTableView>
#include <QHeaderView>
#include <QLabel>
#include <QTimer>
#include <QStorageInfo>
#include <QVBoxLayout>
#include <QPalette>
#include <QPushButton>
#include <QPixmap>
#include <QIcon>
#include <QGraphicsDropShadowEffect>
#include <QHBoxLayout>
#include <QSystemTrayIcon>
#include <QMenu>
#include <QPainter>
#include <QPainterPath>
#include <QTime>
#include <QSortFilterProxyModel>
#include <QSettings>
#include <QMouseEvent>
#include "diskmodel.h"
#include "usageprogressdelegate.h"
#include "settingsdialog.h"
DiskMonitor::DiskMonitor(QWidget *parent) : QWidget(parent) {
setWindowTitle("Disk Monitor Pro");
resize(950, 600);
setMinimumSize(950, 600);
setWindowFlags(Qt::FramelessWindowHint);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(20, 15, 20, 15);
mainLayout->setSpacing(10);
setLayout(mainLayout);
QHBoxLayout *titleLayout = new QHBoxLayout();
titleLayout->setContentsMargins(0, 0, 0, 10);
QLabel *iconLabel = new QLabel(this);
iconLabel->setPixmap(QPixmap(":/icon.png").scaled(32, 32,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
titleLayout->addWidget(iconLabel);
QLabel *titleLabel = new QLabel("Disk Storage Core Performance Analyzer (Disk Storage Analyzer)", this);
QFont titleFont("Arial", 18, QFont::DemiBold);
titleLabel->setFont(titleFont);
titleLabel->setStyleSheet("color: #2C3E50;");
titleLayout->addWidget(titleLabel);
titleLayout->addStretch();
QPushButton *minimizeBtn = createControlButton("−");
QPushButton *closeBtn = createControlButton("✕");
connect(minimizeBtn, &QPushButton::clicked, this, &QWidget::showMinimized);
connect(closeBtn, &QPushButton::clicked, qApp, &QApplication::quit);
titleLayout->addWidget(minimizeBtn);
titleLayout->addWidget(closeBtn);
mainLayout->addLayout(titleLayout);
QHBoxLayout *statsLayout = new QHBoxLayout();
statsLayout->setSpacing(15);
statBoxes[0] = createStatBox("Total Volumes", "0", "disk.png", "#3498DB");
statBoxes[1] = createStatBox("Total Space", "0 GB", "capacity.png", "#2ECC71");
statBoxes[2] = createStatBox("Used Space", "0 GB", "used.png", "#E74C3C");
statBoxes[3] = createStatBox("Free Space", "0 GB", "free.png", "#9B59B6");
for (int i = 0; i < 4; ++i) {
statsLayout->addWidget(statBoxes[i]);
}
mainLayout->addLayout(statsLayout);
mainLayout->addSpacing(10);
QWidget *tableContainer = new QWidget(this);
tableContainer->setStyleSheet("background-color: #FFFFFF; border-radius: 12px;");
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
shadow->setBlurRadius(20);
shadow->setOffset(0, 5);
shadow->setColor(QColor(0, 0, 0, 30));
tableContainer->setGraphicsEffect(shadow);
QVBoxLayout *containerLayout = new QVBoxLayout(tableContainer);
containerLayout->setContentsMargins(0, 0, 0, 0);
tableView = new QTableView(this);
tableView->horizontalHeader()->setMinimumHeight(40);
tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
tableView->verticalHeader()->setDefaultSectionSize(30);
tableView->verticalHeader()->setVisible(false);
tableView->setAlternatingRowColors(true);
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::NoSelection);
tableView->setStyleSheet("border: none;");
diskModel = new DiskModel(this);
proxyModel = new QSortFilterProxyModel(this);
proxyModel->setSourceModel(diskModel);
proxyModel->setDynamicSortFilter(true);
tableView->setModel(proxyModel);
usageDelegate = new UsageProgressDelegate(this);
tableView->setItemDelegateForColumn(DiskModel::Column_Usage, usageDelegate);
tableView->horizontalHeader()->setSectionResizeMode(DiskModel::Column_Usage, QHeaderView::Fixed);
tableView->horizontalHeader()->resizeSection(DiskModel::Column_Usage, 180);
containerLayout->addWidget(tableView);
mainLayout->addWidget(tableContainer);
statusBarLayout = new QHBoxLayout();
statusBarLayout->setContentsMargins(5, 5, 5, 5);
statusLabel = new QLabel("Initializing...", this);
statusLabel->setFont(QFont("Arial", 9));
statusBarLayout->addWidget(statusLabel);
QPushButton *refreshBtn = new QPushButton("Refresh Now", this);
refreshBtn->setFont(QFont("Arial", 9));
refreshBtn->setCursor(Qt::PointingHandCursor);
refreshBtn->setStyleSheet(
"QPushButton {"
" background-color: #5D6D7E;"
" color: white;"
" padding: 5px 10px;"
" border-radius: 4px;"
" border: none;"
"}"
"QPushButton:hover {"
" background-color: #4A5A6A;"
"}"
"QPushButton:pressed {"
" background-color: #3C4B59;"
"}"
);
connect(refreshBtn, &QPushButton::clicked, this, &DiskMonitor::updateDiskInfo);
QPushButton *settingsBtn = new QPushButton("Settings", this);
settingsBtn->setFont(QFont("Arial", 9));
settingsBtn->setCursor(Qt::PointingHandCursor);
settingsBtn->setStyleSheet(
"QPushButton {"
" background-color: #5D6D7E;"
" color: white;"
" padding: 5px 10px;"
" border-radius: 4px;"
" border: none;"
"}"
"QPushButton:hover {"
" background-color: #4A5A6A;"
"}"
"QPushButton:pressed {"
" background-color: #3C4B59;"
"}"
);
connect(settingsBtn, &QPushButton::clicked, this, [this]{
if (!settingsDialog) settingsDialog = new SettingsDialog(this);
settingsDialog->setRefreshIntervalMs(refreshIntervalMs);
settingsDialog->setWarnThresholdPercent(warnThresholdPercent);
settingsDialog->setCriticalThresholdPercent(criticalThresholdPercent);
settingsDialog->setNotificationsEnabled(notificationsEnabled);
if (settingsDialog->exec() == QDialog::Accepted) {
refreshIntervalMs = settingsDialog->refreshIntervalMs();
warnThresholdPercent = settingsDialog->warnThresholdPercent();
criticalThresholdPercent = settingsDialog->criticalThresholdPercent();
notificationsEnabled = settingsDialog->notificationsEnabled();
timer->stop();
timer->start(refreshIntervalMs);
QSettings s;
s.setValue("refreshIntervalMs", refreshIntervalMs);
s.setValue("warnThresholdPercent", warnThresholdPercent);
s.setValue("criticalThresholdPercent", criticalThresholdPercent);
s.setValue("notificationsEnabled", notificationsEnabled);
}
});
statusBarLayout->addStretch();
statusBarLayout->addWidget(settingsBtn);
statusBarLayout->addWidget(refreshBtn);
mainLayout->addLayout(statusBarLayout);
QSettings s;
refreshIntervalMs = s.value("refreshIntervalMs", refreshIntervalMs).toInt();
warnThresholdPercent = s.value("warnThresholdPercent", warnThresholdPercent).toInt();
criticalThresholdPercent = s.value("criticalThresholdPercent", criticalThresholdPercent).toInt();
notificationsEnabled = s.value("notificationsEnabled", notificationsEnabled).toBool();
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &DiskMonitor::updateDiskInfo);
timer->start(refreshIntervalMs);
applyStyle();
createSystemTray();}
void DiskMonitor::updateDiskInfo() {
QList<QStorageInfo> volumes = QStorageInfo::mountedVolumes();
qint64 totalBytes = 0;
qint64 usedBytes = 0;
qint64 freeBytes = 0;
diskModel->updateFromVolumes(volumes, totalBytes, usedBytes, freeBytes);
// Threshold alerts
if (notificationsEnabled && trayIcon && trayIcon->isVisible()) {
for (int r = 0; r < diskModel->rowCount(); ++r) {
QModelIndex idxUsage = diskModel->index(r, DiskModel::Column_Usage);
double percent = idxUsage.data(DiskModel::RoleUsagePercent).toDouble();
QString name = diskModel->index(r, DiskModel::Column_Device).data().toString();
int level = 0;
if (percent >= criticalThresholdPercent) level = 2;
else if (percent >= warnThresholdPercent) level = 1;
int lastLevel = lastAlertLevelByVolume.value(name, 0);
if (level > lastLevel) {
if (level == 2) {
trayIcon->showMessage("Disk Critical",
QString("%1 usage %2% exceeds %3%")
.arg(name)
.arg(QString::number(percent, 'f', 1))
.arg(criticalThresholdPercent),
QIcon(":/icon.png"), 5000);
} else if (level == 1) {
trayIcon->showMessage("Disk Warning",
QString("%1 usage %2% exceeds %3%")
.arg(name)
.arg(QString::number(percent, 'f', 1))
.arg(warnThresholdPercent),
QIcon(":/icon.png"), 4000);
}
}
lastAlertLevelByVolume.insert(name, level);
}
}
updateStatBoxText(0, QString::number(diskModel->rowCount()));
updateStatBoxText(1, formatSize(totalBytes));
updateStatBoxText(2, formatSize(usedBytes));
updateStatBoxText(3, formatSize(freeBytes));
statusLabel->setText(QString("Last updated: %1 | %2 volumes detected | System disk usage: %3%")
.arg(QTime::currentTime().toString("hh:mm:ss") )
.arg(diskModel->rowCount())
.arg(totalBytes > 0 ? (usedBytes * 100 / totalBytes) : 0));}
void DiskMonitor::applyStyle() {
QPalette pal;
pal.setColor(QPalette::Window, QColor("#ECF0F1"));
pal.setColor(QPalette::Base, QColor("#FFFFFF"));
pal.setColor(QPalette::AlternateBase, QColor("#F8F9F9"));
pal.setColor(QPalette::Text, QColor("#2C3E50"));
pal.setColor(QPalette::Button, QColor("#5D6D7E"));
setPalette(pal);
setAttribute(Qt::WA_TranslucentBackground);
setStyleSheet(
"DiskMonitor {"
" background-color: #ECF0F1;"
" border-radius: 16px;"
" border: 1px solid #D5D8DC;"
"}"
);
tableView->setStyleSheet(
"QTableWidget {"
" background-color: white;"
" gridline-color: #EAEDED;"
" border-radius: 12px;"
" border: none;"
"}"
"QHeaderView::section {"
" background-color: #2C3E50;"
" color: white;"
" font-weight: bold;"
" font-family: 'Arial';"
" padding: 12px 8px;"
" border: none;"
" font-size: 12pt;"
"}"
"QTableView::item {"
" font-family: 'Arial';"
" padding: 5px 8px;"
" border: none;"
" border-bottom: 1px solid #EAEDED;"
"}"
"QTableView::item:alternate {"
" background-color: #F8F9F9;"
"}"
);
}
QWidget* DiskMonitor::createStatBox(const QString &title, const QString &value,
const QString &iconName, const QString &color) {
QWidget *statBox = new QWidget(this);
statBox->setMinimumHeight(70);
statBox->setStyleSheet(
QString(
"QWidget {"
" background-color: %1;"
" border-radius: 8px;"
" padding: 10px;"
"}"
).arg(color)
);
QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect;
shadow->setBlurRadius(12);
shadow->setOffset(0, 4);
shadow->setColor(QColor(0, 0, 0, 40));
statBox->setGraphicsEffect(shadow);
QHBoxLayout *layout = new QHBoxLayout(statBox);
layout->setContentsMargins(12, 8, 12, 8);
QLabel *iconLabel = new QLabel();
iconLabel->setPixmap(QPixmap(QString(":/%1").arg(iconName)).scaled(30, 30,
Qt::KeepAspectRatio, Qt::SmoothTransformation));
iconLabel->setStyleSheet("background: transparent;");
layout->addWidget(iconLabel);
QVBoxLayout *textLayout = new QVBoxLayout();
textLayout->setContentsMargins(10, 0, 0, 0);
textLayout->setSpacing(2);
QLabel *titleLabel = new QLabel(title);
titleLabel->setStyleSheet(
"color: white;"
"font-family: 'Arial';"
"font-size: 10pt;"
);
valueLabels[valueLabelCount] = new QLabel(value);
valueLabels[valueLabelCount]->setStyleSheet(
"color: white;"
"font-family: 'Arial';"
"font-weight: bold;"
"font-size: 14pt;"
);
valueLabels[valueLabelCount]->setTextFormat(Qt::RichText);
textLayout->addWidget(titleLabel);
textLayout->addWidget(valueLabels[valueLabelCount]);
layout->addLayout(textLayout);
layout->addStretch();
valueLabelCount++;
return statBox;
}
void DiskMonitor::updateStatBoxText(int index, const QString &value) {
if (index < 0 || index >= valueLabelCount) return;
if (valueLabels[index]) {
valueLabels[index]->setText(QString("<b>%1</b>").arg(value));
}}
QPushButton* DiskMonitor::createControlButton(const QString &text) {
QPushButton *btn = new QPushButton(text, this);
btn->setFixedSize(30, 30);
btn->setStyleSheet(
"QPushButton {"
" background-color: #5D6D7E;"
" color: white;"
" border-radius: 15px;"
" font-size: 15px;"
" font-weight: bold;"
"}"
"QPushButton:hover {"
" background-color: #34495E;"
"}"
"QPushButton:pressed {"
" background-color: #2C3E50;"
"}"
);
return btn;
}
void DiskMonitor::createSystemTray() {
trayIcon = new QSystemTrayIcon(this);
trayIcon->setIcon(QIcon(":/icon.png"));
trayIcon->setToolTip("Disk Monitor Pro");
QMenu *trayMenu = new QMenu(this);
trayMenu->setStyleSheet(
"QMenu {"
" background-color: white;"
" border: 1px solid #D5D8DC;"
" border-radius: 4px;"
" padding: 5px;"
"}"
"QMenu::item {"
" padding: 5px 20px;"
" font-family: 'Arial';"
"}"
"QMenu::item:selected {"
" background-color: #5D6D7E;"
" color: white;"
" border-radius: 2px;"
"}"
);
QAction *restoreAction = new QAction("Show", this);
QAction *quitAction = new QAction("Quit", this);
connect(restoreAction, &QAction::triggered, this, &QWidget::showNormal);
connect(quitAction, &QAction::triggered, qApp, &QApplication::quit);
trayMenu->addAction(restoreAction);
trayMenu->addSeparator();
trayMenu->addAction(quitAction);
trayIcon->setContextMenu(trayMenu);
trayIcon->show();
connect(trayIcon, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason){
if (reason == QSystemTrayIcon::Trigger) {
if (isHidden()) showNormal();
else hide();
}
});
}
void DiskMonitor::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
QPainterPath path;
path.addRoundedRect(rect(), 16, 16);
painter.fillPath(path, palette().window());
QWidget::paintEvent(event);
}
void DiskMonitor::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
dragPosition = event->globalPosition().toPoint() - frameGeometry().topLeft();
event->accept();
}}
void DiskMonitor::mouseMoveEvent(QMouseEvent *event) {
if (event->buttons() & Qt::LeftButton) {
move(event->globalPosition().toPoint() - dragPosition);
event->accept();
}}
QString DiskMonitor::formatSize(qint64 bytes) {
constexpr qint64 TB = 1024LL * 1024LL * 1024LL * 1024LL;
constexpr qint64 GB = 1024LL * 1024LL * 1024LL;
constexpr qint64 MB = 1024LL * 1024LL;
if (bytes >= TB)
return QString::number((double)bytes / TB, 'f', 1) + " TB";
else if (bytes >= GB)
return QString::number((double)bytes / GB, 'f', 1) + " GB";
else if (bytes >= MB)
return QString::number((double)bytes / MB, 'f', 1) + " MB";
else
return QString::number(bytes) + " bytes";
}
Due to space limitations, please follow the UP master and join the group to download the project source code for research and study.