![]() |
![]() |
很重要--转载声明
- 本站文章无特别说明,皆为原创,版权全部,转载时请用连接的方式,给出原文出处。同时写上原做者:朝十晚八 or Twowords
- 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时经过修改本文达到有利于转载者的目的。
提及Qt,真是个不错的ui库,不只仅ui作的好,其余方面也不差,在平台扩展方面也是很是的强大。这篇文章我将会分析下qt的托盘,QSystemTrayIcon是qt的托盘类,托盘类的用途是什么我就不说了,自行百科就好,关键问题是咱们要实现自定义的托盘。html
提及经常使用的客户端软件,qq,微信等聊天工具,有这么几个托盘事件:windows
一、来消息图标闪烁api
二、气泡消息提示微信
三、鼠标左键单击、左键双击、右键单击、滚动单击app
上述这三种事件QSystemTrayIcon类都彻底可以解决,可是托盘的hover事件却无能为力,如图1所示,途图中是帮助文档中的一段描述,指明了只有在x11系统中,能够捕获到系统的tooltip事件,其余系统都无能为力,我本身也看了下qt的源码,果然是这样的,有兴趣的同窗能够自行在研究下。ide
图1 帮助文档函数
如图2所示,qq有消息时,鼠标hover在图盘弹出菜单,那么qq是怎么作的呢,既然qq都到作到了,这个功能咱们本身想必确定也能实现。工具
图2 托盘hover弹框post
好了,上边说了这么多,仅仅是为了铺垫我本身实现的托盘,彻底脱离了qt中的托盘类QSystemTrayIcon,不过也不能说彻底脱离,部分代码仍是从qt源码中摘出来的。文章的最后我附上我本身用qt实现的自定义托盘和下载别人用mfc自定义实现的自定义托盘。ui
由于win32我本身也不是特别了解,所以我也是大概说下自定义托盘须要了解的东西,首先是NOTIFYICONDATA结构,这个结构百科讲的特别详细,看一下就知道怎么用,而后是Shell_NotifyIcon这个api,这个方法就是对托盘操做的接口。具体参数百科中说的很详细,不过若是你不想看也无所谓,直接往下看也能够。对盘托的操做在windows平台下都是同样的,关键问题是用qt怎么接受这个图盘的hover和leave消息。
关于这个托盘的实现我也是从mfc的示例代码中获取的启发,而后用qt方法实现,接下来我就直接说下用qt实现的步骤:
一、首先咱们须要了解下QAbstractNativeEventFilter这个接口类,继承这个接口类的类能够把本身注册到app中,而后就能获取到整个app
的事件,事件的处理函数为nativeEventFilter,该类有3个参数,具体能够参见这篇文字qt捕获全局windows消息 这个文章中说的不全是对的,不过能抓取到app消息应该是没问你的,本篇博客的demo也是印证了这个问题。注册代码以下:
1 qApp->installNativeEventFilter(this);
二、第二步就是建立托盘图标,建立托盘图标的时候,windows提供了api,代码以下:
1 NOTIFYICONDATA nid; 2 QLabel *l = new QLabel; 3 nid.cbSize = sizeof nid; 4 nid.hIcon = qt_pixmapToWinHICON(QIcon(":/trayIcon/Resources/childrenWidget.ico").pixmap(16, 16)); 5 nid.hWnd = HWND(l->winId()); 6 nid.uCallbackMessage = WM_TRAYNOTIFY; 7 nid.uID = 1; 8 nid.uFlags = NIF_ICON | NIF_MESSAGE; 9 10 Shell_NotifyIcon(NIM_ADD, &nid);
此处代码中有一个标签l,建立他是由于建立图标时须要一个接受鼠标事件的窗口句柄hWnd,若是没有句柄,那么托盘也不能建立成功;其余成员的含义从变量的命名上应该也能理解,我重点说下uFlags这个变量,他其实自己没有什么含义,主要是为了标示NOTIFYICONDATA结构中其余成员那个是有效的,这个也方便了咱们后续对托盘图标的修改。好比说修改tooltip、修改图标等信息。uCallbackMessage是消息id,在咱们后续处理的逻辑中会用到
三、鼠标事件处理
1 bool trayIcon::nativeEventFilter(const QByteArray & eventType, void * message, long * result) 2 { 3 if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG") 4 { 5 MSG * pMsg = reinterpret_cast<MSG *>(message); 6 if (pMsg->message == WM_TRAYNOTIFY) 7 { 8 switch (pMsg->lParam) 9 { 10 case WM_MOUSEMOVE: 11 m_traypos.OnMouseMove(); 12 break; 13 case WM_MOUSEHOVER: 14 m_Menu->show(); 15 break; 16 case WM_MOUSELEAVE: 17 m_Menu->hide(); 18 break; 19 case WM_LBUTTONDBLCLK: 20 // m_Menu->show(); 21 break; 22 case WM_LBUTTONDOWN: 23 // m_Menu->show(); 24 break; 25 case WM_RBUTTONDOWN: 26 // m_Menu->show(); 27 break; 28 } 29 } 30 } 31 32 return false; 33 }
上述代码主要是针对鼠标事件的一个处理。WM_TRAYNOTIFY消息是咱们开始的时候注册到图盘中的消息,当托盘发生鼠标事件的时候咱们只须要关注本身注册的消息,对于windows托盘稍微有了解的同窗可能也知道,微软没有提供给咱们托盘图标的进入和离开事件,而仅仅提供了鼠标move的事件,不过仅仅有这一个事件咱们就能够模拟出其余的事件来。细心的同窗将会注意到 m_traypos.OnMouseMove();这句代码,其实m_tryapos这个对象是一个move事件处理类,他能够模拟出鼠标hover和leave事件来。关于这个类的解释我就不说了,是一个国外的大牛写的,demo中有源文件。
四、程序退出时销毁托盘图标
Shell_NotifyIcon(NIM_DELETE, &m_NotifyIconData);
经过上述的代码整理,简单的托盘就能够实现了,由于我是本身作的demo,所以不是全部事件的处理了的,高级定制的功能若是有兴趣的同窗能够给我留言,或者私信我能够,若是是我实现了的,我将愿意和你们一块儿分享。我下边连接中的这个demo其实比较粗糙,就仅仅的能够实现鼠标在托盘图标上的hover和leave请求。
最后我上两张效果图,图3是mfc示例的鼠标hover截图,图4是qt示例的鼠标hover截图
图3 mfc示例demo
图4 qt示例demo
注意:这个demo很是粗糙,不过我已经讲明了怎么实现一个本身的托盘,关于须要怎么实现一个完美的托盘,同窗们能够参考qt的源码中qsystemtrayicon_win.cpp文件,该文件就是QSystemTrayIcon类的真正实现。
qt示例连接:http://download.csdn.net/detail/qq_30392343/9608076
mfc示例连接:http://download.csdn.net/detail/qq_30392343/9608078