【问题标题】:Qt - Closing the program from a QDialog (Before MainWindow fully loaded)Qt - 从 QDialog 关闭程序(在 MainWindow 完全加载之前)
【发布时间】: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, &amp;QCoreApplication::quit)QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection)qApp-&gt;quit()qApp-&gt;exit(1) 什么也没做。

但是,出于某种原因,使用(qApp-&gt;quit()qApp-&gt;exit(1))和(QTimer::singleShot(0, qApp, &amp;QCoreApplication::quit)QMetaObject::invokeMethod(qApp, "quit", Qt::QueuedConnection))有效!

我觉得使用此解决方案可能会在以后再次咬我,因为我不知道它是如何工作的。有没有人有更好的解决方案或解释?

编辑

单独致电QTimer::singleShot(0, qApp, &amp;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-&gt;rejectthis-&gt;accept。无论如何,我可以确认它在没有rejectaccept 的情况下可以工作。尝试在QTimer 下添加return;accept()reject()。您的代码没有错误,我的回答中必须参考我之前的简历。
  • 调用accept() 有效,但会改变exec() 的返回。调用 return; 什么都不做。最后,调用reject() 创建一个循环并中断代码。我将使用done()close() 进行测试。
  • @andseg conf-&gt;exec() should block 主事件循环,直到对话框关闭。 conf-&gt;show() 应该立即关闭,因为主事件循环没有被阻塞并且可以接收到 quit()
  • 对不起,accept() 不会改变exec() 的返回值。但它们不应该是不同类型的回报吗?
  • @user3606329 是的,我考虑过使用show()。但我想阻止所有交互,直到 conf 窗口得到解决。使用conf-&gt;show(),用户可以最小化窗口而不做重要的设置。

标签: c++ qt


【解决方案1】:
#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);
        }
    }
}

【讨论】:

  • 别抱歉。覆盖 showEvent 也是一种可能的解决方案。
  • 我支持你,虽然我不会使用你的解决方案:)(太复杂了恕我直言)。
【解决方案2】:

以下代码

QTimer::singleShot(0, qApp, &QCoreApplication::quit) 

将排队quit() 并在事件循环启动时执行它。没有其他要求。你可以看看这个小例子:

#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
}

在事件循环开始之前运行以下代码

qApp->quit() or qApp->exit(1) 

不会对您的应用程序产生任何影响。

简历

您似乎没有在编辑器中正确放置代码,或者您遗漏了问题中的重要部分。我建议您使用我上面的代码示例创建一个简单的应用程序。

【讨论】:

  • 也许你是对的,我在我的代码中搞砸了一些东西。我将在问题中进行编辑
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-10
  • 1970-01-01
相关资源
最近更新 更多