0

信号がありQApplication::lastWindowClosed()ます。Qtのドキュメントには次のように書かれています:

This signal is emitted from QApplication::exec()
when the last visible primary window [...] is closed.

ただし、ループQApplication::processEvents()の代わりに使用しました。QApplication::exec()この最小限の例を参照してください。(名前を付けて保存しqapp.h、 で終了し.h、 で実行する必要がありますqmake -project && qmake && make)

#include <QApplication>
#include <QDebug>
#include <QObject>
#include <QMainWindow>

int exitprogram = 0;

class MyMainWindow : public QMainWindow
{
    Q_OBJECT
public slots:
    void request_exit() {
        qDebug() << "exit requested";
        exitprogram = 1;
    }
};

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    MyMainWindow w;
    QObject::connect(&app, SIGNAL(lastWindowClosed()),
        &w, SLOT(request_exit()));
    w.show();
    while(!exitprogram)
    {
        app.processEvents(QEventLoop::AllEvents, 20);
    }
}

最後のそのようなウィンドウが閉じられているかどうかを確認したり、信号を取得したりする良い方法はまだありますか?

4

2 に答える 2

3

processEventsの代わりに使用する理由が何であれ、exec間違っています。2つは同等ではありません。exec()たとえば、遅延削除イベントを処理しますが、処理しprocessEventsません。ご覧のとおり、lastWindowClosed信号も送信されません。これは、あなたが間違っていることをすぐに伝えているはずです。

イベントループが別の反復に進むたびに何かを行う慣用的なQtの方法は、ゼロタイムアウトタイマーを使用することです。これらは、オペレーティング システムのリソースを使用しない仮想タイマーであり、Qt の内部構造です。

以下の例は、次のことを示しています。

  1. 内でのゼロ タイムアウト タイマーの使用QObject

  2. State Machine Frameworkを使用してアプリケーションの状態を管理します。次の 3 つの状態があります。

    • sWindowsアプリケーション ウィンドウがまだ表示されている状態です。アプリケーションは、最後のウィンドウが閉じられても終了しないように設定されています。

    • sSetup最後のウィンドウが閉じられたときの状態です。この状態でObject、ゼロタイムアウトタイマーを実行した回数で通知信号を送信するように依頼します。messageこれにより、ラベル (C++11 コード) またはcountラベル (レガシー コード)に適切なカウントが設定されます。ステート マシンは自動的に次の状態に遷移します。

    • sMessageメッセージ ラベルが表示され、最後のウィンドウが閉じられるとアプリケーションが終了するように設定されている状態です。

ステート マシンを使用すると、宣言型コードになります。すべての動作を実装することなく、ステート マシンに動作方法を指示します。アプリケーションに固有で、まだ Qt によって提供されていない動作のみを実装する必要があります。ステート マシンが管理するオブジェクトは非常に分離することができ、マシンの動作を宣言するコードはまとまりがあり、分散するのではなく、すべてを 1 つの関数にすることができます。これは優れたソフトウェア設計と見なされます。

ゼロ タイムアウト タイマーは非常に勤勉であることに注意してください。これにより、イベント ループが空の場合は常にハンドラー コードが強制的に実行されます。これにより、GUI スレッドがたまたま実行されているコアで 100% の CPU 消費が強制されます。何もすることがない場合はstop()、タイマーを使用する必要があります。

Qt 5 C++11 コード

// https://github.com/KubaO/stackoverflown/tree/master/questions/close-process-19343325
#include <QtWidgets>

int main(int argc, char** argv)
{
    QApplication app{argc, argv};
    QLabel widget{"Close me :)"};
    QLabel message{"Last window was closed"};

    int counter = 0;
    auto worker = [&]{
       counter++;
    };
    QTimer workerTimer;
    QObject::connect(&workerTimer, &QTimer::timeout, worker);
    workerTimer.start(0);

    QStateMachine machine;
    QState sWindows{&machine};
    QState sSetup  {&machine};
    QState sMessage{&machine};

    sWindows.assignProperty(qApp, "quitOnLastWindowClosed", false);
    sWindows.addTransition(qApp, &QGuiApplication::lastWindowClosed, &sSetup);

    QObject::connect(&sSetup, &QState::entered, [&]{
       workerTimer.stop();
       message.setText(QString("Last window was closed. Count was %1.").arg(counter));
    });
    sSetup.addTransition(&sMessage);

    sMessage.assignProperty(&message, "visible", true);
    sMessage.assignProperty(qApp, "quitOnLastWindowClosed", true);

    machine.setInitialState(&sWindows);
    machine.start();
    widget.show();
    return app.exec();
}

Qt 4/5 C++11 コード

#include <QApplication>
#include <QLabel>
#include <QStateMachine>
#include <QBasicTimer>

class Object : public QObject {
    Q_OBJECT
    QBasicTimer m_timer;
    int m_counter = 0;
protected:
    void timerEvent(QTimerEvent * ev) {
        if (ev->timerId() == m_timer.timerId())
            m_counter ++;
    }
public:
    Object(QObject * parent = 0) : QObject{parent} {
        m_timer.start(0, this);
    }
    Q_SLOT void stop() const {
      m_timer.stop();
      emit countedTo(m_counter);
    }
    Q_SIGNAL void countedTo(int) const;
};

int main(int argc, char** argv)
{
    QApplication app{argc, argv};
    Object object;
    QLabel widget{"Close me :)"};
    QLabel message{"Last window was closed"};
    QLabel count;

    QStateMachine machine;
    QState sWindows{&machine};
    QState sSetup{&machine};
    QState sMessage{&machine};

    sWindows.assignProperty(qApp, "quitOnLastWindowClosed", false);
    sWindows.addTransition(qApp, "lastWindowClosed()", &sSetup);

    object.connect(&sSetup, SIGNAL(entered()), SLOT(stop()));
    count.connect(&object, SIGNAL(countedTo(int)), SLOT(setNum(int)));
    sSetup.addTransition(&sMessage);

    sMessage.assignProperty(&message, "visible", true);
    sMessage.assignProperty(&count, "visible", true);
    sMessage.assignProperty(qApp, "quitOnLastWindowClosed", true);

    machine.setInitialState(&sWindows);
    machine.start();
    widget.show();
    return app.exec();
}

#include "main.moc"
于 2013-10-13T15:22:52.893 に答える