QT學習筆記-任務欄圖標程序(帶菜單欄)C++實現


雖然是在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,其他為默認。

image-20200813155620354

項目創建好之后會創建4個文件,分別是項目文件夾下的taskbardemo.pro、頭文件的mainwindow.h、源文件的main.cpp和mainwindow.cpp、界面文件的mainwindow.ui。

image-20200813161130666

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左下角的運行,會在構建完成后自動運行,這時候會發現已經可以有一個窗口在運行,並且顯示托盤圖標了。

image-20200825161216968

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));

image-20200826100858236

至此,一個完整的任務欄圖標程序就完成了,接下來我們進階,使用QT的資源文件存放圖片資源。

3.將圖片資源使用qrc存放

在QT中新建文件(Ctrl+N),在模版中選擇QT,文件類型選擇QT Resource File(.qrc)文件。

image-20200826101135160

接下來填寫名稱,我起的名字是myqrc,路徑是默認路徑,即項目下。點擊下一步后直接點擊完成。在項目管理器中就會出現一個資源文件夾,其中新增了一個myqrc.qrc文件。

QT也會打開這個文件,這時候我們在下方點擊添加->添加前綴,在前綴上填寫"/img"。

image-20200826101639183

然后就添加了一個/img的虛擬文件夾,再點擊添加文件,選擇你的圖標文件添加進去。

image-20200826101838319

這時資源已經加載完成了。

利用資源文件最好在項目下新建一個同名文件夾,可以更高效的管理資源文件。

接下來將之前的代碼更改一下,在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM