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. Callback for when a QWidget window is closed?
QtWS25 Last Chance

Callback for when a QWidget window is closed?

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 3 Posters 2.3k Views
  • 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.
  • R Offline
    R Offline
    Rarrum
    wrote on 8 Oct 2022, 03:58 last edited by
    #1

    I'm learning Qt, and have a simple application with two windows. I'm trying to write code that gets called when either window is closed, but I can't get Qt to call me when this happens. I've distilled the problem down to this sample app:

    #include <vector>
    #include <iostream>
    
    #include <QApplication>
    #include <QWidget>
    #include <QPushButton>
    #include <QObject>
    
    int main(int argc, char **argv)
    {
        std::cout<<"Meow Start"<<std::endl;
    
        QApplication app(argc, argv);
        std::vector<std::unique_ptr<QWidget>> allWindows;
    
        {
            std::unique_ptr<QWidget> window = std::make_unique<QWidget>();
            window->resize(320, 240);
            window->setWindowTitle("One");
            window->show();
    
            QObject::connect(window.get(), &QWidget::close, [&]()
            {
                std::cout<<"One close"<<std::endl;
            });
    
            allWindows.emplace_back(std::move(window));
        }
    
        {
            std::unique_ptr<QWidget> window = std::make_unique<QWidget>();
            window->resize(320, 240);
            window->setWindowTitle("Two");
            window->show();
    
            QObject::connect(window.get(), &QWidget::close, [&]()
            {
                std::cout<<"Two close"<<std::endl;
            });
    
            allWindows.emplace_back(std::move(window));
        }
    
        std::cout<<"Before exec"<<std::endl;
        int execResult = app.exec();
        std::cout<<"After exec"<<std::endl;
        return execResult;
    }
    

    When I run this, I get two windows, but neither close event is called. The output leads me to believe that "close" is not the right thing to use here:

    xmake run
    
    Meow Start
    QObject::connect: signal not found in QWidget
    QObject::connect: signal not found in QWidget
    Before exec
    After exec
    

    I've tried using the "destroyed" connect call instead, which doesn't produce the signal not found errors, and is closer to working:

            QObject::connect(window.get(), &QWidget::destroyed, [&]()
            {
                std::cout<<"One destroyed"<<std::endl;
            });
    

    However the code isn't called when I close any individual window. But both callbacks are called after both windows are closed:

    xmake run
    
    Meow Start
    Before exec
    After exec
    One destroyed
    Two destroyed
    

    From some searching, I heard about the DeleteOnClose attribute:

    window->setAttribute(Qt::WA_DeleteOnClose, true);
    

    This gets the callback to work, however the app crashes upon closing:

    xmake run
    
    Meow Start
    Before exec
    Two destroyed
    One destroyed
    After exec
    error: execv(C:\vc\EasyAutoTracker\test\build\windows\x64\release\test.exe) failed(-1073741819)
    

    I wondered if this was causing the actual QWidget object to be deleted prematurely, so I removed my app's code to free it, which solved that problem. However I'd prefer to handle that deletion myself when other code is ready for that object to actually go away.

    Is there a better way to get this "the user closed the window" callback working without setting the DeleteOnClose attribute?

    1 Reply Last reply
    0
    • C Offline
      C Offline
      ChrisW67
      wrote on 8 Oct 2022, 04:57 last edited by
      #2

      QWidget::close() is not signal.
      You want to subclass QWidget::closeEvent() and emit a signal of your own, or do whatever processing you intended there.

      The destroyed() signal will be emitted during destruction of the QWidget instance i.e. when delete is called on the object. In idiomatic Qt programming this would happen when the widget's parent is destroyed (most of the time) or when the stack-based widget goes out of scope (the program's top-level widgets in main()).

      1 Reply Last reply
      1
      • R Offline
        R Offline
        Rarrum
        wrote on 8 Oct 2022, 05:01 last edited by
        #3

        I was hoping to avoid having to subclass it, but I'll try that route. Thanks!

        1 Reply Last reply
        0
        • R Offline
          R Offline
          Rarrum
          wrote on 8 Oct 2022, 05:24 last edited by
          #4

          Can confirm, this did the trick. Instead of using QWidget directly, I use:

          #include <functional>
          
          #include <QWidget>
          #include <QtGui/QCloseEvent>
          
          class ClosableQWidget: public QWidget
          {
          protected:
              inline void closeEvent(QCloseEvent *event) override
              {
                  if (closeCallback)
                      closeCallback();
              }
          
          public:
              std::function<void()> closeCallback;
          };
          

          Then I can hookup a callback similar to the connect pattern, with:

              window->closeCallback = [&]()
              {
                  std::cout<<"Window was closed"<<std::endl;
              };
          
          J 1 Reply Last reply 8 Oct 2022, 07:31
          0
          • R Rarrum
            8 Oct 2022, 05:24

            Can confirm, this did the trick. Instead of using QWidget directly, I use:

            #include <functional>
            
            #include <QWidget>
            #include <QtGui/QCloseEvent>
            
            class ClosableQWidget: public QWidget
            {
            protected:
                inline void closeEvent(QCloseEvent *event) override
                {
                    if (closeCallback)
                        closeCallback();
                }
            
            public:
                std::function<void()> closeCallback;
            };
            

            Then I can hookup a callback similar to the connect pattern, with:

                window->closeCallback = [&]()
                {
                    std::cout<<"Window was closed"<<std::endl;
                };
            
            J Offline
            J Offline
            JonB
            wrote on 8 Oct 2022, 07:31 last edited by
            #5

            @Rarrum
            Indeed. Unlike connecting to signals, accessing Qt ...Event() methods requires subclassing. If you do not wish to do that, be aware that you can use QObject::eventFilter() to avoid having to subclass.

            1 Reply Last reply
            1

            1/5

            8 Oct 2022, 03:58

            • Login

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