Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to propagate the wheelEvent to multiple widgets of my centralwidget
Qt 6.11 is out! See what's new in the release blog

How to propagate the wheelEvent to multiple widgets of my centralwidget

Scheduled Pinned Locked Moved Unsolved General and Desktop
11 Posts 4 Posters 1.6k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • T Offline
    T Offline
    TikkiTxuck
    wrote on last edited by
    #1

    Hello all,

    I am making a C++ desktop application with Qt 6.2.4.

    Basically, I have a MainWindow which has a QVBoxLayout which has 2 custom widgets (let's call them MyWidget which has the wheelEvent function overrided).

    Code extract:

    MainWindow::MainWindow(QWidget *parent) :
            QMainWindow(parent), ui(new Ui::MainWindow) {
        ui->setupUi(this);
    
        QVBoxLayout* vLayout = new QVBoxLayout();
        vLayout->setSpacing(0);
    
        MyWidget* widget1 = new MyWidget(this);
        MyWidget* widget2 = new MyWidget(this);
        vLayout->addWidget(widget1);
        vLayout->addWidget(widget2);
    
        QWidget* centralWidget = new QWidget();
        centralWidget->setLayout(vLayout);
    
        setCentralWidget(centralWidget);
    }
    

    When my mouse is on the first MyWidget and I use the wheel with the key Ctrl pressed, the action is only performed on this widget (the focused one), but I want that all MyWidget receive the event.

    How to do so ? I try to implement the eventFilter function in the MainWindow class, but I don't succeed on catching the event at the highest level in order to propagate it.

    Code extract:

    bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
        if (event->type() == QEvent::Wheel) {
            if (QWidget *widget = qobject_cast<QWidget*>(obj); widget && widget->layout()) {
                QString test = widget->objectName();
                QLayout *layout = widget->layout();
                int nb = layout->count();
                for (int i{0}; i < layout->count(); ++i) {
                    if (QLayoutItem *item = layout->itemAt(i); item->widget()) {
                        QCoreApplication::sendEvent(item->widget(), event);
                    }
                }
    
                return true;
            }
        }
    
        return QMainWindow::eventFilter(obj, event);
    }
    

    Hope I am enough clear.

    JonBJ 1 Reply Last reply
    0
    • T TikkiTxuck

      Hello all,

      I am making a C++ desktop application with Qt 6.2.4.

      Basically, I have a MainWindow which has a QVBoxLayout which has 2 custom widgets (let's call them MyWidget which has the wheelEvent function overrided).

      Code extract:

      MainWindow::MainWindow(QWidget *parent) :
              QMainWindow(parent), ui(new Ui::MainWindow) {
          ui->setupUi(this);
      
          QVBoxLayout* vLayout = new QVBoxLayout();
          vLayout->setSpacing(0);
      
          MyWidget* widget1 = new MyWidget(this);
          MyWidget* widget2 = new MyWidget(this);
          vLayout->addWidget(widget1);
          vLayout->addWidget(widget2);
      
          QWidget* centralWidget = new QWidget();
          centralWidget->setLayout(vLayout);
      
          setCentralWidget(centralWidget);
      }
      

      When my mouse is on the first MyWidget and I use the wheel with the key Ctrl pressed, the action is only performed on this widget (the focused one), but I want that all MyWidget receive the event.

      How to do so ? I try to implement the eventFilter function in the MainWindow class, but I don't succeed on catching the event at the highest level in order to propagate it.

      Code extract:

      bool MainWindow::eventFilter(QObject *obj, QEvent *event) {
          if (event->type() == QEvent::Wheel) {
              if (QWidget *widget = qobject_cast<QWidget*>(obj); widget && widget->layout()) {
                  QString test = widget->objectName();
                  QLayout *layout = widget->layout();
                  int nb = layout->count();
                  for (int i{0}; i < layout->count(); ++i) {
                      if (QLayoutItem *item = layout->itemAt(i); item->widget()) {
                          QCoreApplication::sendEvent(item->widget(), event);
                      }
                  }
      
                  return true;
              }
          }
      
          return QMainWindow::eventFilter(obj, event);
      }
      

      Hope I am enough clear.

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @TikkiTxuck
      While you wait for someone who knows better than I. I believe wheel events go to the focussed window first, and if that consumes them (yours does) they do not get propagated higher up the tree to your man window.

      You may have to install the eventFilter() on the application rather than the main window?

      T 1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #3

        Hi and welcome to devnet,

        Might be a silly question but did you install the filter on your widgets ?

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        T 1 Reply Last reply
        0
        • JonBJ JonB

          @TikkiTxuck
          While you wait for someone who knows better than I. I believe wheel events go to the focussed window first, and if that consumes them (yours does) they do not get propagated higher up the tree to your man window.

          You may have to install the eventFilter() on the application rather than the main window?

          T Offline
          T Offline
          TikkiTxuck
          wrote on last edited by
          #4

          @JonB I tried to install it on qApp, on QCoreApplication::instance() and on QApplication::instance(), but none of them was working. Certainly because I miss something, but I don't know what :/

          jsulmJ JonBJ 2 Replies Last reply
          0
          • T TikkiTxuck

            @JonB I tried to install it on qApp, on QCoreApplication::instance() and on QApplication::instance(), but none of them was working. Certainly because I miss something, but I don't know what :/

            jsulmJ Offline
            jsulmJ Offline
            jsulm
            Lifetime Qt Champion
            wrote on last edited by
            #5

            @TikkiTxuck Shouldn't you install it in the top widget where you want to catch the events?

            https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            0
            • SGaistS SGaist

              Hi and welcome to devnet,

              Might be a silly question but did you install the filter on your widgets ?

              T Offline
              T Offline
              TikkiTxuck
              wrote on last edited by
              #6

              @SGaist Thanks for the welcoming !

              You mean calling installEventFilter on each widget which must receive the propagated event ? Can you provide some code example please ?

              jsulmJ 1 Reply Last reply
              0
              • T TikkiTxuck

                @JonB I tried to install it on qApp, on QCoreApplication::instance() and on QApplication::instance(), but none of them was working. Certainly because I miss something, but I don't know what :/

                JonBJ Offline
                JonBJ Offline
                JonB
                wrote on last edited by JonB
                #7

                @TikkiTxuck
                I knocked up the following simplest, standalone example from your code:

                #include <QDebug>
                #include <QLabel>
                #include <QVBoxLayout>
                #include <QWidget>
                
                #include "mainwindow.h"
                
                MainWindow::MainWindow(QWidget *parent)
                    : QMainWindow(parent)
                {
                    QVBoxLayout* vLayout = new QVBoxLayout();
                    vLayout->setSpacing(0);
                
                    QLabel* widget1 = new QLabel("widget1");
                    QLabel* widget2 = new QLabel("widget2");
                    vLayout->addWidget(widget1);
                    vLayout->addWidget(widget2);
                
                    QWidget* centralWidget = new QWidget();
                    centralWidget->setLayout(vLayout);
                
                    setCentralWidget(centralWidget);
                
                    installEventFilter(this);
                }
                
                bool MainWindow::eventFilter(QObject *obj, QEvent *event)
                {
                    if (event->type() == QEvent::Wheel)
                    {
                        qDebug() << "Wheelevent";
                        return true;
                    }
                
                    return QMainWindow::eventFilter(obj, event);
                }
                

                I run Qt 5.15 under Linux (Xorg desktop). I do not have Qt6. This code debugs out "Wheelevent" when I roll the wheel anywhere over the main window, whether inside the QLabels or not.

                So either it's different at Qt6 (doubt it), I have misunderstood and this code does not represent your situation (I think it does) or where you say

                MyWidget which has the wheelEvent function overrided

                maybe if your override "eats" the wheel event (i.e. returns true) then that prevents the propagation you are wanting?
                UPDATE
                I tried subclassing the QLabels and overriding the eventFilter(). I still always received the MainWindows wheel event, after the label's wheel event, regardless of whether the latter's eventFilter() returned true or false. So it seems you should too?

                1 Reply Last reply
                0
                • T TikkiTxuck

                  @SGaist Thanks for the welcoming !

                  You mean calling installEventFilter on each widget which must receive the propagated event ? Can you provide some code example please ?

                  jsulmJ Offline
                  jsulmJ Offline
                  jsulm
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  @TikkiTxuck said in How to propagate the wheelEvent to multiple widgets of my centralwidget:

                  You mean calling installEventFilter on each widget

                  No, calling installEventFilter on top most widget (your main window for example)...

                  https://forum.qt.io/topic/113070/qt-code-of-conduct

                  1 Reply Last reply
                  0
                  • T Offline
                    T Offline
                    TikkiTxuck
                    wrote on last edited by TikkiTxuck
                    #9

                    Ok! I make some progress base on your help and come to the following code:

                    #include <QtWidgets>
                    
                    class MyWidget : public QWidget {
                    public:
                        MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
                        }
                    
                        void paintEvent(QPaintEvent *event) override {
                            QPainter painter(this);
                            painter.fillRect(rect(), Qt::white);
                        }
                    
                    protected:
                        void wheelEvent(QWheelEvent *event) override {
                            qDebug() << "Wheel event on widget:" << objectName();
                            event->ignore();
                        }
                    };
                    
                    class EventFilter : public QObject {
                        Q_OBJECT
                    
                    public:
                        EventFilter(QObject *parent = nullptr) : QObject(parent) {}
                    
                    protected:
                        bool eventFilter(QObject *obj, QEvent *event) override {
                            if (event->type() == QEvent::Wheel) {
                                QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
                    
                                // Propagate the wheel event to other widgets in the layout
                                QList<QWidget*> widgets = obj->findChildren<QWidget*>();
                                for (QWidget *widget : widgets) {
                                    if (widget != obj) {
                                        QApplication::sendEvent(widget, new QWheelEvent(
                                            wheelEvent->position(), wheelEvent->globalPosition(),
                                            wheelEvent->pixelDelta(), wheelEvent->angleDelta(),
                                            wheelEvent->buttons(), wheelEvent->modifiers(),
                                            wheelEvent->phase(), wheelEvent->inverted()
                                        ));
                                    }
                                }
                    
                                event->accept();
                                return true;
                            }
                    
                            return QObject::eventFilter(obj, event);
                        }
                    };
                    
                    class MyMainWindow : public QMainWindow {
                    public:
                        MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
                            setObjectName("MainWindow");
                    
                            centralWidget_ = new QWidget;
                            centralWidget_->setObjectName("CentralWidget");
                            layout_ = new QVBoxLayout(centralWidget_);
                    
                            for (int i = 0; i < 4; ++i) {
                                MyWidget *widget = new MyWidget(this);
                                widget->setObjectName("Widget " + QString::number(i));
                                layout_->addWidget(widget);
                            }
                    
                            setCentralWidget(centralWidget_);
                            installEventFilter(&eventFilter_);
                        }
                    
                    private:
                        QWidget *centralWidget_;
                        QVBoxLayout *layout_;
                        EventFilter eventFilter_;
                    };
                    
                    int main(int argc, char *argv[]) {
                        QApplication app(argc, argv);
                    
                        MyMainWindow mainWindow;
                        mainWindow.show();
                    
                        return app.exec();
                    }
                    
                    #include "main.moc"
                    

                    As excepted, my event is propagated to the other widgets but the widget that originally received the event receive it twice. How to fix this ?

                    JonBJ 1 Reply Last reply
                    0
                    • T TikkiTxuck

                      Ok! I make some progress base on your help and come to the following code:

                      #include <QtWidgets>
                      
                      class MyWidget : public QWidget {
                      public:
                          MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
                          }
                      
                          void paintEvent(QPaintEvent *event) override {
                              QPainter painter(this);
                              painter.fillRect(rect(), Qt::white);
                          }
                      
                      protected:
                          void wheelEvent(QWheelEvent *event) override {
                              qDebug() << "Wheel event on widget:" << objectName();
                              event->ignore();
                          }
                      };
                      
                      class EventFilter : public QObject {
                          Q_OBJECT
                      
                      public:
                          EventFilter(QObject *parent = nullptr) : QObject(parent) {}
                      
                      protected:
                          bool eventFilter(QObject *obj, QEvent *event) override {
                              if (event->type() == QEvent::Wheel) {
                                  QWheelEvent *wheelEvent = static_cast<QWheelEvent*>(event);
                      
                                  // Propagate the wheel event to other widgets in the layout
                                  QList<QWidget*> widgets = obj->findChildren<QWidget*>();
                                  for (QWidget *widget : widgets) {
                                      if (widget != obj) {
                                          QApplication::sendEvent(widget, new QWheelEvent(
                                              wheelEvent->position(), wheelEvent->globalPosition(),
                                              wheelEvent->pixelDelta(), wheelEvent->angleDelta(),
                                              wheelEvent->buttons(), wheelEvent->modifiers(),
                                              wheelEvent->phase(), wheelEvent->inverted()
                                          ));
                                      }
                                  }
                      
                                  event->accept();
                                  return true;
                              }
                      
                              return QObject::eventFilter(obj, event);
                          }
                      };
                      
                      class MyMainWindow : public QMainWindow {
                      public:
                          MyMainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
                              setObjectName("MainWindow");
                      
                              centralWidget_ = new QWidget;
                              centralWidget_->setObjectName("CentralWidget");
                              layout_ = new QVBoxLayout(centralWidget_);
                      
                              for (int i = 0; i < 4; ++i) {
                                  MyWidget *widget = new MyWidget(this);
                                  widget->setObjectName("Widget " + QString::number(i));
                                  layout_->addWidget(widget);
                              }
                      
                              setCentralWidget(centralWidget_);
                              installEventFilter(&eventFilter_);
                          }
                      
                      private:
                          QWidget *centralWidget_;
                          QVBoxLayout *layout_;
                          EventFilter eventFilter_;
                      };
                      
                      int main(int argc, char *argv[]) {
                          QApplication app(argc, argv);
                      
                          MyMainWindow mainWindow;
                          mainWindow.show();
                      
                          return app.exec();
                      }
                      
                      #include "main.moc"
                      

                      As excepted, my event is propagated to the other widgets but the widget that originally received the event receive it twice. How to fix this ?

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #10

                      @TikkiTxuck
                      Make sure none of the child widgets propagate the event back to their parent?
                      Start with a central widget which contains no child widgets. Does that work or duplicate? Then add a single child widget and check that. Etc.

                      T 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @TikkiTxuck
                        Make sure none of the child widgets propagate the event back to their parent?
                        Start with a central widget which contains no child widgets. Does that work or duplicate? Then add a single child widget and check that. Etc.

                        T Offline
                        T Offline
                        TikkiTxuck
                        wrote on last edited by
                        #11

                        @JonB In the code I provide in my previous message, the MyWidget seems to execute the code assiocated to the wheelevent, and then the event is propagated to the parent widget (the central widget is this case). And the central widget re-propagate the event to all its children (including the original widget).

                        How to avoid this first process, the one before sending the event to the parent ?

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved