如何在 Qt 中添加和使用系统托盘图标
在 Qt 中实现系统托盘图标是一个常见的需求,尤其是在桌面应用程序中。系统托盘图标可以让应用程序在后台运行时仍然具有可见性,同时避免占用过多的桌面空间。本文将详细介绍如何在 Qt 项目中添加托盘图标,并通过资源系统(.qrc
文件)来管理图标文件。
1. 创建 Qt 项目并准备资源文件
首先,确保已经创建了一个 Qt 项目。以下是步骤:
- 创建 Qt 项目:在 Qt Creator 中创建一个新的 Qt Widgets 应用程序。
- 添加资源文件:在 Qt Creator 中右键点击项目文件夹,选择 New > Qt > Resource File,然后命名为
resources.qrc
。
2. 将图标添加到资源文件中
一旦有了资源文件(resources.qrc
),就可以将图标文件(例如 tray_icon.png
)添加到资源系统中了。以下是具体步骤:
- 在 Qt Creator 中打开
resources.qrc
:右键点击resources.qrc
文件并选择 Open。 - 添加图标文件:
- 在资源文件中,点击 添加前缀 按钮,输入前缀。
- 在资源文件中,点击 添加文件 按钮,选择你的图标文件(例如
tray_icon.png
)。
这样,图标就会被嵌入到应用的资源系统中,并且可以通过 :/test/icon/tray_icon.png
路径来访问。
3. 修改 .pro
文件
确保 .pro
文件包含了 resources.qrc
文件。打开 .pro
文件,并确认其中有以下行:
RESOURCES += resources.qrc
这一步非常重要,因为它确保了资源文件会被正确加载到项目中。
cmake参考如下图:
4. 使用资源图标
在 Qt 中加载资源文件的图标非常简单,使用 QIcon
来设置系统托盘图标。以下是代码示例:
4.1 设置系统托盘图标
首先,在你的 MainWindow
或者其他类中,创建一个 QSystemTrayIcon
对象,并为其设置图标:
#include <QSystemTrayIcon>
#include <QMenu>
#include <QAction>// 在 MainWindow 或其他类中添加以下成员变量
QSystemTrayIcon *m_pTrayIcon;
QMenu *m_pTrayMenu;void MainWindow::setupTrayIcon() {// 创建系统托盘图标m_pTrayIcon = new QSystemTrayIcon(this);m_pTrayIcon->setIcon(QIcon(":/icon/tray_icon.png")); // 使用资源图标m_pTrayIcon->setToolTip("Qt 应用 - 托盘模式");// 创建托盘菜单m_pTrayMenu = new QMenu(this);QAction *showAction = new QAction("显示", this);QAction *exitAction = new QAction("退出", this);connect(showAction, &QAction::triggered, this, &MainWindow::showMainWindow);connect(exitAction, &QAction::triggered, this, &MainWindow::exitApplication);m_pTrayMenu->addAction(showAction);m_pTrayMenu->addAction(exitAction);m_pTrayIcon->setContextMenu(m_pTrayMenu);// 显示托盘图标m_pTrayIcon->show();// 处理左键点击:恢复窗口connect(m_pTrayIcon, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason) {if (reason == QSystemTrayIcon::Trigger) {showMainWindow();}});
}
4.2 可勾选的菜单项
在菜单中添加一个 QAction,并使其可勾选。当用户左键单击时,勾选状态会切换。
// 添加一个可勾选的菜单项QAction *checkAction = new QAction("启用功能", this);checkAction->setCheckable(true); // 设置该项为可勾选checkAction->setChecked(false); // 默认不勾选// 当该项的状态改变时,输出当前状态connect(checkAction, &QAction::toggled, this, [=](bool checked) {if (checked) {qDebug("功能已启用");} else {qDebug("功能已禁用");}});
5. 处理关闭事件
当用户尝试关闭窗口时,你可以让窗口最小化到系统托盘,而不是完全关闭。为了实现这一点,你需要重写 closeEvent
方法:
void MainWindow::closeEvent(QCloseEvent *event)
{// 弹出提示框,确认是否关闭应用QMessageBox::StandardButton reply = QMessageBox::question(this, "确认", "确定要关闭应用吗?
应用将最小化到系统托盘",QMessageBox::Yes | QMessageBox::No);if (reply == QMessageBox::Yes) {event->ignore(); // 阻止窗口关闭this->hide(); // 隐藏窗口m_pTrayIcon->showMessage("Qt 应用", "应用已最小化到托盘", QSystemTrayIcon::Information, 3000);} else {event->accept();}
}
6. 重新编译并运行
每次你修改 resources.qrc
文件之后,必须重新编译项目。以下是具体步骤:
- 清理项目:点击 Build > Clean Project。
- 重新构建项目:点击 Build > Run qmake,然后选择 Build > Rebuild Project。
7. 托盘图标的使用
- 左键点击:单击系统托盘图标会将应用恢复到主窗口。
- 右键点击:右键点击托盘图标会显示菜单,菜单中包括 显示 和 退出 选项。
8. 常见问题和调试
如果在运行时遇到如下警告:
QSystemTrayIcon::setVisible: No Icon set
这通常表示 Qt 没有正确加载图标。以下是一些常见的解决方法:
- 确保
.pro
文件包含resources.qrc
。 - 重新编译项目,确保资源文件被正确嵌入到最终的可执行文件中。
- 检查资源路径是否正确,代码中的路径应该是
:/icon/tray_icon.png
。
9. 完整代码
头文件(mainwindow.h)
这个头文件定义了 MainWindow 类,它包含了托盘图标相关的成员变量和函数声明。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QSystemTrayIcon>
#include <QMenu>QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();protected:// 重写关闭事件,将窗口最小化到托盘void closeEvent(QCloseEvent *event) override;private slots:// 显示主窗口void showMainWindow();// 退出应用void exitApplication();private:// 初始化托盘图标void setupTrayIcon();private:Ui::MainWindow *ui; // UI 类QSystemTrayIcon *m_pTrayIcon; // 系统托盘图标QMenu *m_pTrayMenu; // 托盘菜单
};
#endif // MAINWINDOW_H
实现文件(mainwindow.cpp)
在 mainwindow.cpp 中,主要实现了如何初始化系统托盘图标和处理关闭事件。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QCloseEvent>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 设置托盘图标和菜单setupTrayIcon();
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::setupTrayIcon()
{// 创建系统托盘图标m_pTrayIcon = new QSystemTrayIcon(this);m_pTrayIcon->setIcon(QIcon(":/icon/tray_icon.png")); // 使用资源图标m_pTrayIcon->setToolTip("Qt 应用 - 托盘模式");// 创建托盘菜单m_pTrayMenu = new QMenu(this);QAction *showAction = new QAction("显示", this);QAction *exitAction = new QAction("退出", this);// 添加一个可勾选的菜单项QAction *checkAction = new QAction("启用功能", this);checkAction->setCheckable(true); // 设置该项为可勾选checkAction->setChecked(false); // 默认不勾选connect(showAction, &QAction::triggered, this, &MainWindow::showMainWindow);connect(exitAction, &QAction::triggered, this, &MainWindow::exitApplication);// 当该项的状态改变时,输出当前状态connect(checkAction, &QAction::toggled, this, [=](bool checked) {if (checked) {qDebug("功能已启用");} else {qDebug("功能已禁用");}});m_pTrayMenu->addAction(showAction);m_pTrayMenu->addAction(exitAction);m_pTrayMenu->addAction(checkAction);m_pTrayIcon->setContextMenu(m_pTrayMenu);// 显示托盘图标m_pTrayIcon->show();// 处理左键点击:恢复窗口connect(m_pTrayIcon, &QSystemTrayIcon::activated, this, [=](QSystemTrayIcon::ActivationReason reason) {if (reason == QSystemTrayIcon::Trigger) {showMainWindow();}});
}void MainWindow::closeEvent(QCloseEvent *event)
{// 弹出提示框,确认是否关闭应用QMessageBox::StandardButton reply = QMessageBox::question(this, "确认", "确定要关闭应用吗?\n应用将最小化到系统托盘",QMessageBox::Yes | QMessageBox::No);if (reply == QMessageBox::Yes) {event->ignore(); // 阻止窗口关闭this->hide(); // 隐藏窗口m_pTrayIcon->showMessage("Qt 应用", "应用已最小化到托盘", QSystemTrayIcon::Information, 3000);} else {event->accept();}
}void MainWindow::showMainWindow()
{this->show(); // 恢复主窗口this->activateWindow(); // 激活窗口
}void MainWindow::exitApplication()
{m_pTrayIcon->hide(); // 隐藏托盘图标QApplication::quit(); // 退出应用
}
总结
本文介绍了如何在 Qt 项目中通过资源文件(resources.qrc
)添加和使用系统托盘图标。通过这些步骤,可以让应用程序在后台运行时使用托盘图标,同时提供更加友好的用户体验。
相关文章:

如何在 Qt 中添加和使用系统托盘图标
在 Qt 中实现系统托盘图标是一个常见的需求,尤其是在桌面应用程序中。系统托盘图标可以让应用程序在后台运行时仍然具有可见性,同时避免占用过多的桌面空间。本文将详细介绍如何在 Qt 项目中添加托盘图标,并通过资源系统(.qrc 文件…...

【WB 深度学习实验管理】利用 Hugging Face 实现高效的自然语言处理实验跟踪与可视化
本文使用到的 Jupyter Notebook 可在GitHub仓库002文件夹找到,别忘了给仓库点个小心心~~~ https://github.com/LFF8888/FF-Studio-Resources 在自然语言处理领域,使用Hugging Face的Transformers库进行模型训练已经成为主流。然而,随着模型复…...

基础入门-网站协议身份鉴权OAuth2安全Token令牌JWT值Authirization标头
知识点: 1、网站协议-http/https安全差异(抓包) 2、身份鉴权-HTTP头&OAuth2&JWT&Token 一、演示案例-网站协议-http&https-安全测试差异性 1、加密方式 HTTP:使用明文传输,数据在传输过程中可以被…...

C语言基础系列【3】VSCode使用
前面我们提到过VSCode有多么的好用,本文主要介绍如何使用VSCode编译运行C语言代码。 安装 首先去官网(https://code.visualstudio.com/)下载安装包,点击Download for Windows 获取安装包后,一路点击Next就可以。 配…...

MySQL-5.7.44安装(CentOS7)
目录 1、下载安装包并解压 2、创建数据目录与日志目录 3、设置环境变量 4、刷新环境变量 5、执行初始化 6、创建配置文件目录 7、新建配置文件 8、为安装目录赋予可执行权限 9、创建服务启动脚本 10、启动服务并将启动脚本加入开机自启动 11、查看服务状态 12、创建…...
服务端与多客户端照片的传输,recv,send
一、照片传输 server.c /* * 文件名称:server.c * 创 建 者: * 创建日期:2025年02月07日 * 描 述: */ #include <stdio.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h…...

JS实现灯光闪烁效果
在 JS中,我们可以实现灯光闪烁效果,这里主要用 setInterval 和 clearInterval 两个重要方法。 效果图 源代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>灯闪烁效果<…...
SpringCloud面试题----Nacos和Eureka的区别
功能特性 服务发现 Nacos:支持基于 DNS 和 RPC 的服务发现,提供了更为灵活的服务发现机制,能满足不同场景下的服务发现需求。Eureka:主要基于 HTTP 的 RESTful 接口进行服务发现,客户端通过向 Eureka Server 发送 HT…...

verilog练习:i2c slave 模块设计
文章目录 前言1. 结构2.代码2.1 iic_slave.v2.2 sync.v2.3 wr_fsm.v2.3.1 状态机状态解释 2.4 ram.v 3. 波形展示4. 建议5. 资料总结 前言 首先就不啰嗦iic协议了,网上有不少资料都是叙述此协议的。 下面将是我本次设计的一些局部设计汇总,如果对读者有…...
3.5 Go(特殊函数)
目录 一、匿名函数 1、匿名函数的特点: 2、匿名函数代码示例 2、匿名函数的类型 二、递归函数 1. 递推公式版本 2. 循环改递归 三、嵌套函数 1、嵌套函数用途 2、代码示例 3、作用域 & 变量生存周期 四、闭包 1、闭包使用场景 2、代码示例 五、De…...
Android的MQTT客户端实现
在 Android 平台上实现 MQTT 客户端的完整技术方案,涵盖基础实现、安全连接、性能优化和最佳实践: 一、技术选型与依赖配置 推荐库 Eclipse Paho Android Service(官方维护,支持后台运行) gradle 复制 // build.gradl…...

国产编辑器EverEdit - 编辑辅助功能介绍
1 编辑辅助功能 1.1 各编辑辅助选项说明 1.1.1 行号 打开该选项时,在编辑器主窗口左侧显示行号,如下图所示: 1.1.2 文档地图 打开该选项时,在编辑器主窗口右侧靠近垂直滚动条的地方显示代码的缩略图,如下图所示&…...
WPF 在后台使TextBox失去焦点的方法
在软件设计开发的时候,偶尔会遇到在后台xaml.cs后台中,要将TextBox控件的焦点取消或者使TextBox控件获取焦点,下面介绍讲述一种简单的“只让特定的 TextBox 失去焦点”方法: 前端xaml代码示例: <StackPanel Orientation"…...

工作案例 - python绘制excell表中RSRP列的CDF图
什么是CDF图 CDF(Cumulative Distribution Function)就是累积分布函数,是概率密度函数的积分。CDF函数是一个在0到1之间的函数,描述了随机变量小于或等于一个特定值的概率。在可视化方面,CDF图表明了一个随机变量X小于…...

CTF SQL注入学习笔记
部分内容来自于SQL注入由简入精_哔哩哔哩_bilibili SQL语句 1.mysqli_error():返回最近调用函数的最后一个错误描述 语法:mysqli_error(connection) 规定要使用的Mysql连接; 返回一个带有错误描述的字符串。如果没有错误发生则返回 "" 2…...
element-plus el-tree-select 修改 value 字段
element-plus el-tree-select 修改 value 字段 ,不显示label 需要注意两个地方: <el-tree-select v-model"value" :data"data" multiple :render-after-expand"false" show-checkbox style"width: 240px" …...

基于javaweb的SpringBoot小区智慧园区管理系统(源码+文档+部署讲解)
🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 运行环境开发工具适用功能说明 运行环境 Java≥8、MySQL≥5.7、Node.js≥14 开发工具 后端:eclipse/idea/myeclipse…...

SpringBoot学习之shardingsphere实现分库分表(基于Mybatis-Plus)(四十九)
一、shardingsphere介绍 ShardingSphere是一款起源于当当网内部的应用框架。2015年在当当网内部诞生,最初就叫ShardingJDBC。2016年的时候,由其中一个主要的开发人员张亮,带入到京东数科,组件团队继续开发。在国内历经了当当网、电信翼支付、京东数科等多家大型互联网企业的…...

23.PPT:校摄影社团-摄影比赛作品【5】
目录 NO12345 NO6 NO7/8/9/10 单元格背景填充表格背景填充文本框背景填充幻灯片背景格式设置添加考生文件夹下的版式 NO12345 插入幻灯片和放入图片☞快速:插入→相册→新建相册→文件→图片版式→相框形状→调整边框宽度左下角背景图片:视图→…...

Baumer工业相机堡盟相机的相机传感器芯片清洁指南
Baumer工业相机堡盟相机的相机传感器芯片清洁指南 Baumer工业相机1.Baumer工业相机传感器芯片清洁工具和清洁剂2.Baumer工业相机传感器芯片清洁步骤2.1、准备步骤2.2、清洁过程1.定位清洁工具2.清洁传感器3.使用吹风装置 Baumer工业相机传感器芯片清洁的优势设计与结…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
go 里面的指针
指针 在 Go 中,指针(pointer)是一个变量的内存地址,就像 C 语言那样: a : 10 p : &a // p 是一个指向 a 的指针 fmt.Println(*p) // 输出 10,通过指针解引用• &a 表示获取变量 a 的地址 p 表示…...
Monorepo架构: Nx Cloud 扩展能力与缓存加速
借助 Nx Cloud 实现项目协同与加速构建 1 ) 缓存工作原理分析 在了解了本地缓存和远程缓存之后,我们来探究缓存是如何工作的。以计算文件的哈希串为例,若后续运行任务时文件哈希串未变,系统会直接使用对应的输出和制品文件。 2 …...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...