Qt Application hangs on exit (after QDialog exec) - c++

I'm using Qt to build a UI and I need to have a dialog window show up before the main app window, so that the user can select some files to load ans things like that.
What I've got is a fairly simple main:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
IView *view = new QtView();
view->showView();
int rc = a.exec();
std::cout << "exit" << std::endl;
return rc;
}
the QtView class is the concrete implementation of the IView interface.
It has the mainwindow instance and a QDialog instance too. int the view->showView() method this is what I've got:
void QtView::showView()
{
this->_configDialog->exec();
this->_mainAppWindow->show();
}
It works fine, the dialog opens and when the user clicks OK, exec returns and the main window appears. The problem is that when I quit the main window I get a zombie process and the app just seems to hang even though all the windows have been closes and I never get the "exit" I print out in the main just before the main returns.
I'm not sure what I'm doing wrong, but I get the same resutl even if I click on the cross to close the dialog, the main window opens up, and once closed the whole things just hangs there.
If anyone has any advice, that would be cool.
Thanks.

I Fixed my problem.
I used the accepted/rejected/finished(int) signal from the QDialog to trigger the show slot on the main app window, and display it if the dialog was accepted.
Thanks for the help anyway.

I think the possible reason for this behavior is that your configuration dialog may not have a parent widget set on it (it's a blind guess though as you haven't cited the relevant portion of the code). That's because QApplication by default would only quit when all the windows with no parent are closed. And the thing is, a dialog is not a window, technically - it has the Qt::Dialog window type rather than Qt::Window. That means any "orphaned" dialog, that is closed, will still prevent the application from exiting automatically.
The solution?
Either giving a parent to the dialog or enabling the Qt::WA_QuitOnClose attribute:
this->_configDialog->setAttribute(Qt::WA_QuitOnClose);

Related

How to show dialog when main window became visible for the very first time in Qt widgets application?

I have Qt widgets application that has to authorize user with web service request before he can use the program. If user can not sign in for any reason, I have to exit the application.
.NET Framework implements Load event for that: when user sees window for the very firt time (the keyword here is "user sees"), it is possible to display dialog; if dialog result is not OK, we call close on main application window.
With Qt, we can override showEvent. However, it fires before user really can see main window. When I create dialog in showEvent, it appears without main window, and when I close main window in showEvent, it doesn't close (because it is not opened at the moment) and appears later event if user failed to sign in. It appears even after QApplication::quit() call.
My question is: is there a way to receive exactly the same functionality as in .NET Framework/Windows API and get event fired when user really sees window and not when he "may be sees something or will see soon"? It is possible to start timer from showEvent to get similar effect, but I think it is not professional, because you never know what may happend in user computer (may be its CPU works on 100% now), and you can not have real guarantee that timer will show dialog at correct moment.
I would try to create MainWindow and hide() it be default. The only widget to be shown at startup should be then the Login-Dialog. I would connect the successful login with the show() slot of the QMainWindow and the login failure - with the quit slot of the application.
I usually do something like this in my main.cpp:
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
LoginDialog dialog;
if(!dialog.exec()){
return 1;
}
MainWindow w;
w.show();
return a.exec();
}
that (of course) after having LoginDialog defined to inherit from QDialog and MainWindow defined to inherit from QMainWindow.
Create the main dialog at application startup, and only create the main window when the service responds positively.
You don't really need to dig deep in the event handlers.

Why does opening a QDialog the second time cause it to be shown immediately, not animated smoothly?

In my Qt application, I have a QMainWindow subclass for the UI (ProgramWindow) and a QDialog subclass (SettingsDialog) which is shown when the user clicks the "Settings" button in the main window. I'm using the following code to implement this:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ProgramWindow pw;
pw.show();
pw.setFixedSize(pw.size());
SettingsDialog set(&pw);
QObject::connect(&pw, SIGNAL(settingsButtonClicked()), &set, SLOT(show()));
return a.exec();
}
However, I have noticed that when the settings dialog is shown for the second time (the user clicks the settings button, the dialog is shown, then the user closes it, then clicks on "Settings" again) the window is not shown "smoothly", as other windows are in Windows 8.1's default theme, it just suddenly appears on the screen like in the old XP theme, for example. Note that this doesn't happen the first time the window is shown.
What could be the reason?
EDIT: I suspect that instead of destroying the window, close() called on a QDialog will end up calling Win32's ShowWindow with the SW_HIDE parameter, and so when it's shown again later, the Windows UI manager doesn't see it as creating the window but merely re-showing it, so it doesn't "play" the animation. The solution is to create the dialog using new and letting Qt dispose of it when appropriate:
MyDialog* dialog = new MyDialog;
dialog->show();
// in MyDialog's constructor
setAttribute(Qt::WA_DeleteOnClose);

QApplication does not exit when main window closes

I have a QMainWindow that is used to browse and view images with. These images are special medical images that are read using a wrapper that I wrote.
The GUI has a QListview on the left, which shows a list of thumbnails. When the user selects one of them, the QVTKWidget displays the corresponding image on the right. I use a vtkRenderWindowInteractor to manipulate the displayed image.
My main looks like the following:
#include <QApplication>
#include "GUIClassName.h" //inherits from QMainWindow
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GUIClassName w;
w.show();
return a.exec();
}
My closeEvent looks like the following:
void GUIClassName::closeEvent(QCloseEvent* event)
{
// mainInteractor is a vtkSmartPointer<vtkRenderWindowInteractor>
if (this->_mainInteractor != NULL)
this->_mainInteractor->TerminateApp();
event->accept();
}
The issue is that when I close the QMainWindow, the application does not terminate. That is the command prompt stays open and Press any key to continue does not appear. If I Ctrl+break, then the application exits (obviously) but I get the following message:
QObject::~QObject: Timers cannot be stopped from another thread
I have noticed that if I only select one thumbnail and display it in the QVTKWidget, the program terminates just fine. But when I select one thumbnail, display it and then select another thumbnail, then the program does not terminate when I close the window.
I was wondering if anyone could tell me what I am doing wrong here. I would gladly copy/paste more code, but I am not sure which parts are relevant at the moment.
I have read the following in hopes of an answer, but so far I have been unable to solve this issue:
Qt app stays in memory even after MainWindow is closed
Qt process stays in memory after application closes
C++ application does not kill all processes on exit
Thanks
Did you stop all your threads?
I'm not familiar with VTK, but looks like someone run some code in thread and did not stop them properly.
RazrFalcon gave me a good hint. I am not an expert in Qt (yet) so I was looking for the Qthread that was being executed at all the wrong places.
The answer lies in the vtkRenderWindowInteractor class. For most vtkObjects (if I am not mistaken), calling new on the vtkSmartPointer deletes/stops the object if it already exists. However, this does not happen for vtkRenderWindowInteractor.
The solution was the following. When switching between thumbnails, I had to check for the existence of the interactor and if it was running, I would just call
this->_mainInteractor->TerminateApp();
to stop the hidden Qthread.

Qt MainWindow CloseEvent Mac Cmd+Q

On OS X 10.9 with Qt 5.2 and the following application code
#include "mywindow.h"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
MyWindow w();
w.show();
return a.exec(); }
where MyWindow derives from QMainWindow and overwrites the closeEvent(QCloseEvent*) method, this method is called when I close the application window (e.g. click the windows (x) close button), but it is not invoked when I close the application via the main Menu -> "Quit " or via the "CMD + Q" key shortcut.
From looking around the web and numerous question I got the impression that closing the application should invoke the closeEvent for all top level windows. Is this not the case, or is something going wrong here?
Edit: In addition to the above ways of closing the application, are there any other instances that I in general should handle that would result in QApplication::quit rather than invoking the window's close event? What about a system shutdown for example?
When handling a close event, I'm confirming that the user really wants to quit and I make sure cleanup like writing back changed settings is happening. Should I maybe move cleanup / saving settings to the destructor instead and do the confirmation query in closeEvent?
By default on the Mac, Qt will create an Apple Menu | Quit if a menubar doesn't exist with either quit or exit entry. That default created entry will call QApplication::quit() which will not trigger your MyWindow::closeEvent().
In your UI you should add a menu item named Exit (on the Mac it will be automagically renamed to Quit) and in the MyWindow class constructor you should connect that action to the close() slot (which is inherited from QWidget).
Update- To take a shot at your additional questions, no the destructor should probably only be used for deallocation of memory (releasing file locks, etc). Anything that could potentially involve user interaction (such prompting for a file location or alerting the user via a QMessageBox that something failed) will need to go in the closeEvent method. Saving window geometry (and other simple items using QSettings) should also be done via the closeEvent (though, I have seen code that saves geometry in the destructor work, there could be some edge cases where it does unexpected things).

How to close correctly a Qt program?

When I try to close my Qt program, it just keeps running in the background though there's no window anymore.
Basically, I would like to know what I should do so it closes properly when I click the red cross on my main window (which has no parent).
Following this link, I tried a few things like :
QApplication app(argc, argv);
//...
app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
return app.exec();
or
QApplication app(argc, argv);
//...
app.setQuitOnLastWindowClosed(true);
return app.exec();
but neither work, the process still stays in memory, after the cross is clicked.
Then, how can I close correctly my program ?
You can close your application manually using QApplication::quit().
By default the execution is terminated when the last top level window with the Qt::WA_QuitOnClose attribute has been closed. You don't need to connect lastWindowClosed to quit because it repeats the default setQuitOnLastWindowClosed behavior. You don't need to do setQuitOnLastWindowClosed(true) either because it's true by default. The code you've posted does nothing (if nothing is changed somewhere else).
Possible solutions:
Check your main window attributes. Maybe you have removed Qt::WA_QuitOnClose attribute.
If you have reimplemented closeEvent in your top level window, check that close event is being accepted.
Check if there are some other top level widgets that may be hidden but not closed. Use QApplication::topLevelWidgets() to list them.