当前位置: 首页 > news >正文

【QT入门到晋级】QT项目中加入qml界面(包含源码)

前言

        本篇的分享的需求场景是”在系统托盘的右键菜单中,增加一个点击之后,显示CPU占有率的圆形动态图“,系统托盘及托盘的其他右键菜单已经用qt来实现了,因为qt实现”动态图“的效果是比较差的,所以本文分享的是”CPU占有率“右键菜单,弹出的是一个qml窗口,即qt+qml结合的项目。

效果图

功能讲解

系统托盘的功能引用之前分享的博文,本文就不再详细讲解qt的系统托盘部分功能,主要讲解在此系统托盘的基础上,如何加入qml代码,并实现右键菜单功能。

【QT常用技术讲解】QSystemTrayIcon系统托盘-CSDN博客文章浏览阅读456次,点赞4次,收藏2次。项目中需要提供窗口的服务时,就会用到系统托盘。系统托盘支持右键菜单,也支持(左下角)系统消息提醒等实用的功能。_qsystemtrayicon https://blog.csdn.net/liangyuna8787/article/details/149550230?spm=1011.2124.3001.6209

第一步 增加CPU监控实现

新建一个C++  class类CpuMonitor,如下图操作到创建成功

以下是实现的代码

//cpumonitor.h
#ifndef CPUMONITOR_H
#define CPUMONITOR_H#include <QObject>
#include <QTimer>
#include <QProcess>
#include <QDebug>
class CpuMonitor : public QObject
{Q_OBJECT//定义QML可以访问的属性//​​int cpuUsage READ cpuUsage 告诉 Qt 元对象系统,获取此属性值时应调用 cpuUsage()成员函数//​​NOTIFY cpuUsageChanged 指定通知信号,当属性值变化时,CpuMonitor主动发送cpuUsageChanged()信号,qml需要接收此信号Q_PROPERTY(int cpuUsage READ cpuUsage NOTIFY cpuUsageChanged)
public:explicit CpuMonitor(QObject *parent = nullptr);int cpuUsage() const;signals:void cpuUsageChanged();private slots:void updateCpuUsage();private:int m_cpuUsage;QTimer *timer;qint64 lastIdleTime;qint64 lastTotalTime;void getCpuTimes(qint64 &idleTime, qint64 &totalTime);};#endif // CPUMONITOR_H

需要注意的是,一定要加上这一行代码,用于向qml发送信号:

    //定义QML可以访问的属性//​​int cpuUsage READ cpuUsage 告诉 Qt 元对象系统,获取此属性值时应调用 cpuUsage()成员函数//​​NOTIFY cpuUsageChanged 指定通知信号,当属性值变化时,CpuMonitor主动发送cpuUsageChanged()信号,qml需要接收此信号Q_PROPERTY(int cpuUsage READ cpuUsage NOTIFY cpuUsageChanged)

通过定时器每秒中获取一次CPU,并发出cpuUsageChanged信号

//cpumonitor.cpp
#include "cpumonitor.h"
#include <QFile>
#include <QTextStream>
#include <QProcess>CpuMonitor::CpuMonitor(QObject *parent) : QObject(parent)
{// 初始化定时器timer = new QTimer(this);connect(timer, &QTimer::timeout, this, &CpuMonitor::updateCpuUsage);timer->start(1000); // 每秒更新一次// 获取初始CPU时间updateCpuUsage();
}int CpuMonitor::cpuUsage() const
{return m_cpuUsage;
}void CpuMonitor::updateCpuUsage()
{qint64 idleTime, totalTime;getCpuTimes(idleTime, totalTime);if(lastTotalTime != 0 && lastIdleTime != 0) {qint64 totalDiff = totalTime - lastTotalTime;qint64 idleDiff = idleTime - lastIdleTime;if(totalDiff > 0) {int usage = static_cast<int>((totalDiff - idleDiff) * 100.0 / totalDiff);if(usage != m_cpuUsage) {m_cpuUsage = usage;emit cpuUsageChanged();}}}lastIdleTime = idleTime;lastTotalTime = totalTime;
}void CpuMonitor::getCpuTimes(qint64 &idleTime, qint64 &totalTime)
{idleTime = 0;totalTime = 0;QProcess process;process.start("wmic", QStringList() << "cpu" << "get" << "LoadPercentage");process.waitForFinished();QString output = process.readAllStandardOutput();// 修复: 使用兼容的方式分割字符串QStringList lines = output.split('\n', QString::SkipEmptyParts);if(lines.size() >= 2) {QString usageStr = lines[1].trimmed();bool ok;int usage = usageStr.toInt(&ok);if(ok) {m_cpuUsage = usage;emit cpuUsageChanged();}}
}

第二步 增加系统托盘菜单

增加新的右键菜单,及对应的窗口显示、关闭相关的函数

//trayicon.h
#include <QQmlApplicationEngine>
#include "cpumonitor.h"class TrayIcon : public QSystemTrayIcon
{Q_OBJECT
public:void setCpuMonitor(CpuMonitor *monitor);void setQmlEngine(QQmlApplicationEngine *engine);private slots:void showCpuMonitor();void hideCpuMonitor();private:CpuMonitor *cpuMonitor;QQmlApplicationEngine *qmlEngine;QObject *qmlRootObject;
};
//trayicon.cpp
void TrayIcon::createTrayMenu()
{QAction *showAction = new QAction("显示CPU占用", this);QAction *hideAction = new QAction("隐藏监控窗口", this);menu->addAction(showAction);menu->addAction(hideAction);connect(showAction, &QAction::triggered, this, &TrayIcon::showCpuMonitor);connect(hideAction, &QAction::triggered, this, &TrayIcon::hideCpuMonitor);
}void TrayIcon::setCpuMonitor(CpuMonitor *monitor)
{cpuMonitor = monitor;
}void TrayIcon::setQmlEngine(QQmlApplicationEngine *engine)
{qmlEngine = engine;if(qmlEngine && !qmlEngine->rootObjects().isEmpty()) {qmlRootObject = qmlEngine->rootObjects().first();}
}void TrayIcon::showCpuMonitor()
{if(qmlRootObject) {QQuickWindow *window = qobject_cast<QQuickWindow*>(qmlRootObject);if(window) {window->show();window->raise();window->requestActivate();}}
}void TrayIcon::hideCpuMonitor()
{if(qmlRootObject) {QQuickWindow *window = qobject_cast<QQuickWindow*>(qmlRootObject);if(window) {window->hide();}}
}

交互流程:

第三步 加入qml文件

创建完成之后,在项目的资源目录下可以看到main.qml文件,以下给出main.qml的代码

import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Window 2.12/*** 功能:* - 实时显示CPU使用率* - 可拖动位置* - 默认显示在桌面右下角* - 透明背景,圆形设计*/
Window {id: root    // 窗口根元素标识符,可以随便命名width: 120  // 窗口宽度height: 120 // 窗口高度color: "transparent" // 窗口背景完全透明flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint // 窗口标志:无边框(FramelessWindowHint) + 置顶(WindowStaysOnTopHint)title: "CPU占用率监控"  // 窗口标题(标题栏),上面已经去掉边框了,此标题看不见// 设置窗口初始位置在右下角x: Screen.desktopAvailableWidth - width - 20y: Screen.desktopAvailableHeight - height - 20// 可拖动区域(覆盖整个窗口)MouseArea {id: dragArea        // 拖动区域标识符anchors.fill: parent // 覆盖整个父窗口property point dragStart: "0,0"     // 拖动开始时鼠标的绝对位置property point windowStart: "0,0"  // 拖动开始时窗口的位置// 鼠标按下事件处理--实现拖拽功能onPressed: {// 记录初始位置dragStart = Qt.point(mouse.x, mouse.y)  // 记录鼠标绝对位置windowStart = Qt.point(root.x, root.y)  // 记录窗口当前位置cursorShape = Qt.SizeAllCursor;         // 设置光标为移动光标}// 鼠标位置改变事件处理(拖动中)onPositionChanged: {if (pressed) { // 仅在鼠标按下时处理// 计算鼠标移动距离var deltaX = mouse.x - dragStart.xvar deltaY = mouse.y - dragStart.y// 设置新窗口位置root.x = windowStart.x + deltaXroot.y = windowStart.y + deltaY}}// 鼠标释放事件处理onReleased: {cursorShape = Qt.ArrowCursor;// 恢复光标为默认箭头}// 悬停时显示拖动光标hoverEnabled: true  // 启用悬停检测onEntered: cursorShape = Qt.SizeAllCursor;  // 鼠标进入区域时显示移动光标onExited: cursorShape = Qt.ArrowCursor;     // 鼠标离开区域时恢复默认光标}// 背景(圆形)Rectangle {id: backgroundwidth: root.widthheight: root.heightradius: width / 2   // 半径设置为宽度的一半,形成圆形color: "#333333"anchors.centerIn: parent // 在父元素中居中border.color: "#444444" // 边框颜色border.width: 2 // 边框宽度}// 环形进度条轨道Rectangle {id: progressTrackwidth: 120height: 120radius: width / 2       // 圆形半径color: "transparent"    // 透明填充border.color: "#444444" // 边框颜色border.width: 5         // 边框宽度anchors.centerIn: parent  // 在父元素中居中}// 环形进度条Rectangle {id: progressBarwidth: 120height: 120radius: width / 2       // 圆形半径color: "transparent"    // 透明填充border.color: "#4CAF50" // 边框颜色border.width: 5         // 边框宽度anchors.centerIn: parent // 在父元素中居中rotation: -90       // 初始旋转-90度(使进度从顶部开始)// 旋转属性动画效果Behavior on rotation {RotationAnimation { // 旋转动画duration: 500   // 动画持续时间500毫秒direction: RotationAnimation.Shortest // 使用最短路径旋转}}}// CPU使用率文本Text {id: cpuTexttext: cpuMonitor.cpuUsage + "%"   //调用cpuMonitor类的cpuUsage函数获取返回值color: "white"font.pointSize: 24  // 字体大小font.bold: true     // 粗体anchors.centerIn: parent    // 在父元素中居中}// CPU标签Text {text: "CPU"color: "#AAAAAA"font.pointSize: 12  // 字体大小font.bold: true     // 粗体anchors {top: cpuText.bottom // 锚定到百分比文本底部topMargin: 5        // 上边距5像素horizontalCenter: parent.horizontalCenter // 水平居中}}//组件加载完成后初始化进度条Component.onCompleted: updateProgress() // 组件完成加载时调用updateProgress//根据CPU使用率更新进度条角度function updateProgress() {var usage = cpuMonitor.cpuUsage;    //调用cpuMonitor类的cpuUsage函数获取返回值var angle = (usage / 100) * 360;     //计算对应角度(360度圆周)progressBar.rotation = angle - 90;  //设置进度条旋转角度(调整-90度起始位置)}//当CPU使用率变化时更新进度条Connections {target: cpuMonitor  // 连接目标:CPU监控对象//捕获cpuMonitor发送的cpuUsageChanged信号,注意在qml中onCpuUsageChanged()一定要与cpuUsageChanged信号对应,规则是On+大小字母开头function onCpuUsageChanged() {updateProgress();}}
}

以下也给出qml的一些知识点

主窗口结构

元素

用途

说明

​Window​

创建应用程序主窗口

无边框透明窗口,始终置顶显示

├── id: root

窗口标识

用于内部引用的唯一标识符

├── width: 200

设置窗口宽度

固定宽度为 200 像素

├── height: 200

设置窗口高度

固定高度为 200 像素

├── color: "transparent"

设置窗口背景

完全透明背景,只显示内容元素

├── `flags: Qt.FramelessWindowHint

Qt.WindowStaysOnTopHint`

设置窗口属性

├── title: "CPU占用率监控"

设置窗口标题

用于调试和系统识别的标题

└── x/y

设置窗口位置

初始位置在屏幕右下角

交互元素

元素

用途

说明

​MouseArea​

处理鼠标交互

整个窗口的拖动区域

├── id: dragArea

拖动区域标识

用于引用拖动区域的标识符

├── anchors.fill: parent

填充父元素

覆盖整个窗口区域

├── dragStart

存储初始鼠标位置

记录拖动开始时的鼠标绝对坐标

├── windowStart

存储初始窗口位置

记录拖动开始时的窗口位置

├── onPressed

鼠标按下事件

记录初始位置,设置移动光标

├── onPositionChanged

鼠标移动事件

计算并更新窗口位置

├── onReleased

鼠标释放事件

恢复默认光标

├── hoverEnabled: true

启用悬停检测

允许鼠标悬停时改变光标

├── onEntered

鼠标进入区域

显示移动光标(↔)

└── onExited

鼠标离开区域

恢复默认箭头光标

视觉元素

元素

用途

说明

Rectangle (background)

创建背景圆形

CPU 监控器的背景

├── id: background

背景标识

用于引用背景的标识符

├── width: 120

设置宽度

圆形直径为 120 像素

├── height: 120

设置高度

圆形直径为 120 像素

├── radius: width / 2

设置圆角半径

创建完美圆形

├── color: "#333333"

设置填充颜色

深灰色背景

├── border.color: "#444444"

设置边框颜色

稍亮的灰色边框

├── border.width: 2

设置边框宽度

2 像素边框

└── anchors.centerIn: parent

设置位置

在窗口中居中

Rectangle (progressTrack)

创建进度条轨道

进度条的背景轨道

├── id: progressTrack

轨道标识

用于引用轨道的标识符

├── width: 120

设置宽度

与背景相同

├── height: 120

设置高度

与背景相同

├── radius: width / 2

设置圆角半径

创建完美圆形

├── color: "transparent"

设置填充颜色

透明填充

├── border.color: "#444444"

设置边框颜色

灰色边框

├── border.width: 5

设置边框宽度

5 像素边框

└── anchors.centerIn: parent

设置位置

在窗口中居中

Rectangle (progressBar)

创建进度条

显示 CPU 使用率的进度条

├── id: progressBar

进度条标识

用于引用进度条的标识符

├── width: 120

设置宽度

与轨道相同

├── height: 120

设置高度

与轨道相同

├── radius: width / 2

设置圆角半径

创建完美圆形

├── color: "transparent"

设置填充颜色

透明填充

├── border.color: "#4CAF50"

设置边框颜色

绿色进度条

├── border.width: 5

设置边框宽度

5 像素边框

├── rotation: -90

设置初始旋转

从顶部开始显示进度

└── anchors.centerIn: parent

设置位置

在窗口中居中

Behavior

创建属性动画

控制进度条旋转动画

├── on rotation

目标属性

当旋转属性变化时触发动画

└── RotationAnimation

旋转动画

具体的动画实现

├── duration: 500

动画持续时间

500 毫秒动画

└── direction: RotationAnimation.Shortest

动画方向

使用最短路径旋转

Text (cpuText)

显示 CPU 使用率

中央大号百分比数字

├── id: cpuText

文本标识

用于引用文本的标识符

├── text: cpuMonitor.cpuUsage + "%"

设置文本内容

显示 CPU 使用率百分比

├── color: "white"

设置文本颜色

白色文字

├── font.pointSize: 24

设置字体大小

24 磅字号

├── font.bold: true

设置字体样式

粗体显示

└── anchors.centerIn: parent

设置位置

在窗口中居中

Text (CPU 标签)

显示 CPU 标签

"CPU" 文字标签

├── text: "CPU"

设置文本内容

"CPU" 文字

├── color: "#AAAAAA"

设置文本颜色

浅灰色文字

├── font.pointSize: 12

设置字体大小

12 磅字号

├── font.bold: true

设置字体样式

粗体显示

├── anchors.top: cpuText.bottom

垂直位置

位于百分比文本下方

├── anchors.topMargin: 5

上边距

5 像素间距

└── anchors.horizontalCenter: parent.horizontalCenter

水平位置

水平居中

功能逻辑

元素

用途

说明

Component.onCompleted

组件初始化回调

组件加载完成后执行

└── updateProgress()

调用更新函数

初始化进度条位置

function updateProgress()

更新进度条

计算并设置进度条角度

├── var usage = cpuMonitor.cpuUsage

获取 CPU 使用率

从 C++ 对象获取值

├── var angle = (usage / 100) * 360

计算角度

将百分比转换为角度

└── progressBar.rotation = angle - 90

设置进度条旋转

从顶部开始显示进度

Connections

信号连接

连接 C++ 对象信号

├── target: cpuMonitor

目标对象

连接的 C++ CPU 监控对象

└── onCpuUsageChanged

信号处理

CPU 使用率变化时回调

└── updateProgress()

更新进度条

调用更新函数

pro文件引入qml

QT       += core gui  quick qml  #增加quick qml# 添加QML文件到资源
DISTFILES += \main.qml

main.cpp引入qml引擎

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QTimer>
#include "trayicon.h"
#include "cpumonitor.h"
int main(int argc, char *argv[])
{QApplication app(argc, argv);app.setQuitOnLastWindowClosed(false);// 创建CPU监控对象CpuMonitor cpuMonitor;// 创建QML引擎QQmlApplicationEngine engine;engine.rootContext()->setContextProperty("cpuMonitor", &cpuMonitor);engine.load(QUrl("qrc:/main.qml"));TrayIcon tray;tray.setCpuMonitor(&cpuMonitor);//传入CpuMonitor tray.setQmlEngine(&engine);//初始化qml引擎tray.show();return app.exec();
}

篇尾

        与qt相比,qml更加美观,但是比较吃性能,看需求场景来开发,下一篇我会分享完全是qml的项目,其特点是前后端分离,适合有前端人员的项目组,能加快开发进度。


文章转载自:

http://KRn1QHA3.mcbqq.cn
http://8sB0CfrL.mcbqq.cn
http://rs7eKJhe.mcbqq.cn
http://orUGKUGp.mcbqq.cn
http://dhSKTQzz.mcbqq.cn
http://N9kmBGiX.mcbqq.cn
http://AoL1AiCX.mcbqq.cn
http://pPGwL6cX.mcbqq.cn
http://xMbt05op.mcbqq.cn
http://BXCAH6uD.mcbqq.cn
http://59z9Miqt.mcbqq.cn
http://tl88Ejz1.mcbqq.cn
http://KAjLELvd.mcbqq.cn
http://lyWXEDpW.mcbqq.cn
http://u6yLWB9h.mcbqq.cn
http://gRaPLSzG.mcbqq.cn
http://mW6K7p2k.mcbqq.cn
http://O3RtNa1b.mcbqq.cn
http://DPJxMkr0.mcbqq.cn
http://AA1tptyM.mcbqq.cn
http://4ofguZyn.mcbqq.cn
http://VaJ9BKNU.mcbqq.cn
http://QfdHvzqk.mcbqq.cn
http://0N4Xjk3t.mcbqq.cn
http://YnGeAhEg.mcbqq.cn
http://uQ0UhoGp.mcbqq.cn
http://HxzwUsAS.mcbqq.cn
http://QHD1RwNu.mcbqq.cn
http://FtqzKHnC.mcbqq.cn
http://mRTmylwU.mcbqq.cn
http://www.dtcms.com/a/369646.html

相关文章:

  • 三轴云台之高精度姿态调节技术篇
  • GDAL 开发起步
  • 【完整源码+数据集+部署教程】海底水下垃圾分类检测图像分割系统源码和数据集:改进yolo11-attention
  • 24V降12V,8A,电路设计,WD5030L
  • 9.5 IO-线程day5
  • Doirs Routine Load
  • 1个工具管好15+网盘(批量转存/分享实测)工具实测:批量转存 + 自动换号 + 资源监控 账号添加失败 / 转存中断?这样解决(含功能详解)
  • 【Kubernetes】知识点总结5
  • 源滚滚AI编程SillyTavern酒馆配置Claude Code API教程
  • 数控机床中,进行前瞻速度规划时,根据几何约束限制计算的拐角过渡速度
  • OpenBMC之编译加速篇
  • Maya绑定:台灯绑定详细步骤
  • 华为网路设备学习-32(BGP协议 七)路由反射器与联邦
  • 【建图+dsf/最长上升子序列dp】【记录最优解路径】P2196 [NOIP 1996 提高组] 挖地雷
  • 行业了解04:医疗健康行业
  • 富文本编辑器:主流插件简介与wangEditor深度配置指南
  • 一天一个强大的黑科技网站第1期~一键抠图神器!设计师必备!分分钟扣100张图!
  • 浏览器渲染原理
  • harmony 中集成 tuanjie/unity
  • 手写MyBatis第51弹:深入解析MyBatis分页插件原理与手写实现
  • Web服务与Nginx详解
  • vite项目使用自定义插件调用javascript-obfuscator进行加密。
  • 数据结构堆树java版本实现(大顶堆)
  • 飞牛NAS配置FRP内网穿透:实现远程访问
  • C++ 文字识别OCR
  • 告别“失忆”AI:打造有记忆、有温度的智能助手
  • 龙虎榜——20250905
  • 不上融资、不炒概念,它却成了全球AI“全明星”中国独苗!
  • 第八章 Cesium 实现动态模型拖尾效果:从原理到完整实现
  • java基础学习(四):类 - 了解什么是类,类中都有什么?