From f4303356457fd22ddf227f1e6cc2a78f7a942852 Mon Sep 17 00:00:00 2001 From: yeshanshan Date: Fri, 14 Aug 2026 17:31:22 +0800 Subject: [PATCH] fix: wheel event not propagating to parent in Qt6 Qt6 QApplication::notify pre-accepts wheel events (we.setAccepted(true)) before delivery. If a widget's wheelEvent doesn't call the parent class (which would ignore() the event), the event stays accepted and does not propagate to parent widgets (e.g. QScrollArea). This differs from Qt5 where unhandled wheel events propagated by default. Fix by overriding wheelEvent in DSpinBox, DDoubleSpinBox, DComboBox following the pattern from commit fe16c8e9 (settings/ComboBox): - hasFocus(): call base class wheelEvent (stepBy + accept, default behavior) - no focus: call QWidget::wheelEvent (ignore() -> event propagates) For DSlider, which is a QWidget containing an inner QSlider with an eventFilter on qApp, fix the eventFilter instead: when the inner slider has no focus, call e->ignore() before returning true so the event propagates to the parent scrollarea in Qt6. This fixes the Qt6-specific regression where scrolling over spinbox / combobox / slider inside a scrollarea was blocked. Ref: DDE-72 --- include/widgets/dcombobox.h | 2 ++ include/widgets/dspinbox.h | 8 ++++++++ src/widgets/dcombobox.cpp | 10 ++++++++++ src/widgets/dslider.cpp | 6 +++++- src/widgets/dspinbox.cpp | 20 ++++++++++++++++++++ 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/include/widgets/dcombobox.h b/include/widgets/dcombobox.h index 62b94cf11..34c53d56a 100644 --- a/include/widgets/dcombobox.h +++ b/include/widgets/dcombobox.h @@ -23,6 +23,8 @@ class LIBDTKWIDGETSHARED_EXPORT DComboBox : public QComboBox, public DCORE_NAMES protected: DComboBox(DComboBoxPrivate &dd, QWidget *parent); + void wheelEvent(QWheelEvent *event) override; + // QComboBox interface public: virtual void showPopup() override; diff --git a/include/widgets/dspinbox.h b/include/widgets/dspinbox.h index 8a14cbf1d..81520d0cd 100644 --- a/include/widgets/dspinbox.h +++ b/include/widgets/dspinbox.h @@ -25,6 +25,10 @@ class LIBDTKWIDGETSHARED_EXPORT DSpinBox : public QSpinBox, public DTK_CORE_NAME public: explicit DSpinBox(QWidget *parent = nullptr); +protected: + void wheelEvent(QWheelEvent *event) override; + +public: QLineEdit *lineEdit() const; bool isAlert() const; @@ -65,6 +69,10 @@ class LIBDTKWIDGETSHARED_EXPORT DDoubleSpinBox : public QDoubleSpinBox, public D public: explicit DDoubleSpinBox(QWidget *parent = nullptr); +protected: + void wheelEvent(QWheelEvent *event) override; + +public: bool isAlert() const; void showAlertMessage(const QString &text, int duration = 3000); void showAlertMessage(const QString &text, QWidget *follower, int duration = 3000); diff --git a/src/widgets/dcombobox.cpp b/src/widgets/dcombobox.cpp index 6867fe1ce..09a8e41e8 100644 --- a/src/widgets/dcombobox.cpp +++ b/src/widgets/dcombobox.cpp @@ -32,6 +32,7 @@ #include #include #include +#include DWIDGET_BEGIN_NAMESPACE @@ -119,6 +120,15 @@ DComboBox::DComboBox(DComboBoxPrivate &dd, QWidget *parent) d->init(); } +void DComboBox::wheelEvent(QWheelEvent *event) +{ + if (hasFocus()) { + QComboBox::wheelEvent(event); + } else { + QWidget::wheelEvent(event); + } +} + /*! * @~english @brief Override QComboBox::showPopup to limit the maximum display height according to maxVisibleItems(), which has a default value of 16. The maximum display height can be changed using setMaxVisibleItems(), which makes the setMaximumHeight() interface ineffective. diff --git a/src/widgets/dslider.cpp b/src/widgets/dslider.cpp index e10673ce2..e6666493a 100644 --- a/src/widgets/dslider.cpp +++ b/src/widgets/dslider.cpp @@ -136,7 +136,11 @@ bool DSlider::eventFilter(QObject *watched, QEvent *e) Q_D(DSlider); if ((watched == d->slider) && (e->type() == QEvent::Wheel)) { - return !d->mouseWheelEnabled; + if (d->mouseWheelEnabled && d->slider->hasFocus()) { + return false; // let QSlider::wheelEvent handle it (stepBy + accept) + } + e->ignore(); // Qt6: un-accept so event propagates to parent (e.g. scrollarea) + return true; // block delivery to the inner QSlider } if (e->type() == QEvent::MouseButtonRelease) { diff --git a/src/widgets/dspinbox.cpp b/src/widgets/dspinbox.cpp index 08543636b..9a7e087c7 100644 --- a/src/widgets/dspinbox.cpp +++ b/src/widgets/dspinbox.cpp @@ -8,6 +8,8 @@ #include "private/dspinbox_p.h" #include "dlineedit.h" +#include + DWIDGET_BEGIN_NAMESPACE DSpinBoxPrivate::DSpinBoxPrivate(DSpinBox *parent) : @@ -65,6 +67,15 @@ DSpinBox::DSpinBox(QWidget *parent) : d_func()->init(); } +void DSpinBox::wheelEvent(QWheelEvent *event) +{ + if (hasFocus()) { + QSpinBox::wheelEvent(event); + } else { + QWidget::wheelEvent(event); + } +} + /*! @~english @brief get the input line widget @@ -182,6 +193,15 @@ DDoubleSpinBox::DDoubleSpinBox(QWidget *parent) : d_func()->init(); } +void DDoubleSpinBox::wheelEvent(QWheelEvent *event) +{ + if (hasFocus()) { + QDoubleSpinBox::wheelEvent(event); + } else { + QWidget::wheelEvent(event); + } +} + bool DDoubleSpinBox::isAlert() const { D_DC(DDoubleSpinBox);