Search code examples
c++qtqspinbox

Make QSpinBox react to mouse wheel events when cursor is not over it


I am using Qt 5.3.2 with Qt Creator 3.2.1 with MinGW 4.8.2 on Windows 7. I have a QSpinBox and can change its value with the mouse wheel only if the mouse is over the QSpinBox. If the mouse is not over the QSpinBox, scrolling the mouse wheel has no effect, even though the QSpinBox still has focus. What do I need to do to be able to change values in the QSpinBox that has focus with the mouse wheel even if the mouse is not hovering over it? Setting mouseTracking to true does not have that effect.


Solution

  • Use eventFilter to do this. Install it on your mainWindow:

    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        if (obj == this && event->type() == QEvent::Wheel)
        {
            QWheelEvent *wheelEvent = static_cast<QWheelEvent *>(event);
            if(wheelEvent->delta() > 0)
                ui->spinBox->setValue(ui->spinBox->value() + 1);
            else
                ui->spinBox->setValue(ui->spinBox->value() - 1);
        }
        return QMainWindow::eventFilter(obj,event);
    }
    

    It is just example, so you can improve it as you want.

    Or use this:

    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        if (obj == this && event->type() == QEvent::Wheel)
        {
            QApplication::sendEvent(ui->spinBox,event);
        }
        return QMainWindow::eventFilter(obj,event);
    }
    

    In this example, when you detect wheel event, you send it to your spinbox.

    But don't forget

    protected:
        bool eventFilter(QObject *obj, QEvent *event);//in header
    

    and

    qApp->installEventFilter(this);//in constructor
    

    As DmitrySazonov recommended. We will detect wheelEvents when our spinBox is in focus, when spinBox loses focus, we don't react on wheelEvent (other widgets react as normal). We do this in one eventFilter.

    To do this, provide new bool variable. For example:

    private:
        bool spin;//in header
    

    Initialize it in constructor:

    spin = false;
    

    And your eventFilter should be:

    bool MainWindow::eventFilter(QObject *obj, QEvent *event)
    {
        if(obj == ui->spinBox && event->type() == QEvent::FocusIn)
            spin = true;
        
        if(spin)
        {
            if (obj == this && event->type() == QEvent::Wheel)
            {
                QApplication::sendEvent(ui->spinBox,event);
            }
        }
        if(obj == ui->spinBox && event->type() == QEvent::FocusOut)
            spin = false;
    
        return QMainWindow::eventFilter(obj,event);
    }
    

    Or just do this, without an additional variable:

    if (obj == this && event->type() == QEvent::Wheel)
    {
        if(ui->spinBox->hasFocus())
            QApplication::sendEvent(ui->spinBox,event);
    }