Qt 踩坑记录
吃一堑长一智
-
事件过滤器处理函数中添加事件过滤器
-
场景
- 假设有A、B、C三个类,它们都是QObject的子类
- 实例
A1
安装了实例C1
作为事件过滤器 - QApplication发送了一个事件
e
给A1
C1
捕捉到这个事件并对其进行处理,在处理的过程中创建了一个或多个B的实例,创建完后立刻给A1
安装这些B的实例作为事件过滤器
-
后果
C1
的eventFilter
函数处理完本次的事件e
后,控制流又会莫名其妙进入C1
的eventFilter
函数中,它又要处理一次事件e
,处理完后控制流又进入C1
的eventFilter
函数,成为一个死循环永远出不去
-
原因
- 每个QObject将它的事件过滤器存在私有的数据结构中,其
d_ptr
中的extraData
的eventFilters
就是存放它事件过滤器的列表 - QCoreApplication在执行
notify
后,会调用QCoreApplicationPrivate::sendThroughObjectEventFilters
函数,然后从头开始遍历事件接收者的这个eventFilters
列表,一个个调用它们的eventFilter
函数,如果其中有一个返回了true
,那么就算拦截成功,事件将不会进一步传播 - 对一个QObject的实例执行
installEventFilter
是将新的事件过滤器实例加入到这个列表的头部,所以这就是后装的事件过滤器优先过滤事件的原因 - 所以答案已经很明确了,
C1
在处理事件e
的时候,就是qApp
在遍历A1
的eventFitlers
的过程中,然后C1
又new
了一堆B出来并给A1
安装了它们作为事件过滤器,那么这些B的实例就会被添加到A1
的eventFitlers
前面,那么就相当于C1
在A1
的eventFitlers
中被向后移了,之后qApp
肯定又会遍历到C1
,然后C1
再弄一堆新的B实例…结果就是每过一遍C1
,A1
就多几个事件过滤器,这个列表永远也遍历不完
- 每个QObject将它的事件过滤器存在私有的数据结构中,其
-
-
包含子菜单的QMenu触发QAction以后立即删除
-
场景
- 假设一个QMenu对象
M1
,M1
的子菜单M2
中的Action被单击以后,M1
与M2
的triggered
信号都被触发,但是M2
中的Action的快捷键被按下,只有M2
的triggered
信号会被触发,所以不得不给M1
与M2
的信号都连接一个槽,如果连接的是同一个槽,那么麻烦的问题就来了 - 在这个槽中,通过
qobject_cast<QMenu *>(sender())
得到触发这个信号的QMenu实例,获取传入的action
的associatedWidgets
,对这两个进行比较,如果不同则不处理这次信号,可以避免同一次单击处理两次信号 - 由于
M2
的信号先到,M1
的后到,那么M2
的被优先处理,M1
的不会被处理 - 但是如果在处理
M2
的信号过程中把这个action
给删了(直接delete而不是调用deleteLater
),例如直接执行M2
的clear
函数
- 假设一个QMenu对象
-
后果
Segmentation Fault
-
原因
- 在处理
M2
的信号过程中删除了这个action
,那么后面当M1
的信号到的时候,此时传入的同一个action
已经变成一个垃圾指针,调用它的associatedWidgets
成员函数就会触发异常
- 在处理
-