zoukankan      html  css  js  c++  java
  • 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() << "不在托盘中";
        }
    }
    
  • 相关阅读:
    机器学习笔记
    python学习笔记-day8
    python学习笔记-day7
    python学习笔记-day6
    python学习笔记-day5
    python习题
    単語
    bat批处理----copy和xcopy区别
    C#
    VB
  • 原文地址:https://www.cnblogs.com/xiang--liu/p/12035570.html
Copyright © 2011-2022 走看看