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?
Forum Updated to NodeBB v4.3 + New Features

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

Scheduled Pinned Locked Moved Solved General and Desktop
20 Posts 5 Posters 2.4k 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

    @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