QT 托盤 hover事件捕捉


1. QSystemTrayIcon hover事件

參考:https://stackoverflow.com/questions/21795919/how-to-catch-the-mousehover-event-for-qsystemtrayicon

There is no cross-platform solution for the hover event of QSystemTrayIcon, yet (Qt5.7). You are lucky, when you are on X11: Only on X11, when a tooltip is requested, the QSystemTrayIcon receives a QHelpEvent of type QEvent::ToolTip. Additionally, the QSystemTrayIcon receives wheel events of type QEvent::Wheel. **These are not supported on any other platform.** – Jens A. Koch Dec 4 '16 at 22:34

We can only get mouse move, up, down, and double-click messages from the system tray.

QT沒有QSystemTrayIcon托盤hover事件,只有X11系統上可以捕捉。目前只能捕捉單擊、雙擊、右擊等動作。

 

 

 

 

參考:https://www.cnblogs.com/xiang--liu/p/12034608.html

沒有捕捉到托盤事件。

 

2. 使用NOTIFYICONDATA

https://www.cnblogs.com/qnkk123/p/6840944.html

 

3.  開啟一個線程/定時器去監聽

駐留多一個線程,來判斷鼠標是否在托盤圖標區域上

托盤區域:

QSystemTrayIcon *trayicon = new QSystemTrayIcon();

x軸:    trayicon->geometry().x();
y軸:    trayicon->geometry().y();
寬度:    trayicon->geometry().width();
高度:    trayicon->geometry().height();

 

QCursor::pos();//獲取當前光標的位置

 

設定定時器,每過2秒去查看是否停留在托盤區域

QTimer *trayTimer=new QTimer();

trayTimer->start(2000); //每500ms都刷新一次

trayTimer->setSingleShot(false); //如果為真,表示只重復一次,為假表示無限次循環

connect(trayTimer,SIGNAL(timeout()),this,SLOT(checkMousePos()));

 

void MainWindow::checkMousePos()

{
    qDebug() << "iconIsActived:"<<trayicon->geometry().x();
    qDebug() << "iconIsActived:"<<trayicon->geometry().y();
    qDebug() << "iconIsActived:"<<trayicon->geometry().width();
    qDebug() << "iconIsActived:"<<trayicon->geometry().height();
    qDebug() << "鼠標位置x:"<<QCursor::pos().x();
    qDebug() << "鼠標位置y:"<<QCursor::pos().y();
 
        
    int xMin = trayicon->geometry().x();
    int xMax = trayicon->geometry().x()+trayicon->geometry().width();
 
        
    int yMin = trayicon->geometry().y();
    int yMax = trayicon->geometry().y()+trayicon->geometry().height();
 
        
    int x = QCursor::pos().x();
    int y = QCursor::pos().y();
 
        
    qDebug() << "xMin<=x&&x<=xMax:"<<(xMin<=x&&x<=xMax);
    qDebug() << "yMin<=y&&y<=yMax:"<<(yMin<=y&&y<=yMax);
 
        
    if(xMin<=x&&x<=xMax
            &&yMin<=y&&y<=yMax){
        qDebug() << "托盤中";
    }else{
        qDebug() << "不在托盤中";
    }
}

完整代碼示例

CCailianMainWindow.pro

#-------------------------------------------------
#
# Project created by QtCreator 2019-12-13T13:16:48
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = CCailianMainWindow
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        mainwindow.cpp

HEADERS += \
        mainwindow.h

FORMS += \
        mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

 

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QSystemTrayIcon>
#include <QMainWindow>
#include <QAbstractNativeEventFilter>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow,public QAbstractNativeEventFilter
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    bool nativeEventFilter(const QByteArray & eventType, void * message, long * result);

private:
    void closeEvent(QCloseEvent *);    //在關閉窗口時候要重寫該函數,為了最小化到托盤,而不是退出程序
    void    initTray(); //程序設計的托盤初始化

private slots:
    void onSystemTrayIconClicked(QSystemTrayIcon::ActivationReason reason);

    /*托盤*/
    void MenuExit();    //右鍵菜單  退出
    void ShowNormal();  //正常顯示
    void minNormal(  );
    void iconIsActived(QSystemTrayIcon::ActivationReason); //托盤圖表活動,無論是鼠標懸浮,或者雙擊,或者單擊
    void ShowClickMsg();  //點擊了消息框后的響應函數
    void flicker_msg_com();
    void updateIcon();       //定時器剛
    void ShowMessageBox();        //像是托盤圖表的messagebox()

    void checkMousePos();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

 main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    a.installNativeEventFilter(&w);

    return a.exec();
}

 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QSystemTrayIcon>
#include <QTimer>

#include <windows.h>
#pragma comment(lib, "user32.lib")

QTimer *flipTimer=new QTimer();
QTimer *trayTimer=new QTimer();
int TimerCount;
QSystemTrayIcon *trayicon = new QSystemTrayIcon();

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    initTray();
}

MainWindow::~MainWindow()
{
    delete ui;
}


//只能捕捉窗口范圍內的鼠標事件,並不能捕捉托盤內的鼠標事件
bool MainWindow::nativeEventFilter(const QByteArray & eventType, void * message, long * result)
{
    if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
    {
        MSG * pMsg = reinterpret_cast<MSG *>(message);

        if (pMsg->message == WM_MOUSEMOVE)
        {

            //獲取到系統鼠標移動,可以做像qq一樣的忙碌檢測
            qDebug() << "nativeEventFilter:"<<pMsg->pt.x;
        }
    }

    return false;
}






/* 5. 托盤圖標顯示、隱藏 */
void MainWindow::onSystemTrayIconClicked(QSystemTrayIcon::ActivationReason reason)
{
    switch(reason)
    {
    //單擊
    case QSystemTrayIcon::Trigger:
    //雙擊
    case QSystemTrayIcon::DoubleClick:
        if(this->isHidden())
        {
            //恢復窗口顯示
            this->show();
            //一下兩句缺一均不能有效將窗口置頂
            this->setWindowState(Qt::WindowActive);
            this->activateWindow();
        }
        else
        {
            this->hide();
        }
        break;
    default:
        break;
    }
}


void MainWindow::initTray() {
    connect(trayicon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(onSystemTrayIconClicked(QSystemTrayIcon::ActivationReason)));

    //1. 設置定時器去閃爍圖標
    TimerCount=0;  //初始化為零

    //2. 添加托盤右鍵菜單
    QMenu *contexmenu=new QMenu(this);           //注意右鍵菜單的父對象,在窗口銷毀后要把菜單也銷毀掉

    QAction *openNomal=new QAction(this);
    QAction *minNomal=new QAction(this);
    QAction *action_quit=new QAction(this);
    QAction *flicker_test=new QAction(this);

    openNomal->setText(QString("顯示"));
    openNomal->setIcon(QIcon(":/resources/images/tray/tray.png"));

    minNomal->setText(QString("最小化到托盤"));
    minNomal->setIcon(QIcon(":/resources/images/button/min.png"));
//    QPixmap minPix  = style()->standardPixmap(QStyle::SP_TitleBarMinButton);
//    minNomal->setIcon(minPix);

    action_quit->setText(QString("退出"));
    action_quit->setIcon(QIcon(":/resources/images/button/quit.png"));

    flicker_test->setText(QString("閃爍測試"));
    flicker_test->setIcon(QIcon(":/resources/images/tray/flicker.png"));

    contexmenu->addAction(openNomal);
    contexmenu->addSeparator();
    contexmenu->addAction(minNomal);
    contexmenu->addSeparator();
    contexmenu->addAction(action_quit);
//    contexmenu->addSeparator();
//    contexmenu->addAction(flicker_test);

    connect(openNomal,SIGNAL(triggered()),this,SLOT(ShowNormal()));
    connect(minNomal, SIGNAL(triggered()), this, SLOT( minNormal()) );
    connect(action_quit,SIGNAL(triggered()),this,SLOT(MenuExit()));
    connect(flicker_test,SIGNAL(triggered()),this,SLOT(flicker_msg_com()));

    trayicon->setContextMenu(contexmenu);

    //3. 添加托盤圖標
    QIcon   taskIcon;
    taskIcon.addFile(":/resources/images/tray/tray.png");
    //icon的大小調整???

    QIcon   trayIcon;
    trayIcon.addFile(":/resources/images/tray/trayIcon.ico");


    trayicon->setIcon(trayIcon);

    //9. 托盤圖標提示
    trayicon->setToolTip("桌面端");
    trayicon->show();

    //10. 設置任務欄圖標
    this->setWindowIcon(taskIcon);
    this->setWindowTitle(tr("桌面端"));

    //11. 托盤閃爍

    //10. 托盤菜單(右擊功能)

    connect(trayicon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(iconIsActived(QSystemTrayIcon::ActivationReason)));
    connect(trayicon,SIGNAL(messageClicked()),this,SLOT(ShowClickMsg()));

    trayTimer->start(2000);  //每500ms都刷新一次
    trayTimer->setSingleShot(false);  //如果為真,表示只重復一次,為假表示無限次循環
    connect(trayTimer,SIGNAL(timeout()),this,SLOT(checkMousePos()));


}

/* initTray()槽函數區 */
/* 1. 右鍵菜單正常顯示*/
void MainWindow::ShowNormal()
{
    flipTimer->stop();
    trayicon->setIcon(QIcon(":/resources/images/tray/trayIcon.png"));   //正常顯示時候恢復原有圖標,防止定時器在無顯示圖表時候被終止
//    this->show();


    if( windowState() == Qt::WindowMinimized ){
        setWindowState( Qt::WindowNoState );
    }
}

/* 2. 右鍵菜單最小化*/
void MainWindow::minNormal()
{
    if( windowState() != Qt::WindowMinimized ){
        setWindowState( Qt::WindowMinimized );
    }
}

/* 3. 響應右鍵菜單 關閉程序*/
void MainWindow::MenuExit()
{

    exit(0);
}

/* 4. 模擬告警消息到來時候,托盤圖表閃動*/
void MainWindow::flicker_msg_com()
{
    flipTimer->start(500);  //每500ms都刷新一次
    flipTimer->setSingleShot(false);  //如果為真,表示只重復一次,為假表示無限次循環
    connect(flipTimer,SIGNAL(timeout()),this,SLOT(updateIcon()));
}
//刷新托盤圖標
void MainWindow::updateIcon()
{
    TimerCount++;
    if(TimerCount%2)
    {
        trayicon->setIcon(QIcon(":/new/prefix1/0"));   //實際上沒有這個圖標,然后會顯示沒有圖表
    }
    else
    {
        trayicon->setIcon(QIcon(":/resources/images/tray/trayIcon.png"));
    }
}

//托盤圖標活動
void MainWindow::iconIsActived(QSystemTrayIcon::ActivationReason reason)
{
    switch(reason)
    {
        case QSystemTrayIcon::DoubleClick:
            ShowNormal();
            break;
//        case QSystemTrayIcon::Trigger:
//           ShowMessageBox();
//            break;
        case QSystemTrayIcon::Unknown:
                QMessageBox::about(this,"unkown","unkown activation");
                break;
    default:
                break;
    }
}
void MainWindow::ShowMessageBox()
{
    QSystemTrayIcon::MessageIcon icon=QSystemTrayIcon::MessageIcon(1);  //設置圖表是標准的系統托盤  信息
     trayicon->showMessage("you click","hello,tray",icon,10000);
}
//點擊了消息框后的要響應的函數
void MainWindow::ShowClickMsg()
{
//    QMessageBox::about(this,"click","you click the messagebox");
    ShowNormal();
}


//相應關閉窗口消息函數
void MainWindow::closeEvent(QCloseEvent *event)
{
    if(trayicon->isVisible())
    {
        QMessageBox::StandardButton questionResult;//返回選擇的 按鈕
        questionResult= QMessageBox::question(this,tr("桌面端"),tr("最小化到托盤"));

        if(questionResult == QMessageBox::Yes){
//            this->hide();
            setWindowState( Qt::WindowMinimized );
//            event->ignore();//如果不想關閉窗口,必須顯示調用ignore(),否則窗口默認會關閉
        }
        else{
            //清除系統托盤圖標
            trayicon->setIcon(QIcon(":/new/prefix1/0"));
            exit(0);
        }
    }

}




void MainWindow::checkMousePos()
{
    qDebug() << "iconIsActived:"<<trayicon->geometry().x();
    qDebug() << "iconIsActived:"<<trayicon->geometry().y();
    qDebug() << "iconIsActived:"<<trayicon->geometry().width();
    qDebug() << "iconIsActived:"<<trayicon->geometry().height();
    qDebug() << "鼠標位置x:"<<QCursor::pos().x();
    qDebug() << "鼠標位置y:"<<QCursor::pos().y();

    int xMin = trayicon->geometry().x();
    int xMax = trayicon->geometry().x()+trayicon->geometry().width();

    int yMin = trayicon->geometry().y();
    int yMax = trayicon->geometry().y()+trayicon->geometry().height();

    int x = QCursor::pos().x();
    int y = QCursor::pos().y();

    qDebug() << "xMin<=x&&x<=xMax:"<<(xMin<=x&&x<=xMax);
    qDebug() << "yMin<=y&&y<=yMax:"<<(yMin<=y&&y<=yMax);

    if(xMin<=x&&x<=xMax
            &&yMin<=y&&y<=yMax){
        qDebug() << "托盤中";
    }else{
        qDebug() << "不在托盤中";
    }
}


免責聲明!

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



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