如何从任何地方完成 Qt 程序?

Posted

技术标签:

【中文标题】如何从任何地方完成 Qt 程序?【英文标题】:How to finish Qt programm from any place? 【发布时间】:2014-04-07 01:12:47 【问题描述】:

我的例子:

main.cpp:
    QApplication a(argc, argv);
    MainWindow w;
    w.start();
    return a.exec();

w.start():
    if (cf.exec())
        this->show();
     else 
        qDebug()<<"Need exit";
        //here should be exit
    

在评论处,我尝试这样做:qApp->exit() 和 qApp->quit() 和 this->close() (但“this”未显示,并且当然 close() 不起作用)。如何从任何代码位置完成应用程序?

完整代码: main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.start();

    return a.exec();

主窗口.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "CadrForm.h"
#include "TeacherForm.h"
#include "DepartmentForm.h"
#include "CategoriesForm.h"
#include "PostForm.h"
#include "RanksAndDegreesForm.h"
#include "TeachersRankAndDegreeForm.h"
#include "ConnectionForm.h"

namespace Ui 
class MainWindow;


class MainWindow : public QMainWindow

    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    void start();
    ~MainWindow();
signals:
    void widgetChanged(QWidget*);
private slots:
    void on_actionCadr_triggered();
    void resetMainLayout(QWidget* w);
    void on_actionTeacher_triggered();

    void on_actionDepartment_triggered();

    void on_actionPost_triggered();

    void on_actionCategories_triggered();

    void on_actionRanksAndDegrees_triggered();

    void on_actionTeachersRD_triggered();

private:
    ConnectionForm cf;
    CadrForm *cadrForm;
    TeacherForm *teacherForm;
    DepartmentForm *departmentForm;
    CategoriesForm *categoriesForm;
    PostForm *postForm;
    RanksAndDegreesForm *ranksAndDegreesForm;
    TeachersRankAndDegreeForm *teachersRankAndDegreeForm;
    QWidget *current;
    Ui::MainWindow *ui;

    void addWidgetToMainLayout(QWidget *w);
;

#endif // MAINWINDOW_H

主窗口.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)

    connect(this, SIGNAL(widgetChanged(QWidget*)), this, SLOT(resetMainLayout(QWidget*)));

    ui->setupUi(this);
    cadrForm = new CadrForm(this);
    teacherForm = new TeacherForm(this);
    departmentForm = new DepartmentForm(this);
    categoriesForm = new CategoriesForm(this);
    postForm = new PostForm(this);
    ranksAndDegreesForm = new RanksAndDegreesForm(this);
    teachersRankAndDegreeForm = new TeachersRankAndDegreeForm(this);

    addWidgetToMainLayout(cadrForm);
    addWidgetToMainLayout(teacherForm);
    addWidgetToMainLayout(departmentForm);
    addWidgetToMainLayout(categoriesForm);
    addWidgetToMainLayout(postForm);
    addWidgetToMainLayout(ranksAndDegreesForm);
    addWidgetToMainLayout(teachersRankAndDegreeForm);


void MainWindow::start()

    if (cf.exec())
        this->show();
     else 
        qDebug()<<"Need exit";
        qApp->quit();
        qDebug()<<"still working";
    


void MainWindow::addWidgetToMainLayout(QWidget *w)

    ui->mainLayout->insertWidget(0, w);
    ui->mainLayout->itemAt(0)->widget()->hide();


MainWindow::~MainWindow()

    delete ui;


void MainWindow::resetMainLayout(QWidget *w)

    int index;
    if (current)
    
        index = ui->mainLayout->indexOf(current);
        ui->mainLayout->itemAt(index)->widget()->hide();
    
    index = ui->mainLayout->indexOf(w);
    if (index != -1) ui->mainLayout->itemAt(index)->widget()->show();
    else 
        addWidgetToMainLayout(w);
        resetMainLayout(w);
    
    current = w;
    setWindowTitle(current->windowTitle());


void MainWindow::on_actionCadr_triggered()

    emit widgetChanged(cadrForm);


void MainWindow::on_actionTeacher_triggered()

    emit widgetChanged(teacherForm);


void MainWindow::on_actionDepartment_triggered()

    emit widgetChanged(departmentForm);


void MainWindow::on_actionPost_triggered()

    emit widgetChanged(postForm);


void MainWindow::on_actionCategories_triggered()

    emit widgetChanged(categoriesForm);


void MainWindow::on_actionRanksAndDegrees_triggered()

    emit widgetChanged(ranksAndDegreesForm);


void MainWindow::on_actionTeachersRD_triggered()

    emit widgetChanged(teachersRankAndDegreeForm);

还有 ConnectionForm - 它只是一个带有一些 GUI 且没有任何额外代码的 QDialog。

【问题讨论】:

什么是cf?您是否至少打印了“需要退出”? qApp-&gt;exit()qApp-&gt;quit() 应该可以工作。当你尝试这些时究竟发生了什么? @AndrewMedico,应用程序仍在运行。根据上面的代码,我有这个 qDebug 输出:调用 aApp-quit() 后“需要退出”和“仍在工作” @LaszloPapp,shure,我收到消息“需要退出”。 cf 它的我的 QDialog 没有任何特定的逻辑。 我不关注。 cf.exec() 是一个阻塞调用,所以很明显你没有得到 else 分支,但是为什么你会得到打印呢?您是否明确关闭对话框,然后您希望应用退出? 【参考方案1】:

看起来问题是在 QApplication 事件循环实际开始之前,不允许您调用 QApplication::quit()QApplication::exit()。事件循环由QApplication::exec() 启动,所以你调用quit()/exit() 太快了,它不会生效。

您可以通过移动 quit()/exit() 调用使其处于事件循环中来解决此问题(例如,通过将您的 MainWindow::start() 代码移动到 QMainWindow::showEvent() 插槽),或者通过更改您的 MainWindow::start()要返回一个值,请检查 main 中的该值,如果该值指示您的进程应提前退出,则退出(不调用 QApplication::exec()`)。

【讨论】:

好吧,让它成为你的。谢谢大家。 第一段是正确的。第二段提供了一种处理问题的相当复杂的方法。执行此操作的惯用方法是通过QMetaObject::invokeMethod 对方法调用进行排队。就是这样。【参考方案2】:

由于您“提前”启动对话框事件循环(即阻塞),因此您无法进入应用程序的事件循环。

如果这是有意设计,您最好调用 exit(3) 并移除应用程序事件循环。

如果您想让应用程序事件循环运行,那么您需要确保它在您到达对话框执行点之前运行。

快速解决方法是在应用程序事件循环开始之前启动单次射击QTimer,这将触发您的“开始”方法调用。

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    w.start();
    QTimer::singleShot(200, w, SLOT(start()));
    return a.exec();

并将起点分别更改为插槽。

不过,从长远来看,您可能希望考虑使用按钮等来弹出对话框。

【讨论】:

感谢您对我所有问题的回答) 没有理由使用非零值计时器,因为应该在事件循环开始后立即执行start 调用。请注意,零持续时间单发计时器只是引用排队元调用的一种奇怪方式。所以,这样做的意图是最清楚的:QMetaObject::invokeMethod(&amp;w, "start", Qt::QueuedConnection). @KubaOber:该值来自文档,并且按照书面说明,它是一种快速解决方法。事实上,对于一个好的设计,这些都不是必需的。 invokeMethod 或 timer... 两者都很丑陋,但是带有 TODO 项的实用解决方法。 :-) "该值来自文档" 这只是一般如何使用计时器的一个示例,并不意味着特别是任何人都应该编写看起来像它的代码。这就像平均值(总体平均值):仅仅因为您可以计算平均值并不意味着它是存在于总体中的值。 @KubaOber:我认为不值得争论哪种解决方法更丑陋。我将专注于主要的设计问题。丑陋的解决方法对我来说只是切线,真的,我永远不会使用的东西:正确,甚至不是invokeMethod。此外,如果您没有选择正确的连接类型,它将无法与 invokeMethod 等一起正常工作。我建议您将更多的精力放在实际重要的东西上。【参考方案3】:

将方法调用排队直到事件循环有机会运行的惯用方式是:

QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);

因此,您的main 将变为:

int main(int argc, char *argv[])

    QApplication a(argc, argv);
    MainWindow w;
    QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
    return a.exec();

【讨论】:

以上是关于如何从任何地方完成 Qt 程序?的主要内容,如果未能解决你的问题,请参考以下文章

Qt:如何编写 Windows 桌面实用程序?

如何从任何地方要求一些 lib 文件

如何从任何地方获取上下文? [复制]

如何从android studio中的任何地方访问localhost数据库

如何使用VS2012调试QT程序

Delphi如何检测表单上任何地方的点击事件,包括其他组件