1
votes

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
1
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 stackoverflow.com/questions/52887096/…Da_Pz
@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

1 Answers

0
votes

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 );
  }
};