Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Handing events from children to parent widget?



  • Hi,

    I know this is probably a very easy to solve problem, but I can't seem to get a satisfying solution.
    My problem is, that I want to pass a mouse click event to a parent widget.

    The situation is as follows:
    I've got a widget which contains 3 QPushButtons. They're arranged above each other in a grid layout. I want to implement a Drag N Drop feature. So if any of those buttons is clicked, I want to stick the whole parent widget to the mouse and so on. I didn't really dive deep on the drag part because I can't event get the buttons to pass their press event to that parent widget.
    What I've tried:
    I have overidden the mousePressEvent(QMouseEvent *e) in my custom child (QPushButton) class. The event then gets triggered when I click the button. Signals connected suddenly stop working, I don't really know why. When I now pass the event by hand EVERY button sends it's signals to the parent widget. Thats not what I want.
    So I implemented the mouse press in my widget. Then the click on the buttons didn't trigger the click event, but clicking slightly next to them did. Probably the invisible part where Qt puts the widget. Thats not what I want either.

    So here are my questions:
    Isn't there any EventBubbling?
    Why dont the child QPushButtons just pass their click event to the parent widget which then can handle them?

    Thanks in advance!



  • IIRC events are virtuals so they are handled at the level where they are applicable. Based on the way you explained it, it is unclear what your experienced behaviour really is in each condition.

    If you want to pass the event up from the child then explicitly call the parent event handler from within the child handler.

    I also suspect that you may be trying to implement drag/drop incorrectly so you should read up on the subject a bit more.



  • I'll do that, as soon as I get the event to work. I also want to learn how events work, the Drag n Drop thing is just the use case for now. Based on this I need the mousePressEvent.
    So you said they're virtual, but isn't the "forwarding to parent" part based on the Qt parents and not the C++ parent classes?
    My understanding of the happening was, that a child gets clicked. It has no implementation of the event itself so it delegates the event to it's parent widget (the Qt parent which is also used for deconstructing etc., not the C++ parent). And so on...
    Am I wrong?



  • So, your attempts works. Thank you very much. But I still got some questions:

    Parent *s = qobject_cast<Parent*>(parent());
        if (e->button() == Qt::LeftButton && s != nullptr) {
            s->mousePressEvent(e);
        } else {
            QPushButton::mousePressEvent(e);
        }
    

    This is code from my derived QPushButton class. The call of the mouse event to the parent object seems fine to me. But I don't really get why the else part works. If I leave that out, my connected slots to the "clicked()" signal stop working. Why is that and what exactly does QPushButton::mousePressEvent(e); do?

    Sry for those basic questions, still learning :D


  • Lifetime Qt Champion

    Hi
    QPushButton::mousePressEvent(e);
    call the base class version of the mousePressEvent virtual function.

    This ensures if the base class, does any handling/action on this event, its
    also run as if we didnt overwrite in our base class.

    This is often a must to as not to break functionality.
    Clicked() stopped working as you didnt call the base event handler, and the button was not allowed to do what it normally does, which includes sending the signal when you release the mouse.



  • @mrjj
    Okay, thank you. And why does the call via the class work? So in the first condition body I call the event through an object. I get why this works. The actual button instance is asked to execute it's mouse press method and there is definietly a instance with an implemented method so it simply gets called. But in the second part I just call it by class and it still does the job. This is more a general C++ noob question, but I still would be very thankful for a quick explaination :D

    Edit: Does this work because it's virtual and it just goes up the hierarchy of my current object and looks for a QPushButton which then gets asked to execute it's mouse press event?
    And is there a way to do this "automated"? So if I don't know which parent class is the next to implement the event, can I just say: I don't want to handle this, but the next one in the hierarchy should? I've seen something like "e->ignore()" but couldn't really get what it does.


  • Lifetime Qt Champion

    @m1212e Calling

    QPushButton::mousePressEvent(e);
    

    in a class derived from QPushButton calls the inherited implementation of mousePressEvent() (inherited from QPushButton). It is executed in the context of the calling instance.
    "I don't want to handle this, but the next one in the hierarchy should?" - that means that you actually want to handle it, but not in the derived class and then you need to know which of the super classes should handle it.
    e->ignore() - this is not related to inheritance. It just tells Qt that you do not want to handle this event in this class and not in its super classes. In that case the event will go to parent widget.



  • @jsulm
    Okay, that helped me a lot. Thank you very much!