pythonpyqtpyqt5qmouseevent

How to capture mousePressEvent between widgets in a layout?


I'm trying to detect mouse clicks for anywhere inside an area with several widgets. For this I'm using the following code:

custom_widget = CustomWidget()
custom_widget.mouse_pressed_signal.connect(self.on_custom_label_mouse_pressed)
main_layout_vbox.addWidget(custom_widget)

hbox = QtWidgets.QHBoxLayout()
custom_widget.setLayout(hbox)

# Adding several widgets to hbox_l6

class CustomWidget(QtWidgets.QWidget):
    mouse_pressed_signal = QtCore.pyqtSignal(QtGui.QMouseEvent)

    def __init__(self):
        super().__init__()

    def mousePressEvent(self, i_qmouseevent):
        super(CustomWidget, self).mousePressEvent(i_qmouseevent)
        logging.debug("======== CustomWidget - mousePressEvent ========")
        self.mouse_pressed_signal.emit(i_qmouseevent)

Problem

This works when clicking in any of the child widgets, but there's a problem: If I click between widgets (so in the area of the hbox layout that is not covered by a widget) the mousePressEvent is not captured

Question

How can I solve this problem? (Or is there another approach that you can recommend?) The important thing is that I am able to capture mouse clicks anywhere inside of custom_widget / hbox (see code above)


Solution

  • If you want to listen to other widget's mousePressEvent you can use an eventFilter as I show below:

    from PyQt5 import QtCore, QtGui, QtWidgets
    import random
    
    
    class Widget(QtWidgets.QWidget):
        mouse_clicked_signal = QtCore.pyqtSignal(QtGui.QMouseEvent, QtWidgets.QWidget)
    
        def __init__(self, parent=None):
            super(Widget, self).__init__(parent)
    
            hlay = QtWidgets.QHBoxLayout(self)
    
            for cls in (QtWidgets.QLabel,  QtWidgets.QPushButton, QtWidgets.QFrame, QtWidgets.QWidget):
                widget = cls()
                color = QtGui.QColor(*random.sample(range(255), 3))
                widget.setStyleSheet("background-color: {}".format(color.name()))
                hlay.addWidget(widget)
    
            for w in self.findChildren(QtWidgets.QWidget) +  [self]:
                w.installEventFilter(self)
    
            self.resize(640, 480)
    
        def eventFilter(self, watched, event):
            if event.type() == QtCore.QEvent.MouseButtonPress:
                self.mouse_clicked_signal.emit(event, watched)
            return super(Widget, self).eventFilter(watched, event)
    
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        w = Widget()
        w.mouse_clicked_signal.connect(print)
        w.show()
        sys.exit(app.exec_())