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. Is there a way to find out which widget consumed an event?
Qt 6.11 is out! See what's new in the release blog

Is there a way to find out which widget consumed an event?

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 5 Posters 3.3k Views 4 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.
  • Axel SpoerlA Axel Spoerl

    Assuming that the right window flags and attributes are set, I can't see more than three options:

    • (a) Someone else (i.e. the QTabBar) steals focus, so the custom widgets don't get get it.
    • (b) The custom widgets, for some reason, do not accept focus.
    • (c) The custom widgets, for some reason, get key events but they don't consume them. So they get propagated down the parental chain.

    You have already excluded (a) by calling setFocusPolicy(Qt::NoFocus); on the QTabBar.
    In addition, you can

    connect (qApp, &QApplication::focusChanged, qApp, [&](Qwidget *old, QWidget *now){qDebug() << old->objectName() << now-objectName(); });
    

    ...to debug focus delivery.

    To exclude (c), override QWidget's virtual void keyPressEvent(QKeyEvent *event) (if you haven't already), send a fake key event directly to your custom widget and see, who eventually consumes it.

    QKeyEvent ke(/* construct it according to what gets delivered to QTabBar */);
    QApplication::sendEvent(myCustomWidget, &ke);
    

    You can also (for analysis only!) intercept the key events of the tab bar in an event filter and send them to a custom widget. That will probably result in a loop and crash the application. But surgeons have to carve the chest open before the bugfixing starts ;-)

    V Offline
    V Offline
    Violet Giraffe
    wrote on last edited by Violet Giraffe
    #9

    @Axel-Spoerl
    Great suggestions! I added the QApplication::focusChanged signal to my UI debugging tool which displays the widget hierarchy of the application, now I can see focus changes in real time.

    It appears that my custom widget cannot get focus by clicking the mouse. Other widgets always get it instead (first the QTabBar, after QTabBar got NoFocus policy - now it is QListWidget).

    However, If I press the Tab button enough times, it does get focus and starts receiving key events. But when I click on my widget, QListWidget gets focus again.
    And I can't assign NoFocus to all the widgets in the program, some of them should be focusable.

    You said "Assuming that the right window flags and attributes are set", what would be the right flags and attributes, and is it possible my problem is caused by not having the right ones?

    One thing that may be important is that this widget calls winId() to become a native window. And I'm debugging on Windows.

    Axel SpoerlA 1 Reply Last reply
    0
    • V Violet Giraffe

      @Axel-Spoerl
      Great suggestions! I added the QApplication::focusChanged signal to my UI debugging tool which displays the widget hierarchy of the application, now I can see focus changes in real time.

      It appears that my custom widget cannot get focus by clicking the mouse. Other widgets always get it instead (first the QTabBar, after QTabBar got NoFocus policy - now it is QListWidget).

      However, If I press the Tab button enough times, it does get focus and starts receiving key events. But when I click on my widget, QListWidget gets focus again.
      And I can't assign NoFocus to all the widgets in the program, some of them should be focusable.

      You said "Assuming that the right window flags and attributes are set", what would be the right flags and attributes, and is it possible my problem is caused by not having the right ones?

      One thing that may be important is that this widget calls winId() to become a native window. And I'm debugging on Windows.

      Axel SpoerlA Offline
      Axel SpoerlA Offline
      Axel Spoerl
      Moderators
      wrote on last edited by
      #10

      @Violet-Giraffe said in Is there a way to find out which widget consumed an event?:

      this widget calls winId() to become a native window

      Just for the records:
      QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

      my custom widget cannot get focus by clicking the mouse

      Have you overridden QWidget::event()?
      If so, does the override return QWidget::event(event)when a mouse event is delivered (and hopefully remains unconsumed)?
      What does qDebug() << myCustomWidget->testAttribute(Qt::WA_TransparentForMouseEvents)say?

      Software Engineer
      The Qt Company, Oslo

      V SGaistS 2 Replies Last reply
      0
      • Axel SpoerlA Axel Spoerl

        @Violet-Giraffe said in Is there a way to find out which widget consumed an event?:

        this widget calls winId() to become a native window

        Just for the records:
        QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

        my custom widget cannot get focus by clicking the mouse

        Have you overridden QWidget::event()?
        If so, does the override return QWidget::event(event)when a mouse event is delivered (and hopefully remains unconsumed)?
        What does qDebug() << myCustomWidget->testAttribute(Qt::WA_TransparentForMouseEvents)say?

        V Offline
        V Offline
        Violet Giraffe
        wrote on last edited by Violet Giraffe
        #11

        @Axel-Spoerl
        You're right, it must be related to the pointer events, but in a way that I cannot yet figure out. The thing is that this QWidget which doesn't get focus is acting as a host to a native widget with its own window procedure. That procedure wants to process WM_POINTERDOWN and does get it! Despite the host widget not getting focus. And the same procedure also wants to process WM_KEYDOWN and doesn't get it. The host widget doesn't get key events, too, unless manually focused by Tab.

        Axel SpoerlA 1 Reply Last reply
        0
        • V Violet Giraffe

          @Axel-Spoerl
          You're right, it must be related to the pointer events, but in a way that I cannot yet figure out. The thing is that this QWidget which doesn't get focus is acting as a host to a native widget with its own window procedure. That procedure wants to process WM_POINTERDOWN and does get it! Despite the host widget not getting focus. And the same procedure also wants to process WM_KEYDOWN and doesn't get it. The host widget doesn't get key events, too, unless manually focused by Tab.

          Axel SpoerlA Offline
          Axel SpoerlA Offline
          Axel Spoerl
          Moderators
          wrote on last edited by
          #12

          @Violet-Giraffe
          ...then all the fellow widgets are proven innocent and the issue is in that custom widget implementation. Please share the code or mark this post solved.

          Software Engineer
          The Qt Company, Oslo

          V 1 Reply Last reply
          0
          • Axel SpoerlA Axel Spoerl

            @Violet-Giraffe
            ...then all the fellow widgets are proven innocent and the issue is in that custom widget implementation. Please share the code or mark this post solved.

            V Offline
            V Offline
            Violet Giraffe
            wrote on last edited by Violet Giraffe
            #13

            Yes, you're right that Qt is not to blame, but could you please help me figure out how to solve the problem? The host widget looks like this:

            template <class WindowT>
            class WindowContainer : public QWidget, public WindowT {
            public:
            	WindowContainer(QWidget * parent)
            		: QWidget{parent}
            	{
            		winId(); /// ensure native window is created
            		setFocusPolicy(Qt::StrongFocus);
            	}
            
            protected:
            	bool nativeEvent(const QByteArray & eventType, void * message, long * result) override {
            		const auto msg = static_cast<MSG *>(message);
            		if (msg->message == WM_SHOWWINDOW) {
            			if (msg->wParam == TRUE) {
            				RECT rc;
            				::GetClientRect(msg->hwnd, &rc);
            				::SetWindowPos(WindowT::hWnd, HWND_TOP, rc.left, rc.top,
            					rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOZORDER);
            			} else {
            				::SetWindowPos(WindowT::hWnd, HWND_TOP, 0, 0, 0, 0,
            					SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOZORDER);
            			}
            		} 
            
            		return QWidget::nativeEvent(eventType, message, result);
            	}
            };
            

            If I remove the WM_SHOWWINDOW handling from the nativeEvent(), then the host widget becomes focusable and gets key events. But the native window (WindowT::hWnd) isn't displayed. Do you understand what exactly is happening?

            Specifically, I do not understand why the native windows gets WM_POINTERDOWN but doesn't get WM_KEYDOWN.

            It seems that I need to manually set focus to the host widget upon receiving WM_POINTERDOWN, but why? That feels like a hack, not a solution.

            V 1 Reply Last reply
            0
            • V Violet Giraffe

              Yes, you're right that Qt is not to blame, but could you please help me figure out how to solve the problem? The host widget looks like this:

              template <class WindowT>
              class WindowContainer : public QWidget, public WindowT {
              public:
              	WindowContainer(QWidget * parent)
              		: QWidget{parent}
              	{
              		winId(); /// ensure native window is created
              		setFocusPolicy(Qt::StrongFocus);
              	}
              
              protected:
              	bool nativeEvent(const QByteArray & eventType, void * message, long * result) override {
              		const auto msg = static_cast<MSG *>(message);
              		if (msg->message == WM_SHOWWINDOW) {
              			if (msg->wParam == TRUE) {
              				RECT rc;
              				::GetClientRect(msg->hwnd, &rc);
              				::SetWindowPos(WindowT::hWnd, HWND_TOP, rc.left, rc.top,
              					rc.right - rc.left, rc.bottom - rc.top, SWP_SHOWWINDOW | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOZORDER);
              			} else {
              				::SetWindowPos(WindowT::hWnd, HWND_TOP, 0, 0, 0, 0,
              					SWP_HIDEWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOREPOSITION | SWP_NOZORDER);
              			}
              		} 
              
              		return QWidget::nativeEvent(eventType, message, result);
              	}
              };
              

              If I remove the WM_SHOWWINDOW handling from the nativeEvent(), then the host widget becomes focusable and gets key events. But the native window (WindowT::hWnd) isn't displayed. Do you understand what exactly is happening?

              Specifically, I do not understand why the native windows gets WM_POINTERDOWN but doesn't get WM_KEYDOWN.

              It seems that I need to manually set focus to the host widget upon receiving WM_POINTERDOWN, but why? That feels like a hack, not a solution.

              V Offline
              V Offline
              Violet Giraffe
              wrote on last edited by
              #14

              P. S. This hack works to fix focus, and the host widget starts getting keyPressEvent(). But its nativeEvent() is not getting anything when keys are pressed. And neither does the underlying native window.
              ???

              Axel SpoerlA 1 Reply Last reply
              0
              • V Violet Giraffe

                P. S. This hack works to fix focus, and the host widget starts getting keyPressEvent(). But its nativeEvent() is not getting anything when keys are pressed. And neither does the underlying native window.
                ???

                Axel SpoerlA Offline
                Axel SpoerlA Offline
                Axel Spoerl
                Moderators
                wrote on last edited by
                #15

                @Violet-Giraffe
                Oh, didn't know that the code intercepts native events.

                The native WM doesn't know about Qt's focus chain. Therefore, WM_POINTERDOWN is easier delivered to the right window because it can be derived from the pointer position. WM_KEYDOWN can get delivered to the wrong window, when the native WM doesn't know about the right focus window. Even though MS-Windows is pretty synchronous and reliable, there are chances that event orders get mixed up and the native WM just makes a wrong assumption about where to deliver key events. Eventually, the wrong nativeEvent handler is called.

                A potential (and fairly solid) workaround is to override eventin the custom widget, intercept the focusAboutToChange and focusInevents, to forcefully propagate focus to the native window. Since that stuff heavily depends on the screen layout, I can't promise that it works. But if it works, it can reliably fix the problem. Code could look as follows:

                bool customWidget::event(QEvent* event)
                {
                    switch (event->type()) {
                    case QEvent::FocusIn:
                    case QEvent::FocusAboutToChange:
                        if (hasFocus() && ::GetFocus() != reinterpret_cast<HWND>(winId()))  {
                            QWidget* nativeParent = this;
                            while (nativeParent) {
                                if (nativeParent->isWindow())
                                    break;
                
                                nativeParent = nativeParent->nativeParentWidget();
                            }
                
                            if (nativeParent && nativeParent != this && ::GetFocus() == reinterpret_cast<HWND>(nativeParent->winId())) {
                                ::SetFocus(reinterpret_cast<HWND>(winId()));
                            }
                            break;
                        }
                    default:
                        break;
                    }
                    return QWidget::event(event);
                }
                

                Software Engineer
                The Qt Company, Oslo

                V 1 Reply Last reply
                1
                • Axel SpoerlA Axel Spoerl

                  @Violet-Giraffe
                  Oh, didn't know that the code intercepts native events.

                  The native WM doesn't know about Qt's focus chain. Therefore, WM_POINTERDOWN is easier delivered to the right window because it can be derived from the pointer position. WM_KEYDOWN can get delivered to the wrong window, when the native WM doesn't know about the right focus window. Even though MS-Windows is pretty synchronous and reliable, there are chances that event orders get mixed up and the native WM just makes a wrong assumption about where to deliver key events. Eventually, the wrong nativeEvent handler is called.

                  A potential (and fairly solid) workaround is to override eventin the custom widget, intercept the focusAboutToChange and focusInevents, to forcefully propagate focus to the native window. Since that stuff heavily depends on the screen layout, I can't promise that it works. But if it works, it can reliably fix the problem. Code could look as follows:

                  bool customWidget::event(QEvent* event)
                  {
                      switch (event->type()) {
                      case QEvent::FocusIn:
                      case QEvent::FocusAboutToChange:
                          if (hasFocus() && ::GetFocus() != reinterpret_cast<HWND>(winId()))  {
                              QWidget* nativeParent = this;
                              while (nativeParent) {
                                  if (nativeParent->isWindow())
                                      break;
                  
                                  nativeParent = nativeParent->nativeParentWidget();
                              }
                  
                              if (nativeParent && nativeParent != this && ::GetFocus() == reinterpret_cast<HWND>(nativeParent->winId())) {
                                  ::SetFocus(reinterpret_cast<HWND>(winId()));
                              }
                              break;
                          }
                      default:
                          break;
                      }
                      return QWidget::event(event);
                  }
                  
                  V Offline
                  V Offline
                  Violet Giraffe
                  wrote on last edited by
                  #16

                  @Axel-Spoerl, thank you!
                  So basically, there is no way to figure out why the native window doesn't want to receive focus? And no way to figure out why the QWidget host doesn't want to receive focus on mouse click either? These are probably two different issues, because solving the latter doesn't fix the former.

                  Axel SpoerlA 1 Reply Last reply
                  0
                  • V Violet Giraffe

                    @Axel-Spoerl, thank you!
                    So basically, there is no way to figure out why the native window doesn't want to receive focus? And no way to figure out why the QWidget host doesn't want to receive focus on mouse click either? These are probably two different issues, because solving the latter doesn't fix the former.

                    Axel SpoerlA Offline
                    Axel SpoerlA Offline
                    Axel Spoerl
                    Moderators
                    wrote on last edited by
                    #17

                    @Violet-Giraffe
                    What I love (under more) about C++: Where there is smoke, there is fire.
                    If the research takes a little longer, the answer is probably 42 ;-)

                    But to isolate the problem, we'd need to see and understand the full picture, rather than a few snippets of code.
                    What is the purpose of the custom widget, how is it implemented and how does it interact with the other widgets?
                    Are eventFilters and event overrides in place? Are any of the parent widgets heavy consumers of mouse and key events?
                    What's the reason and the purpose for descending into the rabbit hole of native events? What's happening there, that cannot be seen or done from the Qt event loop? Just the simple coincidence that (a) native events are intercepted and (b) a custom widget doesn't get certain events delivered, would make me suspicious. And please forgive my bluntness: Disclosing the native adventure only after eliminating other paths, is even more food for doubt.

                    Software Engineer
                    The Qt Company, Oslo

                    1 Reply Last reply
                    1
                    • V Violet Giraffe has marked this topic as solved on
                    • Axel SpoerlA Axel Spoerl

                      @Violet-Giraffe said in Is there a way to find out which widget consumed an event?:

                      this widget calls winId() to become a native window

                      Just for the records:
                      QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

                      my custom widget cannot get focus by clicking the mouse

                      Have you overridden QWidget::event()?
                      If so, does the override return QWidget::event(event)when a mouse event is delivered (and hopefully remains unconsumed)?
                      What does qDebug() << myCustomWidget->testAttribute(Qt::WA_TransparentForMouseEvents)say?

                      SGaistS Offline
                      SGaistS Offline
                      SGaist
                      Lifetime Qt Champion
                      wrote on last edited by
                      #18

                      Hi,

                      @Axel-Spoerl said in Is there a way to find out which widget consumed an event?:

                      Just for the records:
                      QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

                      Aren't you contradicting point 4 of Native Widgets VS Alien Widgets in QWidget's documentation ?

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

                      Axel SpoerlA V 2 Replies Last reply
                      2
                      • SGaistS SGaist

                        Hi,

                        @Axel-Spoerl said in Is there a way to find out which widget consumed an event?:

                        Just for the records:
                        QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

                        Aren't you contradicting point 4 of Native Widgets VS Alien Widgets in QWidget's documentation ?

                        Axel SpoerlA Offline
                        Axel SpoerlA Offline
                        Axel Spoerl
                        Moderators
                        wrote on last edited by
                        #19

                        @SGaist
                        You are actually right. I was referring to the properties of a QWidget, not to what happens on the WM side. At the point when I wrote the comment, I was unaware that there is native stuff involved. But the extended context shows my statement was imprecise. Thanks for bringing that up.

                        Software Engineer
                        The Qt Company, Oslo

                        1 Reply Last reply
                        0
                        • SGaistS SGaist

                          Hi,

                          @Axel-Spoerl said in Is there a way to find out which widget consumed an event?:

                          Just for the records:
                          QWidget::winId()is a const method that just returns the native window ID (if the platform supports it). The call doesn't change anything on the widget and it doesn't "become" anything else.

                          Aren't you contradicting point 4 of Native Widgets VS Alien Widgets in QWidget's documentation ?

                          V Offline
                          V Offline
                          Violet Giraffe
                          wrote on last edited by Violet Giraffe
                          #20

                          @SGaist said in Is there a way to find out which widget consumed an event?:

                          Aren't you contradicting point 4 of Native Widgets VS Alien Widgets in QWidget's documentation ?

                          Thanks for the clarification, that's exactly what I meant. And after Axel's response I started thinking maybe that is no longer the case in new versions of Qt or something, so it's great we cleared that up

                          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