【发布时间】:2018-03-29 17:45:12
【问题描述】:
简介
嗨。在我的应用程序中,我在 MainWindow 的构造函数完成之前运行了一个 QDialog。根据此 QDialog 中的用户输入,我想关闭应用程序。
问题
我无法调用qApp->quit() 或qApp->exit(int retcode = 0),因为QApplication 事件循环尚未开始。有没有办法可以强制 MainWindow 退出?或者等到它完全加载后再退出?
解决方案?
我设法让它工作,但我不知道为什么。这是目前我的 QDialog 的 .cpp:
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);
}
使用QTimer::singleShot(0, qApp, &QCoreApplication::quit)、QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection)、qApp->quit() 或qApp->exit(1) 什么也没做。
但是,出于某种原因,使用(qApp->quit() 或 qApp->exit(1))和(QTimer::singleShot(0, qApp, &QCoreApplication::quit) 或 QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection))有效!
我觉得使用此解决方案可能会在以后再次咬我,因为我不知道它是如何工作的。有没有人有更好的解决方案或解释?
编辑
单独致电QTimer::singleShot(0, qApp, &QCoreApplication::quit) 并不会为我关闭应用程序。虽然,我第二次通过该函数时,它确实关闭了。 QTimer::singleShot() 是重新实现的 QDialog::reject 方法。而且,在关闭之前,我会显示一个QMessageBox。任何这些都会干扰QTimer?
编辑 2
我运行了示例 @user3606329 显示。它确实有效。我又走了几步,并在这个程序中使用了另一个程序中的QDialog。它确实没有用。所以问题出在我的QDialog 上?下面是整个reject 方法:
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);
}
}
编辑 3
我决定创建另一个QDialog 并且仅使用QTimer::singleShot 重新实现拒绝方法。它仍然没有工作。第一次调用拒绝,它通过QTimer::singleShot 并且什么也没做(甚至没有关闭对话框)。第二次,它关闭了对话框并关闭了应用程序。任何想法为什么? (代码如下)
主窗口.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
主窗口.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();
}
输出:
QTimer done //first click on "close window"
Event loop started //first click on "close window"
QTimer done //second click on "close window"
【问题讨论】:
-
@andseg 您在 3 中编辑的代码按预期工作。如果
QTimer未执行,对话框将保持打开状态,因此您在重新实现reject()时通常调用this->reject或this->accept。无论如何,我可以确认它在没有reject和accept的情况下可以工作。尝试在QTimer下添加return;或accept()或reject()。您的代码没有错误,我的回答中必须参考我之前的简历。 -
调用
accept()有效,但会改变exec()的返回。调用return;什么都不做。最后,调用reject()创建一个循环并中断代码。我将使用done()或close()进行测试。 -
@andseg
conf->exec() should block主事件循环,直到对话框关闭。conf->show()应该立即关闭,因为主事件循环没有被阻塞并且可以接收到quit() -
对不起,
accept()不会改变exec()的返回值。但它们不应该是不同类型的回报吗? -
@user3606329 是的,我考虑过使用
show()。但我想阻止所有交互,直到 conf 窗口得到解决。使用conf->show(),用户可以最小化窗口而不做重要的设置。