1. QSystemTrayIcon hover事件
参考:https://stackoverflow.com/questions/21795919/how-to-catch-the-mousehover-event-for-qsystemtrayicon
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() << "不在托盘中"; } }
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