雖然是在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