2014-06-06 24 views
2

我试图检测鼠标点击我的GUI,和下面的代码允许鼠标点击的检测在1层的QWidget的点击鼠标穿透Qwidgets到pyside的应用程序?

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  | 
# | |     | |     | | 
# | ---------------------- ---------------------| | 
# |            | 
# -------------------------------------------------- 

我接近解决方案错了吗?任何意见将不胜感激。

+0

请显示嵌入Widgets的代码。 – NorthCat

回答

1

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

QLabel和QPushButton默认接受鼠标事件,消耗它们并且不让它们传播给父级。你可以继承你的QWidget并覆盖鼠标交互方法而不接受事件,然后它们会传播。你可以把一个透明的捕捉鼠标事件小部件放在一切之上。

或者你可以使用你的事件过滤器工作。我运行PROGRAMM和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?

+0

感谢您的回答,您可以详细说明如何将一个透明的捕获鼠标事件小部件放在一切? – Kevin

+0

@Kevin我阐述了,但你只需要把所有QWidget(默认情况下都是透明的)放在其他所有的东西上。我没有设置布局或位置(因为QWidget的默认大小足够大),但'QStackedLayout'可能会变得方便。 – Trilarion