34

In my program, I'd like to have mouseMoveEvent(QMouseEvent* event) called whenever the mouse moves (even when it's over another window).

Right now, in my mainwindow.cpp file, I have:

void MainWindow::mouseMoveEvent(QMouseEvent* event) {
    qDebug() << QString::number(event->pos().x());
    qDebug() << QString::number(event->pos().y());
}

But this seems to only be called when I click and drag the mouse while over the window of the program itself. I've tried calling

setMouseTracking(true);

in MainWindow's constructor, but this doesn't seem to do anything differently (mouseMoveEvent still is only called when I hold a mouse button down, regardless of where it is). What's the easiest way to track the mouse position globally?

Switch
  • 5,126
  • 12
  • 34
  • 40

2 Answers2

38

You can use an event filter on the application.

Define and implement bool MainWindow::eventFilter(QObject*, QEvent*). For example

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
  if (event->type() == QEvent::MouseMove)
  {
    QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
    statusBar()->showMessage(QString("Mouse move (%1,%2)").arg(mouseEvent->pos().x()).arg(mouseEvent->pos().y()));
  }
  return false;
}

Install the event filter when the MainWindows is constructed (or somewhere else). For example

MainWindow::MainWindow(...)
{
  ...
  qApp->installEventFilter(this);
  ...
}
baysmith
  • 5,082
  • 1
  • 23
  • 18
  • 2
    Thanks, that works for getting continuous updates when the mouse is over the application window, but if the mouse moves elsewhere, the position doesn't update. – Switch Dec 20 '09 at 07:45
  • To track the mouse outside the window, you'd need to grab the mouse (see QWidget::grabMouse()). Since all mouse events will be sent to the widget which has grabbed the mouse, this will prevent normal interaction with other widgets, unless you only grab the mouse only when the mouse leaves the window (in the leaveEvent()) and then release the mouse on enterEvent(). – baysmith Dec 20 '09 at 18:18
  • After adding grabMouse(), it still only updates when the mouse passes over the application window – Switch Dec 21 '09 at 04:44
  • 6
    Using grabMouse() works for me, but it does have negative consequences for trying to interact with multiple windows. Another alternative would be to use a QTimer to continuously poll the mouse position which can be retrieved with QCursor::pos(). – baysmith Dec 21 '09 at 17:08
  • I don't think this is a correct answer. To get continous mouse events, all one has to do is call setMouseTracking(true). To grab mouse outside the window, one has to use grabMouse() as mentioned. – Kyberias Jan 02 '14 at 20:27
  • Are you by any chance using Microsoft Windows ? – Sergio Martins Jan 06 '15 at 12:16
  • @Kyberias: I think `setMouseTracking(true)` has to be called on the right widget and it makes it seem like it doesn't work. I have a simple window that inherits from `QGraphicsView` and the `setMouseTracking` call doesn't do anything. – darda Jun 20 '15 at 22:34
  • @Kyberias: dug deeper; see my answer. – darda Jun 20 '15 at 23:57
4

I had the same problem, further exacerbated by the fact that I was trying to call this->update() to repaint the window on a mouse move and nothing would happen.

You can avoid having to create the event filter by calling setMouseTracking(true) as @Kyberias noted. However, this must be done on the viewport, not your main window itself. (Same goes for update).

So in your constructor you can add a line this->viewport()->setMouseTracking(true) and then override mouseMoveEvent rather than creating this filter and installing it.

darda
  • 3,597
  • 6
  • 36
  • 49