百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术流 > 正文

Qt之自定义托盘(一)(qt自定义按钮控件)

citgpt 2024-07-20 13:25 8 浏览 0 评论

说起Qt,真是个不错的ui库,不仅仅ui做的好,其他方面也不差,在平台扩展方面也是非常的强大。这篇文章我将会分析下qt的托盘,QSystemTrayIcon是qt的托盘类,托盘类的用途是什么我就不说了,自行百科就好,关键问题是我们要实现自定义的托盘。

说起常用的客户端软件,qq,微信等聊天工具,有这么几个托盘事件:

Qt之自定义托盘(一)(qt自定义按钮控件)

1、来消息图标闪烁

2、气泡消息提示

3、鼠标左键单击、左键双击、右键单击、滚动单击

上述这三种事件QSystemTrayIcon类都完全能够解决,但是托盘的hover事件却无能为力,如图1所示,途图中是帮助文档中的一段描述,指明了只有在x11系统中,可以捕获到系统的tooltip事件,其他系统都无能为力,我自己也看了下qt的源码,果真是这样的,有兴趣的同学可以自行在研究下。

图1 帮助文档

如图2所示,qq有消息时,鼠标hover在图盘弹出菜单,那么qq是怎么做的呢,既然qq都到做到了,这个功能我们自己想必肯定也能实现。

图2 托盘hover弹框

好了,上边说了这么多,仅仅是为了铺垫我自己实现的托盘,完全脱离了qt中的托盘类QSystemTrayIcon,不过也不能说完全脱离,部分代码还是从qt源码中摘出来的。文章的最后我附上我自己用qt实现的自定义托盘和下载别人用mfc自定义实现的自定义托盘。

因为win32我自己也不是特别了解,因此我也是大概说下自定义托盘需要了解的东西,首先是NOTIFYICONDATA结构,这个结构百科讲的特别详细,看一下就知道怎么用,然后是Shell_NotifyIcon这个api,这个方法就是对托盘操作的接口。具体参数百科中说的很详细,不过如果你不想看也无所谓,直接往下看也可以。对盘托的操作在windows平台下都是一样的,关键问题是用qt怎么接受这个图盘的hover和leave消息。

关于这个托盘的实现我也是从mfc的示例代码中获取的启发,然后用qt方法实现,接下来我就直接说下用qt实现的步骤:

1、首先我们需要了解下QAbstractNativeEventFilter这个接口类,继承这个接口类的类可以把自己注册到app中,然后就能获取到整个app

的事件,事件的处理函数为nativeEventFilter,该类有3个参数,具体可以参见这篇文字qt捕获全局windows消息 这个文章中说的不全是对的,不过能抓取到app消息应该是没问你的,本篇博客的demo也是印证了这个问题。注册代码如下:

1 qApp->installNativeEventFilter(this);

2、第二步就是创建托盘图标,创建托盘图标的时候,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,在我们后续处理的逻辑中会用到

3、鼠标事件处理

 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中有源文件。

点击领取Qt学习资料+视频教程~「链接」

4、程序退出时销毁托盘图标

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

相关推荐

js中arguments详解

一、简介了解arguments这个对象之前先来认识一下javascript的一些功能:其实Javascript并没有重载函数的功能,但是Arguments对象能够模拟重载。Javascrip中每个函数...

firewall-cmd 常用命令

目录firewalldzone说明firewallzone内容说明firewall-cmd常用参数firewall-cmd常用命令常用命令 回到顶部firewalldzone...

epel-release 是什么

EPEL-release(ExtraPackagesforEnterpriseLinux)是一个软件仓库,它为企业级Linux发行版(如CentOS、RHEL等)提供额外的软件包。以下是关于E...

FullGC详解  什么是 JVM 的 GC
FullGC详解 什么是 JVM 的 GC

前言:背景:一、什么是JVM的GC?JVM(JavaVirtualMachine)。JVM是Java程序的虚拟机,是一种实现Java语言的解...

2024-10-26 08:50 citgpt

使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
  • 使用Spire.Doc组件利用模板导出Word文档
跨域(CrossOrigin)

1.介绍  1)跨域问题:跨域问题是在网络中,当一个网络的运行脚本(通常时JavaScript)试图访问另一个网络的资源时,如果这两个网络的端口、协议和域名不一致时就会出现跨域问题。    通俗讲...

微服务架构和分布式架构的区别

1、含义不同微服务架构:微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法,每个服务运行在自己的进程中,服务间通信采用轻量级通信机制(通常用HTTP资源API)。这些服务围绕业务能力构建并...

深入理解与应用CSS clip-path 属性
深入理解与应用CSS clip-path 属性

clip-pathclip-path是什么clip-path 是一个CSS属性,允许开发者创建一个剪切区域,从而决定元素的哪些部分可见,哪些部分会被隐...

2024-10-25 11:51 citgpt

HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
  • HCNP Routing&Switching之OSPF LSA类型(二)
Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
  • Redis和Memcached的区别详解
Request.ServerVariables 大全

Request.ServerVariables("Url")返回服务器地址Request.ServerVariables("Path_Info")客户端提供的路...

python操作Kafka

目录一、python操作kafka1.python使用kafka生产者2.python使用kafka消费者3.使用docker中的kafka二、python操作kafka细...

Runtime.getRuntime().exec详解

Runtime.getRuntime().exec详解概述Runtime.getRuntime().exec用于调用外部可执行程序或系统命令,并重定向外部程序的标准输入、标准输出和标准错误到缓冲池。...

promise.all详解 promise.all是干什么的
promise.all详解 promise.all是干什么的

promise.all详解promise.all中所有的请求成功了,走.then(),在.then()中能得到一个数组,数组中是每个请求resolve抛出的结果...

2024-10-24 16:21 citgpt

Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解
  • Content-Length和Transfer-Encoding详解

取消回复欢迎 发表评论: