系统托盘,相信大家并不陌生,在使用电脑过程中我们无时无刻都在进行使用着它。今天记录下自己写的qt程序如何使用系统托盘。
由标题可知,本篇博客介绍的是:自定义类继承自系统托盘类,并实现其中所需功能。由此写好的类,可以给任何项目使用!
先看效果图:
消息框:
系统托盘:
托盘菜单:
新建类并继承自托盘类
首先新建类,并继承自系统托盘类QSystemTrayIcon
包含其头文件:#include <QSystemTrayIcon>
并定义私有变量Widget类型,也得包含头文件:#include <QWidget>
如下代码:
#include <QSystemTrayIcon>
#include <QWidget>
class Systray : public QSystemTrayIcon {
Q_OBJECT
public:
Systray(QWidget *parent); // 不能指定默认值
~Systray();
private:
QWidget *m_pParent; // 父类,用于显示窗体
};
注意:
- 构造函数中不能指定默认值,因为new该类对象是需要传入父类的。
- 一定要定义私有QWidget 类型变量用于存储传入的父类widget对象。
初始化托盘
新建初始化函数,用于准备工作。(设置工具提示、设置托盘图标、信号与槽的绑定)
private:
void initSysTray(); // 初始化托盘
// 初始化
void Systray::initSysTray() {
setToolTip(tr("我的五子棋")); // 设置工具提示
setIcon(QIcon("chess.ico")); // 设置托盘图标
// 点击托盘所作的操作
connect(this, &Systray::activated, this, &Systray::onIconActivated);
// 点击消息框后显示主页面
connect(this, &Systray::messageClicked, [this] {
m_pParent->activateWindow();
m_pParent->showNormal();
});
// 显示系统托盘消息框
connect(this, &Systray::showTrayMessage, this, &Systray::showMessage);
}
第一个connect:我们单击或者双击或者右键单击系统托盘时会发出activated信号,将其与我们自己写的槽函数进行绑定,可以实现显示与退出等操作!
第二个connect:最小化后电脑右下角会显示托盘消息框,其有一个消息点击信号,将其与我们自己写的槽函数进行绑定,可以实现点击显示窗体效果。
第三个connect:自己定义的信号与自己定义的槽函数进行绑定,用于实现最小化后发射信号触发托盘消息框显示。
现在来实现第一个connect绑定的槽函数
注意槽函数的参数
private slots:
void onIconActivated(QSystemTrayIcon::ActivationReason reason); // 处理事件函数
void Systray::onIconActivated(QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) { // 点击触发
// 显示窗体
m_pParent->activateWindow();
m_pParent->showNormal();
} else if (reason == QSystemTrayIcon::Context) { // 右键触发
// 显示菜单
trayMenu->exec(QCursor::pos()); // 在鼠标的位置显示
}
通过参数进行判断,可以知道鼠标对系统托盘做了那些操作,进而对于做出相应操作。
除了上面两种外还有一下几种:
This enum describes the reason the system tray was activated.
Constant | Value | Description |
---|---|---|
QSystemTrayIcon::Unknown | 0 | 未知的原因 |
QSystemTrayIcon::Context | 1 | 请求系统托盘条目的上下文菜单 |
QSystemTrayIcon::DoubleClick | 2 | 系统托盘入口被双击 |
QSystemTrayIcon::Trigger | 3 | 系统托盘条目被点击 |
QSystemTrayIcon::MiddleClick | 4 | 用鼠标中键点击系统托盘入口 |
添加托盘菜单
.h文件中定义私有变量菜单对象。QMenu *trayMenu; // 菜单
需包含头文件:#include <QMenu>
新建私有函数添加菜单
private:
void addSysTrayMenu(); // 添加菜单
// 菜单
void Systray::addSysTrayMenu() {
trayMenu = new QMenu(m_pParent); // 新建菜单,指定父对象
// 新建菜单子项
QAction *action1 = new QAction(trayMenu);
QAction *action2 = new QAction(trayMenu);
action1->setIcon(QIcon("show.png")); // 设置菜单图标
action1->setText(QString("Show")); // 设置带单文本
action2->setIcon(QIcon("close.png"));
action2->setText(QString("Quit"));
// 添加菜单子项
trayMenu->addAction(action1);
trayMenu->addAction(action2);
// 显示窗体
connect(action1, &QAction::triggered, [this](bool) {
m_pParent->activateWindow();
m_pParent->showNormal();
});
// 退出
connect(action2, &QAction::triggered, [this](bool) { this->m_pParent->close(); });
}
注意:
new菜单对象时,指定的父对象是我们通过构造函数传入来的值,不是this。
给菜单新建子项,并指定菜单,设置图标,文本。最后将其添加到菜单中。
为子项菜单绑定信号与槽:
第一个connect:显示主窗体
第二个connect:关闭主窗体
上面绑定信号与槽,槽函数使用的是lambada表达式。
做完上面两个操作后,就可以在构造函数中调用这些函数了。
Systray::Systray(QWidget *parent) : m_pParent(parent), QSystemTrayIcon(parent) {
initSysTray(); // 初始化托盘
addSysTrayMenu(); // 初始化菜单
this->show(); // 显示托盘
}
注意:需要调用show()函数,否则托盘菜单是无法显示的。
实现消息框
.h文件中定义信号,用于触发显示消息框
signals:
void showTrayMessage(); // 触发显示系统托盘消息框
现在来实现上面第三个connect绑定的槽函数
private:
void showMessage(); // 显示消息框
// 消息框
void Systray::showMessage() {
QSystemTrayIcon::showMessage("Notice", // 消息窗口标题
"The form is minimized!",// 消息内容
QSystemTrayIcon::MessageIcon::Information,// 消息窗口图标
1000); // 消息窗口显示时长(经测试,win10系统下,没有效果)
}
使用QSystemTrayIcon类调用静态showMessage方法。
参数一:消息窗口标题
参数二:消息内容
参数三: 消息窗口图标
参数四:消息窗口显示时长(经测试,win10系统下,没有效果)
上面我们自定义的函数名与托盘类的消息函数名相同,所以使用类名进行区分调用。
能观看此篇博客到这里的朋友们,按照上面的步骤做下来,恭喜你们已经成功封装好自己的托盘类了。下面就是调用。
在需要实现系统托盘的的程序中,加入此类的头文件。
在构造函数中new出自定托盘类的对象,并传入this参数,即可自动实现全部功能。
#include "Systray.h" // 托盘
Qt_Gobang::Qt_Gobang(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this);
// 此处省略一万行代码......
// 托盘
m_pTray = new Systray(this);
}
仅需new出托盘对象即可,无需再做其他操作,甚是方便!
当然还有一个操作,当我们点击主窗体最小化按钮时,我们需要将窗体隐藏,否则就会最小化到任务栏中了。
加入下面函数即可实现:
加入头文件:#include <QEvent>
protected:
// 捕捉最小化按钮
void changeEvent(QEvent *event);
void Qt_Gobang::changeEvent(QEvent *event) {
// 事件类型是否等于窗体状态发生改变事件
if (event->type() != QEvent::WindowStateChange) return;
// 窗体状态等于最小化按钮
if (this->windowState() == Qt::WindowMinimized) {
this->hide(); // 隐藏窗体
emit m_pTray->showTrayMessage(); // 最小化后消息提示框
}
}
隐藏窗体后应发射信号,调出托盘消息框!
emit m_pTray->showTrayMessage(); // 最小化后消息提示框
还有以下几种枚举:
Constant | Value | Description |
---|---|---|
Qt::WindowNoState | 0x00000000 | 窗口没有设置状态(正常状态) |
Qt::WindowMinimized | 0x00000001 | 窗口最小化(即图标化) |
Qt::WindowMaximized | 0x00000002 | 窗口最大化 |
Qt::WindowFullScreen | 0x00000004 | 该窗口填满了整个屏幕,周围没有任何边框 |
Qt::WindowActive | 0x00000008 | 该窗口是活动窗口,即它有键盘焦点 |
全部代码:
如果你照着上面步骤无法实现,可以复制下面代码到自己的项目中,新建类粘贴,即可实现使用。
.h文件
#pragma once
#include <QSystemTrayIcon>
#include <QWidget>
#include <QMenu>
class Systray : public QSystemTrayIcon {
Q_OBJECT
public:
Systray(QWidget *parent);
~Systray();
private slots:
void onIconActivated(QSystemTrayIcon::ActivationReason reason); // 处理事件函数
private:
void initSysTray(); // 初始化托盘
void addSysTrayMenu(); // 添加菜单
void showMessage(); // 显示消息框
signals:
void showTrayMessage(); // 触发显示系统托盘消息框
private:
QWidget *m_pParent; // 父类,用于显示窗体
QMenu *trayMenu; // 菜单
};
.cpp文件
#include "Systray.h"
#pragma execution_character_set("utf-8") // qt支持显示中文
Systray::Systray(QWidget *parent) : m_pParent(parent), QSystemTrayIcon(parent) {
initSysTray(); // 初始化托盘
addSysTrayMenu(); // 初始化菜单
this->show(); // 显示托盘
}
Systray::~Systray() {
}
// 事件触发
void Systray::onIconActivated(QSystemTrayIcon::ActivationReason reason) {
if (reason == QSystemTrayIcon::Trigger) { // 点击触发
m_pParent->activateWindow();
m_pParent->showNormal();
} else if (reason == QSystemTrayIcon::Context) { // 右键触发
trayMenu->exec(QCursor::pos());
}
}
// 初始化
void Systray::initSysTray() {
setToolTip(tr("我的五子棋")); // 设置工具提示
setIcon(QIcon(tr("chess.ico"))); // 设置托盘图标
// 点击托盘所作的操作
connect(this, &Systray::activated, this, &Systray::onIconActivated);
// 点击消息框后显示主页面
connect(this, &Systray::messageClicked, [this] {
m_pParent->activateWindow();
m_pParent->showNormal();
});
// 显示系统托盘消息框
connect(this, &Systray::showTrayMessage, this, &Systray::showMessage);
}
// 菜单
void Systray::addSysTrayMenu() {
trayMenu = new QMenu(m_pParent); // 新建菜单,指定父对象
// 新建菜单子项
QAction *action1 = new QAction(trayMenu);
QAction *action2 = new QAction(trayMenu);
action1->setIcon(QIcon("show.png")); // 设置菜单图标
action1->setText(QString("Show")); // 设置带单文本
action2->setIcon(QIcon("close.png"));
action2->setText(QString("Quit"));
// 添加菜单子项
trayMenu->addAction(action1);
trayMenu->addAction(action2);
// 显示窗体
connect(action1, &QAction::triggered, [this](bool) {
m_pParent->activateWindow();
m_pParent->showNormal();
});
// 退出
connect(action2, &QAction::triggered, [this](bool) { this->m_pParent->close(); });
}
// 消息框
void Systray::showMessage() {
QSystemTrayIcon::showMessage("Notice", // 消息窗口标题
"The form is minimized!",// 消息内容
QSystemTrayIcon::MessageIcon::Information,// 消息窗口图标
1000); // 消息窗口显示时长(经测试,win10系统下,没有效果)
}
总结:
网上有许多博客也都有介绍系统托盘的使用,但是他们讲的都是在主程序构造函数中进行操作的,虽然可以实现,但是却显得代码很臃肿,不是很好看;当你自己定义类实现时,代码就清爽很多了。