Qt-鼠标长按式弹出菜单的一种实现方案

本文最后更新于:2022年10月26日 晚上

前情提要

菜单,所为何物?

餐馆里菜品的种类表嘛

核理 太河里了

今天的blog就写到这里,开饭了

end

在软件中,在大众印象里,菜单应该是右键单击后弹出来的那玩意儿:

Menu

横平竖直,死板而不富有生力

但是菜单项右侧的小箭头预示着 该项也是个菜单,可以开启二级菜单

同理可以开启多级菜单,aka 级联菜单

级联菜单

Qt中,这玩意儿叫做QMenu

QMenu中可以放入若干个菜单项:

  • 可以是QAction
  • 也可以是QMenu,构成级联树状结构

太好了,Qt提供了QMenu,太好用了,简直是救苦救难活菩萨

blog到这里又可以结束了 开饭了

欲求不满

太没追求了,太埋汰了,太丑了

他甚至不能自定义菜单项的位置,只能垂直排列

作为一个有追求的程序员,决不能就此罢休

让我们来康康Maya的菜单:

Maya Menu

我靠,什么叫Maya,什么叫业内标杆,就一个字:newbility

哭闹

我也要我也要,不嘛不嘛,我就要,www

我不听我不听,别人有我也要

义眼盯针

论断:

这肯定是自绘菜单,肯定不是用的系统菜单(虽然QMenu也是Qt自绘的)

你问我怎么知道的?

我只能说:dddd,懂的都懂,不懂的也不必多说,这里面的水很深,不说也是为你好

正片(叠底

那么要如何实现这种效果呢?

大聪明

有人可能会说:一个menu不行,那就多个menu同时popup()就可以了呀

聪明,太聪明了

但是经过实验发现,只有一个menu可以响应鼠标划过(hover),其他的均无反应

自绘

当然,自绘控件(窗体)肯定是最优解决方案,自定义程度最高,如:

自绘菜单

这是一个图片查看器的右键菜单,长按右键弹出,并且可以实现花里胡哨的效果

但是要注意一个问题,一般的菜单都是可以实现级联的

如果要自绘实现级联,那代码量就可想而知了

所以这个方案好是好,但是我是懒狗,o(╥﹏╥)o

女娲补天

实际上,仔细观察Maya的菜单,只有第一级菜单是持久显示的

只要解决了第一级菜单的显示和响应,后续菜单直接使用QMenu即可

也就是只要实现第一级触发器即可

那么有什么能持久显示在窗体上呢

那么显然,除了QMenu都可以…

好的,当然,经过层层筛选,发现QToolButton是最合适的载体

因为这个控件自带菜单显示(setMenu方法)

补充一点:showMenu是阻塞方法(类似exec,内部循环),在QTimer中用会阻断Timer

正片

根据高内聚低耦合精神,我们决定将菜单封装为一个单独的窗体

在窗体上放置QToolButton作为菜单的载体,自然地解决了级联菜单问题

然后再将窗体设置为透明和鼠标穿透

Perfect

哦,我的上帝,太简单了

简直是原子核脑袋

还记得我们的标题吗:长按鼠标弹出菜单

参考:Apex长按中键弹出标记菜单,松开即可标记

Apex Menu

所以这题真正的难点在于:按住鼠标按键,并响应菜单

一般人可能不觉得这有什么难的

像Apex和Maya自绘的话,也当然不是什么难题

但对于偷鸡取巧的我们来讲,这就差点被checkmate

偷鸡,是要承担后果的

Windows窗口焦点系统

众所周知,只有焦点窗口才能接收鼠标和键盘输入

这其中,当属鼠标焦点最特殊

在一个窗口A内,按住鼠标任意按键,拖动鼠标至窗口B,Press & Move & Release消息都会发送给窗口A

导致作为菜单弹出的B无法正常响应鼠标(即便是转移焦点也不行)

也就是在窗口A中按住鼠标中键弹出菜单B的话,菜单B中的QToolButton是无法正常响应鼠标的,也就无法自动弹出Menu

离奇的是弹出的QMenu是可以响应鼠标hover的(怀疑是自行拦截了qApp事件)

所以我们的目标就是让QToolButton响应鼠标并弹出Menu

唯一的方法是向qApp安装事件过滤器,过滤所有mouseMove事件,控制菜单的弹出和关闭

当然细节很多,但是有了大思路,小细节只要耐心即可解决

Follower Menu

具体可以参考:toolmenu.cpp · 蔡姬/Follower v2.0 - 码云 - 开源中国 (gitee.com)

Peace

Ref

qt - How to show the menu in QPushButton without blocking? - Stack Overflow

toolmenu.cpp · 蔡姬/Follower v2.0 - 码云 - 开源中国 (gitee.com)


Qt-鼠标长按式弹出菜单的一种实现方案
https://mrbeancpp.github.io/2022/10/26/Qt-鼠标长按式弹出菜单的一种实现方案/
作者
MrBeanC
发布于
2022年10月26日
许可协议