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