How to detect any mouse click on PySide Gui?

2019-06-25 11:36发布

问题:

I am trying implement a feature such that when a mouse is clicked on the gui, a function is triggered

Below is my mouse click detection, it doesn't work when I click on any part of the gui

from PySide.QtCore import *
from PySide.QtGui import *

import sys


class Main(QWidget):


    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        layout  = QHBoxLayout(self)
        layout.addWidget(QLabel("this is the main frame"))
        layout.gui_clicked.connect(self.anotherSlot)

    def anotherSlot(self, passed):
        print passed
        print "now I'm in Main.anotherSlot"


class MyLayout(QHBoxLayout):
    gui_clicked = Signal(str)

    def __init__(self, parent=None):
        super(MyLayout, self).__init__(parent)

    def mousePressEvent(self, event):
        print "Mouse Clicked"
        self.gui_clicked.emit("emit the signal")



a = QApplication([])
m = Main()
m.show()
sys.exit(a.exec_())

This is my goal

Mouseclick.gui_clicked.connect(do_something)

Any advice would be appreciated

回答1:

Define mousePressEvent inside Main:

from PySide.QtCore import *
from PySide.QtGui import *

import sys


class Main(QWidget):


    def __init__(self, parent=None):
        super(Main, self).__init__(parent)

        layout  = QHBoxLayout(self)
        layout.addWidget(QLabel("this is the main frame"))

    def mousePressEvent(self, QMouseEvent):
        #print mouse position
        print QMouseEvent.pos()


a = QApplication([])
m = Main()
m.show()
sys.exit(a.exec_())


回答2:

This can get complicated depending on your needs. In short, the solution is an eventFilter installed on the application. This will listen the whole application for an event. The problem is "event propagation". If a widget doesn't handle an event, it'll be passed to the parent (and so on). You'll see those events multiple times. In your case, for example QLabel doesn't do anything with a mouse press event, therefore the parent (your main window) gets it.

If you actually filter the event (i.e. you don't want the original widget to respond to the event), you won't get that problem. But, I doubt that this is your intent.

A simple example for just monitoring:

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_())

You can see that, clicking on the QLabel will give you something like:

mouse pressed <PySide.QtGui.QLabel object at 0x02B92490>
mouse pressed <__main__.MainWindow object at 0x02B92440>

Because, QLabel receives the event and since it doesn't do anything with it, it's ignored and passed to the parent (MainWindow). And it's caught by the filter/monitor again.

Clicking on the QPushButton doesn't have any problem because it uses that event and does not pass to the parent.

PS: Also note that this can cause performance problems since you are inspecting every single event in the application.