[Interest] Strange problem where exec() of dialogs returns immediately

Nikos Chantziaras realnc at gmail.com
Sun Mar 11 18:39:31 CET 2012

On 11/03/12 19:09, Thiago Macieira wrote:
> On domingo, 11 de março de 2012 18.45.50, Nikos Chantziaras wrote:
>> On 11/03/12 18:33, Thiago Macieira wrote:
>>> On domingo, 11 de março de 2012 18.25.58, Nikos Chantziaras wrote:
>>>>> But it is the creation of that message box that causes the problem,
>>>>> right?
>>>>> Try removing the message box and you'll see it works again.
>>>> Of course if I remove the message box the bug doesn't trigger, because
>>>> the point of this is that exec() returns immediately.  If I remove the
>>>> message box, there's no call to exec().
>>>> I'm reporting a problem with exec(), not the absence of one when not
>>>> using exec()
>>> It looks like you forgot to accept the close event and pass it to the
>>> QMainWindow class. It will not close unless you let it close.
>> I suspect that you didn't look at the code.
> And I suspect you didn't read my reply.
> void MainWindow::closeEvent(QCloseEvent* e)
> {
>      QMessageBox* msgBox = new QMessageBox(QMessageBox::Question,
>                                            "Quit",
>                                            "Quit the application?",
>                                            QMessageBox::Yes |
> QMessageBox::Cancel, this);
>      msgBox->setDefaultButton(QMessageBox::Cancel);
>      if (msgBox->exec() == QMessageBox::Yes) {
>          qDebug()<<  "Yes";
>          exit(0);
>      } else {
>          qDebug()<<  "Cancel";
>          e->ignore();
>      }
> }
> I don't see e->accept() or QMainWindow::closeEvent(e).

Yeah, I omitted the correct implementation because it would be 
irrelevant.  e->accept() would need to happen after the msgBox->exec() 
call, so it would be of no consequence to exec() returning prematurely 
without any user input.

> If that msgBox->exec() returns immediately, it's because the event loop is
> already exiting. You cannot loop again while the quit flag is active.
> You connected the lastWindowClosed() signal to the application's quit() slot,
> so my guess is that somehow the last window *was* closed, the signal emitted,
> the event loop started to quit, which means you can't open any more dialogs.
> Which begs the question: which window was closed? It seems impossible that
> it's the main window, because we're inside its closeEvent. Looking at your
> code again, we see this:
> void Application::main()
> {
>      QFileDialog::getOpenFileName(0, "TEST", "", "All files (*)");
>      this->fMainWin->show();
>      while (true) {
>          qApp->processEvents(QEventLoop::WaitForMoreEvents |
> QEventLoop::AllEvents);
>      }
> }
> Note how you open and *close* a window before showing the main window. That
> means the lastWindowClosed() signal got emitted. You can't start new event
> loops now until this event loop comes out of app->exec().

That was it.  Very nice catch, Thiago.  Thank you very much!

(Missing that one seems so stupid in hindsight...)

> Note how even you had to force an event loop by that horrible while (true)
> construct. Remove it completely. Once you solve the problem of the last window
> closing too soon, the main event loop will take care of the main window's
> lifetime.

It's not optimal, but needed.  The application is an engine for running 
programs in it, and those programs have their own internal event loops. 
  They call callbacks so the host application can advance its own event 
loop.  In those callbacks I then do processEvents().  There's no way 
around that.

Even though I've dealing with this for years, I'm still not sure how to 
correctly advance Qt's event loop.  For example is:

   qApp->sendPostedEvents(0, QEvent::DeferredDelete);

even needed?  I think it takes care of deleting objects (for 
deleteLater() calls), but seems to produce 100% CPU load on Mac OS X.

More information about the Interest mailing list