鼠标点击是否可以穿过Qwidgets进入pyside的应用程序?

时间:2014-06-06 18:38:46

标签: python user-interface pyside qwidget

我正在尝试检测鼠标点击我的gui,以下代码允许在1层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 个答案:

答案 0 :(得分:1)

这是Qt中mouse event propagation的预期行为。

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 - top level widget with keyboard and mouse event transparency?