Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Mouse grabbing not working in menu with qwidgetaction



  • Hello. I have a custom component to edit number (derived from QSpinBox). I grab mouse move for line edit to simulate changing value up and down. When I grabbing mouse movement, I change cursor position to position I saved when enter editing component by mouse clicking. Everything works fine if I add component to main window. However if I have this componet in menu or popup, cursor go out of menu and I don't know why


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    How are you invoking your pop/menu ?



  • I'm using QPushButton with menu set by setMenu method. Then I click on button and menu popup.



  • @SGaist

    spinbox.cpp

    #include "spinbox.h"
    
    #include <QDebug>
    #include <QMouseEvent>
    #include <QLineEdit>
    #include <QApplication>
    
    SpinBox::SpinBox(QWidget* parent)
        : QSpinBox(parent)
    {
        lineEdit()->installEventFilter(this);
    }
    
    void SpinBox::onMouseMoved(QMouseEvent* event)
    {
        if (m_pos.isNull())
            return;
    
        const int delta = (m_pos.y() - event->globalY()) * (event->modifiers().testFlag(Qt::ControlModifier) ? singleStep() * 1 : 10);
        auto wheelEvent = new QWheelEvent(event->globalPos(), delta, event->buttons(), event->modifiers());
        QApplication::postEvent(this, wheelEvent);
        QCursor::setPos(m_pos);
    }
    
    void SpinBox::onMousePressed(QMouseEvent* event)
    {
        lineEdit()->grabMouse();
        grabKeyboard();
        QApplication::setOverrideCursor(Qt::SizeVerCursor);
        m_pos = event->globalPos();
    }
    
    bool SpinBox::eventFilter(QObject* watched, QEvent* event)
    {
        if (watched != lineEdit())
            return QSpinBox::eventFilter(watched, event);
    
        switch (event->type())
        {
        case QEvent::MouseMove:
            onMouseMoved(static_cast<QMouseEvent*>(event));
            return true;
        case QEvent::MouseButtonPress:
            onMousePressed(static_cast<QMouseEvent*>(event));
            return true;
        default:
            break;
        }
    
        return QSpinBox::eventFilter(watched, event);
    }
    
    void SpinBox::keyPressEvent(QKeyEvent* event)
    {
        if (event->key() != Qt::Key_Escape)
            return QSpinBox::keyPressEvent(event);
    
        event->accept();
        QApplication::restoreOverrideCursor();
        m_pos = { };
        lineEdit()->releaseMouse();
        releaseKeyboard();
    }
    

    mainwindow.cpp

    #include "mainwindow.h"
    
    #include <QApplication>
    #include <QDebug>
    #include <QGuiApplication>
    #include <QComboBox>
    #include <QEvent>
    #include <QHBoxLayout>
    #include <QMenu>
    #include <QPushButton>
    #include <QWidgetAction>
    #include <QMoveEvent>
    #include <QTime>
    
    #include "spinbox.h"
    #include "doublespinbox.h"
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
    {
        auto spinbox = new SpinBox(this);
        auto action = new QWidgetAction(nullptr);
        action->setDefaultWidget(spinbox);
    
        auto menu = new QMenu;
        menu->addAction(action);
    
        auto button = new QPushButton(this);
        button->setText("click me");
        button->setMenu(menu);
    
        auto widget = new QWidget(this);
        auto layout = new QHBoxLayout(widget);
        layout->addWidget(button);
        layout->addWidget(new SpinBox);
    
        setCentralWidget(widget);
    }
    
    MainWindow::~MainWindow()
    {
    }
    

Log in to reply