Terminating a application



  • 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.


  • Moderators

    @Dan3460

    There is an example for a controlled closing with quit of your app. This gives you the chance in other areas close things, if required.



  • 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();
            }
        }
    
    }
    


  • use qApp->quit():

    if(action == QMessageBox::Cancel)
         qApp->quit();
    

    don't forget to include QApplication.h



  • Thanks. Did not work. I think the problem is that this call to the database is done in the constructor of the main window, before the mainwindo.exec() is called. The way that i had the function call addDatabase if the file is not there nothing happens you are sent to the main window. With qApp->quit() happens the same thing. I don't want the main window showing.



  • Ah, yes, that won't work.
    exit(1) should do the job.


  • Moderators

    @taedium

    Calling exit is basically pulling the power plug and killing the application. That is certainly a way, but not always desirable.

    @Dan3460

    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();
    }
    


  • @taedium

    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.


  • Qt Champions 2016

    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 handling SIGSEGV 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!


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.