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

Why is setting the accept flag of certain QEvents sufficient to cause behaviour?



  • Hi forums,

    I understand that in the Qt events system, events are dispatched to appropriate objects by calling their event() function with the relevant QEvent object as a parameter.

    I also understand that these QEvent objects (and all its subclass objects) have an accept flag, which can either be:

    1. set to indicate that the current recipient object will process/handle the event (the event handling will be contained within the recipient object)
    2. cleared to indicate that the current recipient object does not wish to handle the event (therefore the event will be passed on to the current recipient's parent object, and this can go on recursively until the accept flag is set by some object or there are no more parent objects and the event is discarded)

    Therefore, it is my understanding that the purpose of the accept flag of a QEvent is to inform Qt when the propagation chain of a particular event can be terminated.

    Then, it is also my understanding that it is the job of the recipient QObject's event() function (or more specific functions such as mouseMoveEvent() if appropriate) implementations to produce the behaviour that is expected as a response to the event.

    With this in mind, I was confused when I found out that with certain events, like QCloseEvent, the simple act of setting their accept flag is sufficient to cause behaviour (in this case, to close the widget).

    The reason it confuses me is because I thought that the behaviour associated with the closeEvent would be coded within the recipient object's closeEvent() function, and therefore that merely setting the accept flag of the event object would not be sufficient to actually cause the window to close.

    What have I missed here? Are the accept flags of QEvent objects inherently associated with code required to produce behaviour? If so, then what is the purpose of writing "handling" behaviour code within the event functions of the recipient?

    Thanks in advance!



  • @Yuta
    Maybe this will help. It is not the closeEvent() which does the window closing. It is close() which does that. closeEvent() is a notification that handles close being requested.

    [slot]bool QWidget::close()

    Closes this widget. Returns true if the widget was closed; otherwise returns false.

    First it sends the widget a QCloseEvent. The widget is hidden if it accepts the close event. If it ignores the event, nothing happens. The default implementation of QWidget::closeEvent() accepts the close event.

    Also, this shows why either accept() or calling base QWidget::closeEvent() both accept the event, and allow close() to proceed.


  • Lifetime Qt Champion

    Hi,

    The CloseEvent handling is "reversed". By default the closing shall happen so you have to stop it from happening if that's what you want.



  • @SGaist Hi, thank you for your reply. Yes, I understand that the handling is "reversed" in closeEvents. And I also understand that in most cases, the accept flag of event objects are set by default, and so the default behaviour of a close event is to close the window. But what I am wondering is why, when/if you reimplement closeEvent() functions, all you need to do is event->accept() to close the window. I thought that you would need to write specific handling code within the closeEvent() function to actually close the window, but I am confused because actually no code is required, and all you need is event->accept(). In other words, I thought that the purpose of the accept flags on events was solely to guide the event propagation process, and nothing else. I thought it was the job of event handling functions such as event(), mouseMoveEvent() or closeEvent() to contain code that produces behaviours in response to events. But, in the case of closeEvent(), it seems that the accept flag acutally serves a purpose in producing the actual behaviour of the event (window closing), because all that an implementation of closeEvent() has to do to allow the window to close is to make sure that event->isAccepted() == true. This is where I got confused. Are the accept flags of event objects commonly associated with their actual behaviours within the application that you are building? And in the case of closeEvents, where is the code located which is responsible for actually carrying out the behaviour (i.e. closing the window)?– because it is certainly not directly inside closeEvent() and I am confused. I hope that I am explaining my question clearly...



  • @Yuta

    Accept in this case does not mean that the accept itself closes the window. It "swallows" the event and signals that the event was handled and can be removed from Event Queue. Then the window will hide and get destroyed (destructed).
    So there is no code to literally close the widget/window in accept, if this is what you thought :)

    QWidget::closeEvent is the event handler for any QWidget. If you don't want the default behavior, you can reimplement it and set your custom handling to your widget.



  • @Pl45m4 Thanks for your reply, and for all your collective patience with my question!

    So let's say that you want to reimplement the QWidget::closeEvent() for your custom window, because you want to handle cases where the QCloseEvent is ignored (e.g. the window contains work that should be saved first). I have seen many examples and tutorials where they reimplement the function in a way similar to below:

    void YourCustomWindow::closeEvent(QCloseEvent * event)
    {
       if (windowCanBeClosed()) {
          // If the window can be closed, close it by calling event->accept()
          event->accept();
       } else {
          // Otherwise, the window should remain open, so call event->ignore()
          event->ignore();
       }
    }
    

    Now, in the above example I understand why calling event->ignore() causes the QCloseEvent to be ignored, and therefore the window to remain open. However, I am confused why simply calling event->accept() leads to the window actually closing. I thought that you would at least need to call the default event handler function (i.e. QWidget::closeEvent() in this case) for the event to be properly handled and produce any behaviour, for example like this:

    void YourCustomWindow::closeEvent(QCloseEvent * event)
    {
       if (windowCanBeClosed()) {
          // If the window can be closed, first accept the event
          event->accept();
          // Then close the window by calling the default event handler
          QWidget::closeEvent(event);
       } else {
          // Otherwise, the window should remain open so ignore the event
          event->ignore();
       }
    }
    

    But apparently, you don't even need to call the base class's default closeEvent() function! All you need to do is just event->accept(). This is why I am confused. Who is actually handling the QCloseEvent by hiding and destroying the window? It seems like the first example of YourCustomWindow::closeEvent() should not do anything, because all it is doing is just calling event->accept() or event->ignore().

    I hope this makes my question clearer– I apologise that I am probably very bad at explaining my question and I thank your patience!



  • @Yuta
    Maybe this will help. It is not the closeEvent() which does the window closing. It is close() which does that. closeEvent() is a notification that handles close being requested.

    [slot]bool QWidget::close()

    Closes this widget. Returns true if the widget was closed; otherwise returns false.

    First it sends the widget a QCloseEvent. The widget is hidden if it accepts the close event. If it ignores the event, nothing happens. The default implementation of QWidget::closeEvent() accepts the close event.

    Also, this shows why either accept() or calling base QWidget::closeEvent() both accept the event, and allow close() to proceed.



  • @JonB said in Why is setting the accept flag of certain QEvents sufficient to cause behaviour?:

    It is close()

    Doesn't close() just create a request to close the window (closeEvent)?
    The window/widget is "closed" using hide + its destructor.



  • @Pl45m4
    You may know more than I. I pasted the explanation from QWidget::close(). In either case, it seems to me it is the caller of closeEvent() which does the closing, not closeEvent() itself, which does the closing, which I think is germane to the question @Yuta is asking.



  • @Yuta

    BTW:
    You should call the base implementation because theoretically you can do anything in your reimplemented closeEvent, even stuff that does not handle the event, but calls some of your functions. After that, you would call the base implementation to keep the default handling (otherwise the window would not close properly)

    For example:

    MyWigdet::closeEvent(QCloseEvent *e){
    
    // Saves some settings before closing the widget
    writeToFile();
    
    QWidget::closeEvent(e);
    
    }
    


  • @JonB and @Pl45m4 thank you for your answers.

    @Pl45m4 said in Why is setting the accept flag of certain QEvents sufficient to cause behaviour?:

    The window/widget is "closed" using hide + its destructor.

    Ah– so then who calls the window's hide() and destructor? In a closeEvent() reimplementation like the one below (which is seen in many example projects, and it works) those functions are not overtly called anywhere.

    void YourCustomWindow::closeEvent(QCloseEvent * event)
    {
       if (windowCanBeClosed()) {
          event->accept();
       } else {
          event->ignore();
       }
    }
    

    And I suspect it must have something to do with the QCloseEvent object itself, because from the above code we can infer that whether the window will be closed or not depends solely on whether the accept flag of the QCloseEvent is set or cleared.



  • @Yuta
    I have to say: I pasted from QWidget::close() documentation for you, and I think it's pretty clear what is happening. It seems to me it answers the questions you are asking, e.g. the latest post's two questions.



  • @JonB Apologies! I did read your reply when you first posted it, but I was too thick to understand what you actually meant. I have just re-read it and thought about it– and what you are saying has answered my question! Thank you. I will mark this post as solved.



  • @Yuta
    BTW: for the kind of detail you are looking for, are you aware that even if you do not have the Qt sources/do not compile Qt yourself (e.g. I do not, and do not have the source files). there is a site which has all the Qt source code and allows you to click to navigate on all the code calls?

    You will find the code for QWidget::close() at https://code.woboq.org/qt5/qtbase/src/widgets/kernel/qwidget.cpp.html#_ZN7QWidget5closeEv It actually just reads:

    bool QWidget::close()
    {
        return d_func()->close_helper(QWidgetPrivate::CloseWithEvent);
    }
    

    so you will have some clicking to do (here just click on close_helper, it's immediately above) if you want to follow what it actually performs :) But if I wanted your level of detail I would at least give it a go!

    While you are there you will also see the base implementation of QWidget::closeEvent():

    void QWidget::closeEvent(QCloseEvent *event)
    {
        event->accept();
    }
    

    This is why it doesn't make any difference whether your override calls the base implementation (at least so long as you inherit directly from QWidget, so there is no other possible overriding going on --- if you have a deeper class, I would prefer to call the base just in case it does something else) or just goes event->accept() directly, or both!


Log in to reply