虽然是在Linux下编写的,但是参考了别人代码感觉是通用的,Windows也可以参考。
环境:Linux(Ubuntu/Debian)(方德)、QT5.6.2、GCC6.2.1
在编写程序之前首先需要准备一个任务栏图标。以下是QT官方文档对于系统任务栏图标大小的解释。
On Windows, the system tray icon size is 16x16; on X11, the preferred size is 22x22. The icon will be scaled to the appropriate size as necessary.[1]
翻译:在Windows上,系统任务栏图标的大小为16x16; 在X11上,首选尺寸为22x22。 图标将根据需要缩放为适当的大小。
我是在Linux上编写程序,而Linux基本都支持X11协议,所以将图片尺寸更改为22x22,这里可以在网上找到很多在线工具进行编辑。而如果在Windows上则应该将图标大小缩放至16x16,这里我并未在Windows上进行测试。
在官方文档中并未找到关于图片格式的说明,这里我就使用的图片格式为png,命名为icon.png。
我将项目的实现分为两步,第一步为实现一个任务栏图标,第二步为实现任务栏图标右键菜单栏。文章最后会给出完整代码。
0.创建一个项目
首先新建一个Qt Widgets Application项目,我把项目命名为taskbardemo。构建套件选择自己配置好的套件,基类我选的是QMainWindow,其他为默认。
项目创建好之后会创建4个文件,分别是项目文件夹下的taskbardemo.pro、头文件的mainwindow.h、源文件的main.cpp和mainwindow.cpp、界面文件的mainwindow.ui。
1.创建任务栏图标
1.1新建一个任务栏图标
在编写任务栏图标代码之前需要先将QSystemTrayIcon头文件加上,我加在mainwindow.h文件上。
#include <QSystemTrayIcon>
在mainwindow.h中还应该加一个类成员函数用来当托盘图标点击的槽函数:
private slots:
void iconActived(QSystemTrayIcon::ActivationReason reason);
在mainwindow.cpp的MainWindow构造函数中加入以下代码:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//新建一个托盘图标对象 //2020-09-22更新,在QSystemTrayIcon()中添加this指针指向mainwindow,以便在关闭窗口时销毁托盘图标
QSystemTrayIcon *m_trayicon = new QSystemTrayIcon(this);
//设置托盘图标提示:鼠标移动到上面会提示文字
m_trayicon->setToolTip(QString("托盘图标程序Demo"));
//设置图标文件,这里先使用路径来设置,后面介绍使用qt资源文件设置图标文件
//我将图标放在了项目路径下,并使用了绝对路径
m_trayicon->setIcon(QIcon("/home/fan/qtproject/taskbardemo/icon.png"));
//连接信号与槽:点击托盘图标执行事件
connect(m_trayicon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActived(QSystemTrayIcon::ActivationReason)));
//显示托盘图标
m_trayicon->show();
}
接下来点击QT左下角的运行,会在构建完成后自动运行,这时候会发现已经可以有一个窗口在运行,并且显示托盘图标了。
1.2 为图标增加双击显示主界面功能
在mainwindow.h中,添加一个类成员函数:
private:
void changeEvent(QEvent *event);
我们重载事件改变函数,让点击最小化按钮改变一个功能,变成隐藏窗口,还有很多让窗口隐藏的方法,例如点击关闭按钮可以弹出消息框选择是否隐藏,大家可以自行尝试。
在mainwindow.cpp中,添加它的函数定义:
void MainWindow::changeEvent(QEvent *event)
{
if(event->type()!=QEvent::WindowStateChange)
return;
if(this->windowState()==Qt::WindowMinimized)
{
this->hide();
}
}
这里先判断事件的类型是不是窗体状态改变,如果是的话再判断是不是状态为最小化,如果是最小化,那么隐藏当前窗口。
接下来为任务栏图标增加双击显示主窗口的功能,之前我们添加了一个槽函数iconActived,我们在mainwindow.cpp中添加以下定义:
void MainWindow::iconActived(QSystemTrayIcon::ActivationReason reason)
{
switch(reason)
{
//双击托盘显示窗口
case QSystemTrayIcon::DoubleClick:
{
this->show();
break;
}
default:
break;
}
}
这里QSystemTrayIcon::ActivationReason枚举描述了系统托盘被激活的原因,其中QSystemTrayIcon::DoubleClick是双击系统托盘条目,QSystemTrayIcon::Trigger是单击系统托盘条目,QSystemTrayIcon::Context是请求了托盘条目的上下文菜单,更多资料另请参见参考资料[1]中enum QSystemTrayIcon::ActivationReason条目。
this->show();为显示主窗口界面。这样我们在构建项目后运行程序,点击最小化按钮就可以隐藏窗口界面了,并且双击托盘图标,就可以恢复窗口界面了。
2.创建任务栏图标右键菜单
我们见过非常多的程序都可以右键单击托盘图标之后弹出菜单,可以选择一些功能,例如显示主界面、退出程序等功能,这里我们实现这两个功能,和其他一些演示。
在mainwindow.cpp的MainWindow构造函数中继续添加以下代码:
//创建菜单项
QMenu *m_traymenu = new QMenu();
//创建菜单项内容
QAction *action_show = new QAction(tr("Show MainWindow"),this);
QAction *action_quit = new QAction(tr("Quit"),this);
QAction *action_test1 = new QAction(tr("test1"),this);
QAction *action_test2 = new QAction(tr("test2"),this);
QAction *action_test3 = new QAction(tr("test3"),this);
//设置一个菜单项的图标作为演示
action_show->setIcon(QIcon("/home/fan/qtproject/taskbardemo/icon.png"));
//将他们关联起来
m_traymenu->addAction(action_show);
m_traymenu->addAction(action_quit);
m_traymenu->addSeparator();//设置一个分割条作为演示
m_traymenu->addAction(action_test1);
m_traymenu->addAction(action_test2);
m_traymenu->addAction(action_test3);
m_trayicon->setContextMenu(m_traymenu);//设置上下文菜单
//连接信号与槽:单击菜单项内容执行相应的函数
connect(action_show,SIGNAL(triggered()),this,SLOT(show()));
connect(action_quit,SIGNAL(triggered()),this,SLOT(close()));
这里我直接创建了QAction对象,如果需要在其它函数操作菜单项的内容,例如改变菜单项显示的文本,可以将其添加成类成员变量,在mainwindow.h的类声明中添加一个QAction *action_show即可,这里就不需要再声明了。
这里注意addAction的顺序和最终形成的菜单项顺序是一致的,具体可以联系我的代码看下面的图。
进阶:加入二级菜单,在mainwindow.cpp的MainWindow构造函数中继续添加以下代码:
m_traymenu->addSeparator();//设置一个分割条作为演示
//增加一个二级菜单,以此类推可以实现多级菜单
QMenu *m_traymenu1 = m_traymenu->addMenu("1_0");
//一个更快捷添加菜单项的方法
m_traymenu1->addAction("1_1",this,SLOT(close));
至此,一个完整的任务栏图标程序就完成了,接下来我们进阶,使用QT的资源文件存放图片资源。
3.将图片资源使用qrc存放
在QT中新建文件(Ctrl+N),在模版中选择QT,文件类型选择QT Resource File(.qrc)文件。
接下来填写名称,我起的名字是myqrc,路径是默认路径,即项目下。点击下一步后直接点击完成。在项目管理器中就会出现一个资源文件夹,其中新增了一个myqrc.qrc文件。
QT也会打开这个文件,这时候我们在下方点击添加->添加前缀,在前缀上填写"/img"。
然后就添加了一个/img的虚拟文件夹,再点击添加文件,选择你的图标文件添加进去。
这时资源已经加载完成了。
利用资源文件最好在项目下新建一个同名文件夹,可以更高效的管理资源文件。
接下来将之前的代码更改一下,在mainwindow.cpp的构造函数中,两处设置图标的地方分别使用":/img/icon.png"来替换之前的路径,使用qrc资源只需添加一个冒号即可,非常方便快捷。
m_trayicon->setIcon(QIcon(":/img/icon.png"));
action_show->setIcon(QIcon(":/img/icon.png"));
4.完整代码
给出完整代码仅供参考。
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSystemTrayIcon>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
void changeEvent(QEvent *event);
private slots:
void iconActived(QSystemTrayIcon::ActivationReason reason);
};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//新建一个托盘图标对象 //2020-09-22 添加this
QSystemTrayIcon *m_trayicon = new QSystemTrayIcon(this);
//设置托盘图标提示:鼠标移动到上面会提示文字
m_trayicon->setToolTip(QString("托盘图标程序Demo"));
//设置图标文件,这里先使用路径来设置,后面介绍使用qt资源文件设置图标文件
//我将图标放在了项目路径下
m_trayicon->setIcon(QIcon(":/img/icon.png"));
//连接信号与槽:点击托盘图标执行事件
connect(m_trayicon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(iconActived(QSystemTrayIcon::ActivationReason)));
//显示托盘图标
m_trayicon->show();
//创建菜单项
QMenu *m_traymenu = new QMenu();
//创建菜单项内容
QAction *action_show = new QAction(tr("Show MainWindow"),this);
QAction *action_quit = new QAction(tr("Quit"),this);
QAction *action_test1 = new QAction(tr("test1"),this);
QAction *action_test2 = new QAction(tr("test2"),this);
QAction *action_test3 = new QAction(tr("test3"),this);
//设置一个菜单项的图标作为演示
action_show->setIcon(QIcon(":/img/icon.png"));
//将他们关联起来
m_traymenu->addAction(action_show);
m_traymenu->addAction(action_quit);
m_traymenu->addSeparator();//设置一个分割条作为演示
m_traymenu->addAction(action_test1);
m_traymenu->addAction(action_test2);
m_traymenu->addAction(action_test3);
m_trayicon->setContextMenu(m_traymenu);//设置上下文菜单
//连接信号与槽:单击菜单项内容执行相应的函数
connect(action_show,SIGNAL(triggered()),this,SLOT(show()));
connect(action_quit,SIGNAL(triggered()),this,SLOT(close()));
m_traymenu->addSeparator();//设置一个分割条作为演示
//增加一个二级菜单,以此类推可以实现多级菜单
QMenu *m_traymenu1 = m_traymenu->addMenu("1_0");
//一个更快捷添加菜单项的方法
m_traymenu1->addAction("1_1",this,SLOT(close()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::iconActived(QSystemTrayIcon::ActivationReason reason)
{
switch(reason)
{
//双击托盘显示窗口
case QSystemTrayIcon::DoubleClick:
{
this->show();
break;
}
default:
break;
}
}
void MainWindow::changeEvent(QEvent *event)
{
if(event->type()!=QEvent::WindowStateChange)
return;
if(this->windowState()==Qt::WindowMinimized)
{
this->hide();
}
}
参考资料:
[1]Qt Documentation 之 QSystemTrayIcon
https://doc.qt.io/qt-5/qsystemtrayicon.html
[2]QT多级菜单
https://www.jianshu.com/p/c79958fec4cb
[3]【Qt开发】实现系统托盘,托盘菜单,托盘消息
https://www.cnblogs.com/woniu201/p/10573431.html
[4]qt 实现托盘菜单
https://blog.csdn.net/sinat_33859977/article/details/89489046