user7989146
user7989146

Reputation:

Move entire window with Middle Mouse Click & Drag in Qt

I have a Qt program that has many child widgets. I want the user to be able to move the window by middle mouse clicking and dragging around, it works fine when there are no children, like this:

class MainWindow(QtGui.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.startPos = QtCore.QPoint()

    def mousePressEvent(self, event):
        self.startPos = event.pos()
        super(MainWindow, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() == QtCore.Qt.MiddleButton:
            delta = event.pos() - self.startPos
            self.move(self.pos() + delta)
            event.accept()
        super(MainWindow, self).mouseMoveEvent(event)

But when I populate my widget with all the children widgets, and their children widgets, and so on. I only catch the event if I click in the margin/padding area, and not anywhere else in the widget.

Is there a way to make the middle mouse drag event usable with children widgets in the way?

Upvotes: 2

Views: 1521

Answers (1)

musicamante
musicamante

Reputation: 48489

When mouse events are intercepted by widgets that can relate to them, they are automatically accepted and won't be relayed to the parent widgets. While most widgets ignore middle clicks, some actually do, so your main window will never receive them.

The solution is to install an event filter on the QApplication instead, so that any mouse event you're interested into will be filtered before being sent to any possible target widget:

class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()
        # just some test widgets
        layout = QtWidgets.QGridLayout(self)
        for row in range(4):
            for col in range(4):
                layout.addWidget(QtWidgets.QPushButton('Button'), row, col)
        layout.addWidget(QtWidgets.QTextEdit(), 
            layout.rowCount(), 0, 1, layout.columnCount())

        self.startPos = None
        # install the event filter on the application
        QtWidgets.QApplication.instance().installEventFilter(self)

    def eventFilter(self, source, event):
        if (event.type() == QtCore.QEvent.MouseButtonPress and 
            event.button() == QtCore.Qt.MiddleButton):
                self.startPos = event.pos()
                return True
        elif event.type() == QtCore.QEvent.MouseMove and self.startPos is not None:
            self.move(self.pos() + event.pos() - self.startPos)
            return True
        elif event.type() == QtCore.QEvent.MouseButtonRelease and self.startPos is not None:
            self.startPos = None
            return True
        return super(MainWindow, self).eventFilter(source, event)

Upvotes: 2

Related Questions