Reputation: 698
Hi. In my application, I run a QDialog before the constructor of the MainWindow finishes. Depending on the user input in this QDialog, I want to close the application.
I can't call qApp->quit()
or qApp->exit(int retcode = 0)
as the QApplication event loop haven't started. Is there a way I can force MainWindow to quit? Or maybe wait until it is fully loaded before quitting?
I managed to make it work but I have no idea why. This is the .cpp of my QDialog at the moment:
QFileInfo checkConfig(configPath);
if(!checkConfig.exists() || !checkConfig.isFile())
{
qDebug() << "Sair!";
qApp->quit();
//qApp->exit(1);
//QTimer::singleShot(0, qApp, &QCoreApplication::quit);
QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
}
Using QTimer::singleShot(0, qApp, &QCoreApplication::quit)
, QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection)
, qApp->quit()
or qApp->exit(1)
did nothing.
But, for some reason, using ( qApp->quit()
or qApp->exit(1)
) and ( QTimer::singleShot(0, qApp, &QCoreApplication::quit)
or QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection)
) works!
I feel that using this solution can come back to bite me in the ass later, since I don't know how it is working. Does anyone have a better solution or an explanation?
Calling QTimer::singleShot(0, qApp, &QCoreApplication::quit)
alone is not closing the application for me. Although, the second time I pass through the function, it does close. The QTimer::singleShot()
is on a re implemented QDialog::reject
method. And, before closing I show a QMessageBox
. Any of this can interfere with the QTimer
?
I ran the example @user3606329 show. It does indeed work. I went a few steps further and used my QDialog
from the other program in this one. And it indeed did not work. So the problem is in my QDialog
? Below is the entire reject
method:
void Configuracao::reject()
{
QFileInfo checkConfig(configPath);
if(!checkConfig.exists() || !checkConfig.isFile())
{
QMessageBox::critical(this,"Erro na configuração","Erro na criação do aquivo config.ini.\n"
"O programa será finalizado!");
qDebug() << "Sair!";
//qApp->quit();
//qApp->exit(1);
QTimer::singleShot(0, qApp, &QCoreApplication::quit);
//QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection);
}
}
I decided to create another QDialog
and ONLY re implement the reject method with QTimer::singleShot
. It still didn't work. The first time reject was called, it went through QTimer::singleShot
and did nothing (Not even closed the Dialog). The second time, it closed the dialog and closed the application. Any ideas why? (Code below)
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "dialog.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
Dialog *conf;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
conf = new Dialog(this);
conf->exec();
}
MainWindow::~MainWindow()
{
delete ui;
}
dialog.h:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
protected:
void reject();
};
#endif // DIALOG_H
dialog.cpp:
#include "dialog.h"
#include "ui_dialog.h"
#include <QTimer>
#include <QDebug>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::reject()
{
QTimer::singleShot(0, qApp, []() {
qDebug() << "QTimer done";
QCoreApplication::quit();
});
}
main.cpp:
#include "mainwindow.h"
#include <QApplication>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
qDebug() << "Event loop started";
return a.exec();
}
Output:
QTimer done //first click on "close window"
Event loop started //first click on "close window"
QTimer done //second click on "close window"
Upvotes: 1
Views: 1360
Reputation: 141
#include <QShowEvent>
#include <QDebug>
...
protected:
...
void showEvent(QShowEvent *event);
...
private:
...
bool init_check = false;
...
void MainWindow::showEvent(QShowEvent *event){
qDebug() << "QShowEvent" << init_check;
if(!init_check){
init_check = true;
bool err = true;
if(err){
qDebug() << "Closing app";
exit(EXIT_FAILURE);
}
}
}
Upvotes: 3
Reputation: 2534
The following code
QTimer::singleShot(0, qApp, &QCoreApplication::quit)
will queue quit() and execute it when the event loop is started. Nothing else is required. You can take a look at this small example:
#include "mainwindow.h"
#include <QApplication>
#include <QTimer>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QTimer::singleShot(0, qApp, []() {
qDebug() << "Event loop started";
QCoreApplication::quit();
});
return a.exec(); // QCoreApplication::quit() is executed after the call
}
Running the following code before the event loop starts
qApp->quit() or qApp->exit(1)
will not have any effect to your application.
Résumé
It appears that you have either not placed the the code correctly in your editor or you left out important parts in your question. I suggest you create a simple application with my above code example.
Upvotes: 2