1

In Qt with C++, I created a window with a small QWidget inside.

The small QWidget show a message every time QEvent::Enter, QEvent::Leave or QEvent::MouseMove is triggered.

When any mouse button is pressed (and holded) outside of the small QWidget, and the mouse is moved on the top of this small QWidget (While holding), QEvent::MouseMove is not triggered for this small QWidget. Additionally, QEvent::Enter is postponed to after the mouse button is released.

In the reverse situation: when the mouse is pressed on the small QWidget (and holded), and then the mouse is moved outside, the QEvent::Leave is postponed to after the mouse button is released.

IS there any solution to retrieve QEvent::MouseMove all the time, even when the mouse button is holded?

Additional data: Yes, setMouseTracking(true) is set.

Testing example:

Widget:

#ifndef MYWIDGET_HPP
#define MYWIDGET_HPP

#include <QWidget>
#include <QStyleOption>
#include <QPainter>
#include <QEvent>
#include <QDebug>

class MyWidget: public QWidget
{
    Q_OBJECT
public:
    MyWidget( QWidget* parent=nullptr ): QWidget(parent)
    {
        setMouseTracking(true);
    }
protected:

    // Paint for styling
    void paintEvent(QPaintEvent *)
    {
        // Needed to allow stylesheet.
        QStyleOption opt;
        opt.init(this);
        QPainter p(this);
        style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
    }

    // Show Enter and Leave event for debugging purpose
    bool event( QEvent *e)
    {
        static int counting=0;
        if (e->type() ==QEvent::Enter)
        {
            qDebug() << counting++ << " Enter: " << this->objectName();
        }
        if (e->type() ==QEvent::Leave)
        {
            qDebug() << counting++ << " Leave: " << this->objectName();
        }

        if (e->type() ==QEvent::MouseMove)
        {
            qDebug() << counting++ << " Move: " << this->objectName();
        }
        return QWidget::event(e);
    }

};

#endif // MYWIDGET_HPP

Main

#include <QApplication>

#include <QDebug>
#include <QWidget>
#include <QTimer>

#include "Testing.hpp"


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    // Create a main window
    QWidget main;
    main.setWindowTitle("Cursor blocked for 5s - wait and see");
    main.resize(500, 200);
    main.move(200, 200);

    // Create a MyWidget
    MyWidget sub(&main);
    sub.setObjectName("sub");
    sub.resize(50, 50);
    sub.move(50, 50);

    // Style the button with a hover
    main.setStyleSheet
    (
        "QWidget#sub{background-color: rgba(0,0,128,0.5);}"
        "QWidget#sub:hover{background-color: rgba(128,0,0,0.5);}"
    );

    // Show the window
    main.show();

    return a.exec();

}

Project

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

SOURCES +=\
    main.cpp

HEADERS  +=\
    Testing.hpp

RESOURCES +=\

CONFIG += c++11 -Wall

TARGET = Testing
TEMPLATE = app
Tay2510
  • 5,748
  • 7
  • 39
  • 58
Adrian Maire
  • 14,354
  • 9
  • 45
  • 85
  • Hi @Adrian Maire. i know this is 3 years old. but did you manage to solve this issue? i am trying to achieve something similar using `PyQt5`. The mouse-down and mouse-move event happens in `QFrame` and moves to a `QWidget` that wraps a `QQuickView`. However, no mouse events are triggered in `QQuickView`. Similar to a situation like here https://stackoverflow.com/questions/52887096/how-to-forward-qt-mouse-event-to-qquickview – Da_Pz Oct 19 '18 at 09:19
  • @Da_Pz: Hello! I can't really remember what was the action at the end, what I remember is that it was declared as "this is not a bug, it's a feature"-equivalent. I guess we did some ugly work-around like capturing the mouse-move at the top-window level and propagating the event. Sorry not being more helpful, I am not working on this project anymore. – Adrian Maire Oct 19 '18 at 09:33

1 Answers1

0

It is standard behavior. When you press mouse button, widget begin to grab it (make a call of QWidget::grabMouse). I think that you should redesign your behavior, or explain some real use-cases, when you need to track mouse globally.

If you really need to track mouse, you may use event filters.

Pseudo-code (without checks):

QWidget *otherWidget = /*...*/;
QWidget *myWidget  = /*...*/;
otherWidget->installEventFilter( myWidget );
// you need to install filter on each widget,
// that you want to track.
// Care with performance

MyWidget : QWidget
{
  void handleMouseMove( QPoint pos ) { /*...you code...*/ }

  void mouseMove( QMouseEvent *e ) override;
  {
    handleMouseMove( e->pos() );
    QWidget::mouseMove( e );
  }

  bool eventFilter( QObject *obj, QEvent *e )
  {
    auto srcWidget = qobject_cast< QWidget * >( obj );
    switch ( e->type() )
    {
    case QEvent::MouseMove:
      {
        auto me = static_cast< QMouseEvent * >( e );
        auto globalPos = srcWidget->mapToGlobal( me->pos() );
        auto localPos = this->mapFromGlobal( globalPos ); // Possible, you need to invalidate that poing belongs to widget
        handleMouseMove( localPos );
      }
      break;
    };
    return QWidget::eventFilter( obj, e );
  }
};
Adrian Maire
  • 14,354
  • 9
  • 45
  • 85
Dmitry Sazonov
  • 8,801
  • 1
  • 35
  • 61
  • The use is for styling purpose: hover and pressed style does not work correctly in some situations (e.g. I would like the hover/pressed style to be canceled when the mouse go out, and the hover to be activated when the mouse come onto, even if the mouse is pressed). To fix these enter/leave missing events I need the MouseMove, but it does not work correctly too. The problem is that the QEvent is not passed to the widget, so filters does not solve it. I could implement my own event system in parallel, but it is something time consuming. – Adrian Maire Mar 27 '15 at 10:24
  • If you want behavior, that is different from default in Qt and OS - you should do it manually. It is OK, that hover is not occured, when mouse is pressed on another widget. – Dmitry Sazonov Mar 27 '15 at 11:36
  • What is wrong is that the mouseMove does not trigger when moving on top of the widget, just because the button was pressed before. – Adrian Maire Mar 27 '15 at 12:04
  • Because mouse capture belong to another window. This is clear and OK from my point of view... You should address your question to developers of OS that you use. In case of Windows - send your question to Microsoft. In case of OS X - to Apple. – Dmitry Sazonov Mar 27 '15 at 12:48