系统托盘如何实现

发布时间 2023-07-10 21:00:51作者: 理想主义者光芒万丈

qt中有这么一个类(系统托盘类QSystemTrayIcon),但是我们要设置一些自定义功能,所以要对此类进行重写。

1.如何调用:需要的地方使用自定义托盘类:MySysTray* systray = new MySysTray(this);若是仅仅在此继承类中改变图标的话,是会在托盘中显示出来的,但是却没有任何点击效果(即点击后无反应)。

2.

//MySysTray类头文件
#pragma once
#include
<QSystemTrayIcon>
#include <QWidget>
class MySysTray:public QSystemTrayIcon{ Q_OBJECT public:
   My
SysTray(QWidget *parent);
~MySysTray();
public slots:
   void onIconActivated(QSystemTrayIcon::ActivationReason reason); //自定义槽函数非继承而来,响应点击图标 参数:触发/内容
private:
   void initSystemTray();    
private:
   QWidget* m_parent;
}

3.

//MySysTray类cpp
#include "MySysTray.h"

void MySysTray::MySysTray(QWidget *parent):m_parent(parent),QSystemTrayIcon(parent){
  initSystemTray(); 
  show();

}
void MySysTray::onIconActivated(QSystemTrayIcon::ActivationReason reason){
  if(reason==QSystemTrayIcon::Trigger){  
    m_parent->show();
    m_parent->activatedWindow();}
}
void MySysTray::initSystemTray(){ 
  
    setIcon(QIcon([pathname])); //pathname是图片路径
    setToolTip(QStringLiteral("QQ_奇牛科技"));
    connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onIconActivated(QSystemTrayIcon::ActivationReason)));
}

 4.以上左键点击托盘图标时(触发),是能够显示出窗口的,我们需要通过托盘实现退出功能,右击托盘图标发射(内容)信号,为了响应

这个信号,我们自行增加一个菜单,即右击后 ,可以有菜单进行选择功能。为了完成这个功能,我们需要重写菜单类。

#include <QMenu>
#include <QMap>

class CustomMenu:public QMenu{ Q_OBJECT
public:
  CustomMenu(QWidget *parent = nullptr):QMenu(parent){
    setAttribute(Qt::WA_TranslucentBackground);//设置透明
    //CommonUtils::loadStyleSheet(this,"Menu"); //这是使用自定义类CommonUtils中的样式方法,无需关注
   }

  ~CustomMenu(){}

  public:
    void addCustomMenu(const QString& text, const QString& icon,const QString& name){

      QAction* pAction = addAction(QIcon(icon), name);

      m_menuActionMap.insert(text, pAction);

    }
    QAction* getAction(const QString& text){

      return m_menuActionMap[text];

    }

private:
    QMap<QString, QAction*> m_menuActionMap;      //映射到动作按钮上,以便发射信号

}

5.如何在自定义的系统托盘类中使用:(在原基础上增加代码)

//MySysTray类头文件
#pragma once
#include <QSystemTrayIcon>
#include <QWidget>
class MySysTray:public QSystemTrayIcon{
        Q_OBJECT  
public: MySysTray(QWidget *parent);     
        ~MySysTray();
public slots:   
void onIconActivated(QSystemTrayIcon::ActivationReason reason); //自定义槽函数非继承而来,响应点击图标 参数:触发/内容private:    void initSystemTray();
private:
     void addSystrayMenu();
private:   QWidget* m_parent; }
//MySysTray类cpp
#include "MySysTray.h"
#include "CustomMenu"
void MySysTray::MySysTray(QWidget *parent):m_parent(parent),QSystemTrayIcon(parent){
  initSystemTray(); 
  show();
}
void MySysTray::onIconActivated(QSystemTrayIcon::ActivationReason reason){
  if(reason==QSystemTrayIcon::Trigger){  
    m_parent->show();
    m_parent->activatedWindow();}
  if(reason==QSystemTrayIcon::Context){
    addSystrayMenu();
  }
}
void MySysTray::initSystemTray(){      setIcon(QIcon([pathname])); //pathname是图片路径     setToolTip(QStringLiteral("QQ_奇牛科技"));     connect(this, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onIconActivated(QSystemTrayIcon::ActivationReason))); }
void MySysTray::addSystrayMenu(){
    CustomMenu* customMenu = new CustomMenu(m_parent);
    customMenu->addCustomMenu("onShow",[pathname],QStringLiteral("显示"));
    
customMenu->addCustomMenu("onQuit",[pathname],QStringLiteral("退出"));
    connect(customMenu->getAction("onShow"),SIGNAL(triggered(bool)),m_parent,SLOT(onShowNormal(bool)));
    connect(customMenu->getAction("onQuit"),SIGNAL(triggered(bool)),m_parent,SLOT(onShowQuit(bool)));
    ////让菜单进入事件循环,接收鼠标的操作
    customMenu->exec(QCursor::pos());
    delete customMenu;
    customMenu = nullptr;
}

第5步中有两个问题:

1.为什么要让菜单事件进入循环?

答:若省略////让菜单进入事件循环,接收鼠标的操作的下面三行代码,我们右击托盘图标时,是不会有菜单显示出来的,若是写一句:customMenu->show()则右击托盘时是有

菜单显示的,且能够达到作用效果。只不过显示的位置不符合预期,故此我们这里采用事件循环:customMenu->exec(QCursor::pos());这就使得能够显示,并且在鼠标位置显示。

这句函数的作用就是显示菜单,其中的参数(QCursor::pos())可以指示菜单显示位置,另外该函数可以返回单击选中项。

 

2.为什么还要手动delete菜单,对象树怎么了?

若是直接选择退出的话,可以不手动删除,由对象树来删,但若是选择的是显示的话,每次调用菜单的时候都会开辟一块内存,泄露了,故此要手动删除。(退出事件循环后,继续执行完下面的delete语句。)