鼠标点击会穿透Qwidgets到pyside应用吗?
我正在尝试在我的图形界面(gui)中检测鼠标点击,下面的代码可以检测到在一个Qwidget层级上的鼠标点击。
import sys
from PySide import QtGui, QtCore
class MouseDetector(QtCore.QObject):
def eventFilter(self, obj, event):
if event.type() == QtCore.QEvent.MouseButtonPress:
print 'mouse pressed', obj
return super(MouseDetector, self).eventFilter(obj, event)
class MainWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
layout = QtGui.QHBoxLayout()
layout.addWidget(QtGui.QLabel('this is a label'))
layout.addWidget(QtGui.QPushButton('Button'))
self.setLayout(layout)
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
mouseFilter = MouseDetector()
app.installEventFilter(mouseFilter)
main = MainWindow()
main.show()
sys.exit(app.exec_())
但是,如果我在一个Qwidget里面再嵌套一个Qwidget,然后再嵌套一个Qwidget,鼠标点击就无法穿透到应用程序的其他部分。
更让人困惑的是,当我在最里面的那个小部件上安装事件过滤器时,鼠标点击依然无法被检测到。
# Widget x.1 is embedded in Widget X
# -----------------Widget x.1-----------------------
# | |
# | |
# | ---------------------- ---------------------| |
# | | | | | |
# | | Widget x.1.1 | | | Widget x.1.2 |
# | | | | | |
# | ---------------------- ---------------------| |
# | |
# --------------------------------------------------
我是不是在解决这个问题的方式上搞错了?任何建议都非常感谢。
1 个回答
1
这是Qt中鼠标事件传播的正常表现。
QLabel和QPushButton默认会接收鼠标事件,这意味着它们会处理这些事件,而不让事件继续传递给它们的父级。如果你想让事件继续传递,可以继承你的QWidget,并重写鼠标交互的方法,不去处理这些事件,这样它们就会继续传播。你也可以在所有东西上面放一个透明的控件来捕捉鼠标事件。
另外,你还可以使用事件过滤器,这样也能实现。我运行了程序,MouseDetector运行得很好(Windows 7,Python 2.7,PySide 1.2.2):
mouse pressed <PySide.QtGui.QPushButton object at 0x00000000038A0A88>
mouse pressed <PySide.QtGui.QLabel object at 0x00000000038A0908>
mouse pressed <__main__.MainWindow object at 0x00000000038A0888>
在所有控件上面放一个捕捉鼠标事件的QWidget是很简单的。例如:
from PySide import QtCore, QtGui
class ClickableWidget(QtGui.QWidget):
clicked = QtCore.Signal(QtGui.QMouseEvent)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def mousePressEvent(self, event):
self.clicked.emit(event)
event.ignore()
def beep():
print('button clicked')
def dup():
print('catcher clicked')
app = QtGui.QApplication([])
window = QtGui.QWidget()
button = QtGui.QPushButton('Click me', window)
button.clicked.connect(beep)
catcher = ClickableWidget(window)
catcher.clicked.connect(dup)
catcher.raise_()
window.show()
app.exec_()
在这里,按钮是可见的,但无法点击,因为另一个(默认是透明的)QWidget
在它上面(raise_()
)。实际上,即使不发出信号,只要在按钮上面放一个控件,就能捕捉到所有的鼠标事件,因为这些事件只会传递给父控件(而这个捕捉控件并不是按钮的子控件)。另一种方法(忽略事件)就有点复杂了。你可以参考Qt - 顶层控件的键盘和鼠标事件透明性?来了解更多。