Terminating a application
-
Calling exit is basically pulling the power plug and killing the application. That is certainly a way, but not always desirable.
You may declare a signal in your main window and connect the signal to quit before you call exec(). That would be one solution. The signal may be called anywhere in your main window.
Another one is pass the pointer to QApplication to your main window. This makes the quit accessible. -
Taedium, yes that worked and does exactly what i wanted.
Koahnig, I agree and in other cases i have done that to make sure that connections are closed along with any files that may have been open. In this case this is at the very beginning of the program, i know that is nothing open and i don't want them to create a new file if they are not sure.
Thanks
-
@koahnig Connecting to quit() slot won't help here, because @Dan3460 wants app to quit inside QMainWindow ctor, before the main event loop gets exec()'ed.
From docs:
Tells the application to exit with return code 0 (success). Equivalent to calling QCoreApplication::exit(0).
And:
After this function has been called, the application leaves the main event loop and returns from the call to exec(). The exec() function returns returnCode. If the event loop is not running, this function does nothing.
But I agree that calling exit() directly is not the usual way of how things should be done properly :)
-
What do you mean with the app qutting inside QMainWindow ctor?
-
@Charlie_Hdz said in Terminating a application:
What do you mean with the app qutting inside QMainWindow ctor?
Default GUI project main.cpp:
int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; // <- exit call inside counstructor w.show(); return a.exec(); }
-
Does the main window contains/has the message box? Have you tried using a connect() in the constructor where the signal is the message box cancel button clicked? To do this, the Message box should inherits from QObject. Is it?
For example, in one of my projects I called a function onBackClicked() which encapsulates all the exiting procedure to all Main Window.
connect(m_pBackButton,SIGNAL(clicked()),this,SLOT(onBackClicked()));
Please let me know if this work for you.
Thank you
-
@Charlie_Hdz said in Terminating a application:
Does the main window contains/has the message box?
It is irrelevant to the OP's question.
Have you tried using a connect() in the constructor where the signal is the message box cancel button clicked?
Yes, it works. Why shouldn't it?
To do this, the Message box should inherits from QObject. Is it?
QMessageBox inherits (indirectly) QObject.
connect(m_pBackButton,SIGNAL(clicked()),this,SLOT(onBackClicked()));
Looks normal to me.
-
I did see that, but it did not work where i try to call it (i probably do not understand how this work). I'm in a class called by the main window. Also i'm using a message box to present to the user, I can check if QMessageBox::Cancel was pressed.
Here is the code where im trying to do this, maybe it helps:DataBase::DataBase(QObject *parent) : QObject(parent) { m_db = QSqlDatabase::addDatabase("QSQLITE"); m_db.setDatabaseName("analysisData"); if(QFile::exists("analysisData")==true) m_db.open(); else { QMessageBox fileBox; fileBox.setText("Database Doesn't Exist"); fileBox.setInformativeText("Could not find the database. \n OK to create a new one, Cancel to exit without creating "); fileBox.setStandardButtons(QMessageBox::Ok|QMessageBox::Cancel); fileBox.setDefaultButton(QMessageBox::Ok); int action = fileBox.exec(); if(action == QMessageBox::Cancel); else { m_db.open(); createDatabase(); } } }
Don't call
::exit
, unless this is the last and only way to close an application. It will terminate the app directly, and destructors won't be called, possibly causing resources to be left hanging.::exit
is there for you to terminate if you're handlingSIGSEGV
or some other obscurity that shouldn't happen to begin with.What you should do is to move your database code out of the constructor, it's not the right place for it. Create a separate initialization method and schedule a delayed call through the event loop, then emit a signal if you want the GUI to show, or just call
QCoreApplication::quit
if you don't. It'd look something like this:class DataBase : public QObject { Q_OBJECT public: DataBase(QObject *parent) : QObject(parent) { // This is fine to stay here, no real operations are done with the DB m_db = QSqlDatabase::addDatabase("QSQLITE"); m_db.setDatabaseName("analysisData"); // Schedule your init routine QTimer::singleShot(0, std::bind(&DataBase::initDatabase, this)); } private: void initDatabase() { if (QFile::exists("analysisData") == true) m_db.open(); //< Do check the return value else { // ... if (fileBox.exec() == QMessageBox::Cancel) { emit canceled(); return; } else { // ... } } emit ready(); } signals: void ready(); void canceled(); };
Then you can hook it up like this:
MainWindow::MainWindow() : QMainWindow(), m_db(new DataBase(this)) // < Assuming a member m_db of type DataBase * { QObject::connect(m_db, &DataBase::ready, this, &MainWindow::show); QObject::connect(m_db, &DataBase::canceled, QCoreApplication::instance(), &QCoreApplication::quit); //< This can also be done in main }
And
main()
is simply done by creating the window object and spinning the event loop:int main(int argc, char ** argv) { QApplication app(argc, argv): MainWindow window; return QApplication::exec(); }
No
::exit
and a clean shutdown! -
This is probably a very basic question, but how do you close the application from somewhere else than the main window?
I'm working on an application that checks for the existence of a file at startup, then i have a message box that ask the user if he/she continues will create a new database. If he/she presses cancel i what to terminate the program right there.That's good info, that exit() leaves memory leaks. The stuff with connect is cute, but a simpler method is to add a public member to yer MainWindow:
int returnCode=0;
Then, write yer main() like this:
QApplication a(argc, argv); MainWindow w; if (!w.returnCode) { w.showMaximized(); return a.exec(); } else return w.returnCode;
Then, if you need to error out of the ctor, just do something like:
if (someCond) returnCode=2;
It's faster, too.
-
That's good info, that exit() leaves memory leaks. The stuff with connect is cute, but a simpler method is to add a public member to yer MainWindow:
int returnCode=0;
Then, write yer main() like this:
QApplication a(argc, argv); MainWindow w; if (!w.returnCode) { w.showMaximized(); return a.exec(); } else return w.returnCode;
Then, if you need to error out of the ctor, just do something like:
if (someCond) returnCode=2;
It's faster, too.
@Morbius said in Terminating a application:
That's good info, that exit() leaves memory leaks.
std::exit doesn't invoke destructors for non-static, non-thread-local objects. Private memory is still freed by process termination in most if not all modern operating systems. Otherwise, a program crashing would also leak.
The stuff with connect is cute, but a simpler method is to add a public member to yer MainWindow:
[...]This creates a situation where code needs to either be aware of whether the event loop has started, or use this variable and QCoreApplication::quit.
https://doc.qt.io/qt-6/qcoreapplication.html#quit provides instructions for signaling the event loop to terminate whether or not it has already started:
It's good practice to always connect signals to this slot using a QueuedConnection. If a signal connected (non-queued) to this slot is emitted before control enters the main event loop (such as before "int main" calls exec()), the slot has no effect and the application never exits. Using a queued connection ensures that the slot will not be invoked until after control enters the main event loop.