10

I need to catch when a User moves the mouse over the GUI, but not when they're holding down the mouse button (which would do something different).

I can't find any conveniant method to do this, except to periodically find the mouse position and check it to it's previous position... Which would suck.

The mouseMoveEvent is only called when the mouse is moved whilst the left mouse button is pressed, unless ofcourse the widget has 'mouse tracking'. Mouse tracking is not an option for me, because the GUI must behave differently when the mouse is moved and the left mouse button is pressed.

Are there any inbuilt methods to do this? (or just any clever ideas?)

eg: Is there a way to check if the left mouse button is being pressed at any time?
Or a 'mouse hover' event that can be applied to a QRect (coordinates)?

Muchas gracias.


Windows 7 (32)
python 2.7
PyQt4

JasonMArcher
  • 14,195
  • 22
  • 56
  • 52
Anti Earth
  • 4,671
  • 13
  • 52
  • 83

4 Answers4

9

The most straightforward way to do this is to install an event filter on qApp:

from PyQt4 import QtGui, QtCore

class Window(QtGui.QMainWindow):
    def __init__(self):
        QtGui.QMainWindow.__init__(self)
        widget = QtGui.QWidget(self)
        layout = QtGui.QVBoxLayout(widget)
        self.edit = QtGui.QLineEdit(self)
        self.list = QtGui.QListWidget(self)
        layout.addWidget(self.edit)
        layout.addWidget(self.list)
        self.setCentralWidget(widget)

    def eventFilter(self, source, event):
        if event.type() == QtCore.QEvent.MouseMove:
            if event.buttons() == QtCore.Qt.NoButton:
                pos = event.pos()
                self.edit.setText('x: %d, y: %d' % (pos.x(), pos.y()))
            else:
                pass # do other stuff
        return QtGui.QMainWindow.eventFilter(self, source, event)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    win = Window()
    win.show()
    app.installEventFilter(win)
    sys.exit(app.exec_())
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
3

As people have said, the correct approach seems to be to call setMouseTracking(True) on the widget. What I'd like to add is that, having done this, you can distinguish between a mouse motion and a mouse drag as follows:

def mouseMoveEvent(self, event):
    if event.buttons() == QtCore.Qt.NoButton:
        print "Simple mouse motion"
    elif event.buttons() == QtCore.Qt.LeftButton:
        print "Left click drag"
    elif event.buttons() == QtCore.Qt.RightButton:
        print "Right click drag"
MarcTheSpark
  • 473
  • 5
  • 14
  • 1
    Hey, as I was bored and looking into Qt4 I found your example here - I found that the above doesn't 'work' for the `NoButton` event but does work for the `LeftButton` and `RightButton` events. For me this is fine, I want to test mouse functions including clicks - the 'drag' exercises both. – Mark Rowlands May 01 '15 at 10:33
2

call setMouseTracking(True) method first. Then mouseMoveEvent will be fired without any button pressed.

HYRY
  • 94,853
  • 25
  • 187
  • 187
  • I specified that this is not an option, because I need to discriminate the response depending on if the button is pressed or not. "Mouse tracking is not an option for me" – Anti Earth Oct 20 '11 at 00:44
2

It seems you've misunderstood what mouseTracking does. It only causes mouseMoveEvent to be fired, nothing else. In other words, it's exactly what you need.

Check the event's buttons() to see if any button was pressed:

For mouse move events, this is all buttons that are pressed down.

Petr Viktorin
  • 65,510
  • 9
  • 81
  • 81
  • Does it matter if the widget that needs the mouse tracking is a QMainWindow? I can't seem the find mouseTracking in the class reference. – Anti Earth Oct 20 '11 at 00:51
  • QMainWindow does not have the 'setMouseTracking' function. I tried your suggested procedure using a Group box widget, but with no success. – Anti Earth Oct 20 '11 at 04:23
  • 1
    @AntiEarth: It does have `setMouseTracking`. It is inherited from `QWidget`. Look under `QWidget`. – Avaris Oct 20 '11 at 05:07
  • Why is this not working for me?!?!?! D: I've resorted to QTimer and multithreading. – Anti Earth Oct 20 '11 at 08:14
  • @AntiEarth What happens if you try that function with QMainWindow ? – alexisdm Oct 20 '11 at 11:26
  • 'QMainWindow has no attribute: setMouseTracking' – Anti Earth Oct 22 '11 at 11:36
  • @AntiEarth. `QMainWindow` most certainly does have a `setMouseTracking` attribute - you must be doing something wrong. – ekhumoro Oct 22 '11 at 12:57
  • I'm using PyQt4? Might that make a difference? – Anti Earth Oct 22 '11 at 13:31
  • @AntiEarth. No. You can easily answer these sorts of questions by importing the PyQt4 modules into a python interactive session and using tab completion, `dir()`, or something like `hasattr(QMainWindow, 'setMouseTracking')`. This is also the simplest way to check that the particular versions of Qt and PyQt (or PySide) you're targeting support the feature(s) you're interested in. – ekhumoro Oct 22 '11 at 14:44