processEvents
の代わりに使用する理由が何であれ、exec
間違っています。2つは同等ではありません。exec()
たとえば、遅延削除イベントを処理しますが、処理しprocessEvents
ません。ご覧のとおり、lastWindowClosed
信号も送信されません。これは、あなたが間違っていることをすぐに伝えているはずです。
イベントループが別の反復に進むたびに何かを行う慣用的なQtの方法は、ゼロタイムアウトタイマーを使用することです。これらは、オペレーティング システムのリソースを使用しない仮想タイマーであり、Qt の内部構造です。
以下の例は、次のことを示しています。
内でのゼロ タイムアウト タイマーの使用QObject
。
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"