QComboBox: Ignore wheel event when not reacting to it

With the SH_ComboBox_AllowWheelScrolling style hint introduced in [1],
it's possible for combo boxes to not react to wheel scrolling. However,
since the event isn't explicitly ignored, it gets "eaten" by the combo
box instead of propagating up. This leads to upper level scroll areas
not receiving the event (and thus not scrolling).
By ignoring the event, the scroll area now scrolls if the hint is set
to false instead of nothing happening. This feels more intuitive and
mimics system behavior on both macOS (where the hint is set to false by
default) and Windows 11.

[1]: 5e9e4ccdc363297f70d4ebfbbb3e279670eca553

Pick-to: 6.8
Change-Id: I2207af8aad81fb76f3b1bbe074c3c4fbf22e3eca
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit 9c966d837fe33b1e32f5e95f29a380dd3063055b)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Sebastian Beckmann 2025-03-19 18:00:57 +01:00 committed by Qt Cherry-pick Bot
parent fe1863228c
commit c0cee227de
2 changed files with 61 additions and 0 deletions

View File

@ -3449,6 +3449,8 @@ void QComboBox::wheelEvent(QWheelEvent *e)
d->emitActivated(d->currentIndex);
}
e->accept();
} else {
e->ignore();
}
}
#endif

View File

@ -105,6 +105,8 @@ private slots:
void mouseWheel_data();
void mouseWheel();
void popupWheelHandling();
void ignoreWheelEvents_data();
void ignoreWheelEvents();
#endif // QT_CONFIG(wheelevent)
void sendKeyEventToPopup();
void layoutDirection();
@ -2192,6 +2194,63 @@ void tst_QComboBox::popupWheelHandling()
QVERIFY(comboBox->view()->isVisible());
QCOMPARE(comboBox->view()->pos(), popupPos);
}
void tst_QComboBox::ignoreWheelEvents_data()
{
QTest::addColumn<bool>("allowWheelScrolling");
QTest::newRow("Check that QComboBox ignores wheel scrolling and propagates") << false;
QTest::newRow("Check that QComboBox allows wheel scrolling and doesn't propagate") << true;
}
void tst_QComboBox::ignoreWheelEvents()
{
class AllowWheelScrollStyle : public QProxyStyle
{
public:
explicit AllowWheelScrollStyle(bool allowWheelScroll) : allow(allowWheelScroll) { }
int styleHint(const QStyle::StyleHint hint, const QStyleOption *opt, const QWidget *widget,
QStyleHintReturn *returnData) const override
{
if (hint == QStyle::SH_ComboBox_AllowWheelScrolling)
return allow;
return QProxyStyle::styleHint(hint, opt, widget, returnData);
}
bool allow;
};
class WheelEventTestWidget : public QWidget
{
public:
bool eventReceived = false;
void wheelEvent(QWheelEvent *e) override
{
eventReceived = true;
e->accept();
}
};
QFETCH(bool, allowWheelScrolling);
WheelEventTestWidget widget;
QComboBox *comboBox = new QComboBox(&widget);
comboBox->addItems({ "0", "1" });
comboBox->setStyle(new AllowWheelScrollStyle(allowWheelScrolling));
widget.show();
QVERIFY(QTest::qWaitForWindowExposed(&widget));
const QPoint wheelPoint = comboBox->rect().center();
QWheelEvent event(wheelPoint, comboBox->mapToGlobal(wheelPoint), {}, { 0, -WHEEL_DELTA },
Qt::NoButton, Qt::NoModifier, Qt::NoScrollPhase, false);
QSpontaneKeyEvent::setSpontaneous(&event);
QVERIFY(QCoreApplication::instance()->notify(comboBox, &event));
const int expectedComboBoxIndex = allowWheelScrolling ? 1 : 0;
QCOMPARE(comboBox->currentIndex(), expectedComboBoxIndex);
QCOMPARE(widget.eventReceived, !allowWheelScrolling);
}
#endif // QT_CONFIG(wheelevent)
void tst_QComboBox::sendKeyEventToPopup()