当光标不在QSpinBox上时,使其对鼠标滚轮事件作出反应

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

本文关键字:鼠标 事件 光标 QSpinBox 上时      更新时间:2023-10-16

我在Windows 7上使用Qt 5.3.2Qt Creator 3.2.1以及MinGW 4.8.2。我有一个QSpinBox,只有当鼠标位于QSpinBox上方时,才能使用鼠标滚轮更改其值。如果鼠标没有在QSpinBox上,即使QSpinBox仍然有焦点,滚动鼠标滚轮也没有效果。即使鼠标没有悬停在QSpinBox上,我也需要做些什么才能更改它的值?将mouseTracking设置为true并没有这种效果。

使用eventFilter执行此操作。将其安装在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);
        }
}

这只是一个例子,所以你可以随心所欲地改进它。

或者使用这个:

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

在本例中,当检测到轮子事件时,将其发送到旋转框。

但别忘了

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

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

按照DmitrySazonov的建议。当spinBox聚焦时,我们将检测wheelEvents,当spinBox失去焦点时,我们不会对wheel做出反应(其他小部件反应正常)。我们在一个eventFilter中完成此操作。为此,请提供新的bool变量。例如:

private:
bool spin;//in header

在构造函数中初始化它:

spin = false;

你的eventFilter应该是.

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

或者只这样做,不需要额外的变量:

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

我在问题中没有提到它,但我有不止一个QSpinBox,测试它们似乎都是次优的,所以我需要一个通用的消息转发器。根据切尔诺贝利的代码,我制作了自己版本的消息过滤器:

bool MainWindow::eventFilter(QObject *obj, QEvent *event){
    if (obj == this && event->type() == QEvent::Wheel)
    {
        auto focusWidget = QApplication::focusWidget();
        if (focusWidget){
            qApp->removeEventFilter(this);
            QApplication::sendEvent(focusWidget, event);
            qApp->installEventFilter(this);
            return true;
        }
    }
    return false;
}

这将所有QWheelEvent转发到具有焦点的QWidget。还可以添加其他需要转发的事件。

事件过滤器内的qApp->removeEventFilterqApp->installEventFilter是我发现的唯一方法,可以防止事件过滤器在主窗口上滚动时调用自己,导致堆栈溢出(条件focusWidget != this没有帮助)。可能有一种方法可以防止无限递归,而无需在每个QWheelEvent上重新安装事件过滤器。