1

My example:

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
    }

At comment place, I tried to do: qApp->exit() and qApp->quit() and this->close() (but 'this' not shown and of cource close() is not working). How can I finish app from any place of code?


Whole code:
main.cpp

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

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.start();

    return a.exec();
}


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


mainwindow.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);
}

And ConnectionForm - it's just a QDialog with some GUI and without any additional code.

László Papp
  • 51,870
  • 39
  • 111
  • 135
Maksim Nesterenko
  • 5,661
  • 11
  • 57
  • 91

3 Answers3

2

It looks like the problem is you're not allowed to call QApplication::quit() or QApplication::exit() until the QApplication event loop has actually started. The event loop gets started by QApplication::exec(), so you're calling quit()/exit() too soon for it to have an effect.

You can fix this either by moving the quit()/exit() call so that it's in the event loop (e.g. by moving your MainWindow::start() code to the QMainWindow::showEvent() slot), or by changing your MainWindow::start() to return a value, inspect that value in main, and exit (without calling QApplication::exec()`) if it's a value that indicates your process should exit early.

nobody
  • 19,814
  • 17
  • 56
  • 77
1

Since you start the dialog event loop "early" - which is blocking -, you do not get to the event loop of the application.

If this is an intentional design, you better call exit(3) and remove the application event loop.

If you want to have the application event loop running, then you will need to make sure that it runs before you get to the point of your dialog execution.

The quick fix would be to start a single shot QTimer right just before the application event loop is started and that would trigger your "start" method call.

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.start();
    QTimer::singleShot(200, w, SLOT(start()));
    return a.exec();
}

and change the start to a slot, respectively.

In the long run, you may wish to consider a button and so on for bringing your dialog up, however.

László Papp
  • 51,870
  • 39
  • 111
  • 135
  • Thanks for your answers to all my questions ) – Maksim Nesterenko Apr 07 '14 at 02:02
  • There's no reason to use a non-zero valued timer, since the `start` call should be executed as soon as the event loop starts. Note then that a zero-duration single shot timer is just a weird way of referring to a queued metacall. So, the intent is most clear by doing just that: `QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection)`. – Kuba hasn't forgotten Monica Apr 07 '14 at 13:06
  • @KubaOber: the value is right from the documentation, and as written it is a quick workaround. In fact, none of this would be necessary with a good design as written. invokeMethod or timer... both are ugly, but pragmatic workarounds with a TODO item noted. :-) – László Papp Apr 07 '14 at 13:52
  • "the value is right from the documentation" It's just an example of how one might use a timer in general, it doesn't mean anyone in particular should write code that looks like it. It's like with the average value (population mean): just because you can calculate the mean doesn't mean that it is a value that exists in the population. – Kuba hasn't forgotten Monica Apr 07 '14 at 14:25
  • @KubaOber: I do not think it is worth arguing which workaround is uglier. I would concentrate on the main design issue. The ugly workarounds are just tangential to me, really, and something I would not ever use: correct, not even invokeMethod. Moreover, if you do not pick up the right connection type, it will not work properly with invokeMethod, etc. I would suggest to put more effort into the actual important stuff. – László Papp Apr 07 '14 at 14:31
  • In general, it is not good user experience to launch an application with a dialog. There are cases where it makes sense, but IMHO, it is the minority. I would reconsider whether that is a good decision if I were the OP. Without more details, however, I cannot tell more. It is also questionable whether you need an application event loop at all when you only have one dialog and that is the only thing that is expected to block, especially if you quit the dialog, or ... even ... having a dialog for this might be suboptimal altogether. These are more important questions to me here to consider. – László Papp Apr 07 '14 at 14:38
  • @LaszloPapp, my app is purely for training purposes. The first thing that makes the app - connects to the database. I decided to use a separate dialog for that. Is this bad? – Maksim Nesterenko Apr 08 '14 at 03:54
1

The idiomatic way of queuing a method call until the event loop gets a chance to run is:

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

Thus, your main would become:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    QMetaObject::invokeMethod(&w, "start", Qt::QueuedConnection);
    return a.exec();
}
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313