PyQt wheelEvent 重定向和超过最大递归深度
PyQt wheelEvent redirection and maximum recursion depth exceeded
我在 QDialog 中有一个 QListWidget,我希望所有的滚轮事件都被重定向到列表中,所以我这样做了:
class Form(QDialog):
def __init__(self):
...
self.myList = QListWidget()
...
def wheelEvent(self, scrollEvent):
if not scrollEvent.isAccepted():
scrollEvent.accept()
self.myList.wheelEvent(scrollEvent)
在滚动操作尝试将列表移出其限制之前它工作正常。似乎在这些情况下,QListWidget 不接受(忽略)滚动事件并将其传输(忽略)到其父级 Form,Form 将其再次发送到 QListWidget,一次又一次,直到出现 "maximum recursion depth exceeded" 错误提出了消息。
如果事件在被重定向到QListWidget 之前被接受,为什么当它返回到Qdialog 时又被重定向到QListWidget?似乎事件的 "accept" 标志未保留(或 QListWidget 将其设置回 "not accepted"),当它返回 QDialog 时被视为新事件。如何保留这些标志或使 QListWidget 接受事件,即使列表位于 top/bottom?
我试图定义 QListWidget 的子类并在将事件重定向到超类之前在该子类中接受事件,但结果相同,事件返回到 Dialog 时未被接受。
编辑:大家好!我找到了解决方案:
class Form(QDialog):
def __init__(self):
...
self.processingWheel = False
self.myList = QListWidget()
...
def wheelEvent(self, scrollEvent):
if not self.processingWheel:
self.processingWheel = True
self.myList.wheelEvent(scrollEvent)
self.processingWheel = False
现在,当 QListWidget 不处理事件时(因为列表位于 top/bottom),事件再次到达 QDialog,但第二次不会再次重定向到 QListWidget。我想它被重定向到 QDialog 父级并在那里被处理(什么都不做)。
如果允许的话,我想留下这个问题,因为我仍然想知道为什么我必须自己管理标志并且不能使用与事件关联的 isAccepted() 标志就像我第一次尝试一样。恐怕我还没有理解在 Qt 中事件传播期间事件标志在幕后发生了什么。
注意:这适用于 Qt5 - 在 Qt4 中可能会有所不同。
当您调用 self.myList.wheelEvent(scrollEvent)
时,这将在内部调用 QListView.wheelEvent(event)
,这将创建一个新的 QWheelEvent
,并将其转发到适当的滚动条小部件。如果滚动条无法处理该事件,它将接受标志设置为 false。这将导致事件立即重新传播到对话框,整个事件将再次发生。
将事件发送到列表小部件后,您无法重新设置接受标志,直到 myList.wheelEvent()
return 秒。但是当然,如果 list-widget 的滚动条忽略该事件,它可以永远不会 return,因为它会立即进入无限倒退。
在转发事件之前调用event.flag()
将不会有任何效果,因为滚动条默认将其重新设置为false,只有在明确处理该事件时才会将其设置为true。
鉴于所有这些,您使用外部标志的解决方案似乎是唯一可行的解决方案(它有点类似于 blockSignals 机制)。
我在 QDialog 中有一个 QListWidget,我希望所有的滚轮事件都被重定向到列表中,所以我这样做了:
class Form(QDialog):
def __init__(self):
...
self.myList = QListWidget()
...
def wheelEvent(self, scrollEvent):
if not scrollEvent.isAccepted():
scrollEvent.accept()
self.myList.wheelEvent(scrollEvent)
在滚动操作尝试将列表移出其限制之前它工作正常。似乎在这些情况下,QListWidget 不接受(忽略)滚动事件并将其传输(忽略)到其父级 Form,Form 将其再次发送到 QListWidget,一次又一次,直到出现 "maximum recursion depth exceeded" 错误提出了消息。
如果事件在被重定向到QListWidget 之前被接受,为什么当它返回到Qdialog 时又被重定向到QListWidget?似乎事件的 "accept" 标志未保留(或 QListWidget 将其设置回 "not accepted"),当它返回 QDialog 时被视为新事件。如何保留这些标志或使 QListWidget 接受事件,即使列表位于 top/bottom?
我试图定义 QListWidget 的子类并在将事件重定向到超类之前在该子类中接受事件,但结果相同,事件返回到 Dialog 时未被接受。
编辑:大家好!我找到了解决方案:
class Form(QDialog):
def __init__(self):
...
self.processingWheel = False
self.myList = QListWidget()
...
def wheelEvent(self, scrollEvent):
if not self.processingWheel:
self.processingWheel = True
self.myList.wheelEvent(scrollEvent)
self.processingWheel = False
现在,当 QListWidget 不处理事件时(因为列表位于 top/bottom),事件再次到达 QDialog,但第二次不会再次重定向到 QListWidget。我想它被重定向到 QDialog 父级并在那里被处理(什么都不做)。
如果允许的话,我想留下这个问题,因为我仍然想知道为什么我必须自己管理标志并且不能使用与事件关联的 isAccepted() 标志就像我第一次尝试一样。恐怕我还没有理解在 Qt 中事件传播期间事件标志在幕后发生了什么。
注意:这适用于 Qt5 - 在 Qt4 中可能会有所不同。
当您调用 self.myList.wheelEvent(scrollEvent)
时,这将在内部调用 QListView.wheelEvent(event)
,这将创建一个新的 QWheelEvent
,并将其转发到适当的滚动条小部件。如果滚动条无法处理该事件,它将接受标志设置为 false。这将导致事件立即重新传播到对话框,整个事件将再次发生。
将事件发送到列表小部件后,您无法重新设置接受标志,直到 myList.wheelEvent()
return 秒。但是当然,如果 list-widget 的滚动条忽略该事件,它可以永远不会 return,因为它会立即进入无限倒退。
在转发事件之前调用event.flag()
将不会有任何效果,因为滚动条默认将其重新设置为false,只有在明确处理该事件时才会将其设置为true。
鉴于所有这些,您使用外部标志的解决方案似乎是唯一可行的解决方案(它有点类似于 blockSignals 机制)。