QApplication :: exec()を呼び出さずにウィジェットを表示する正しい方法は何ですか?

Nov 20 2020

テスト目的で、ウィジェットを作成して表示したいと思います。今のところ、正しくレンダリングするためにウィジェットが必要なだけですが、将来的にはこれを拡張して、ウィジェットがどのように動作するかを確認するためにさまざまなイベントをシミュレートしたいと思うかもしれません。

さまざまな情報源から、次のことが機能するはずです。

QApplication app;

QPushButton button("Hello");
button.show();

// Might also be necessary:
QApplication::processEvents();

しかし、私にとってはウィジェットは正しくレンダリングされません。ウィジェットを表示するためのウィンドウが作成されますが、完全に黒です。

次の行を追加することで、ウィジェットを正しくレンダリングできます。

std::this_thread::sleep_for(std::chrono::milliseconds(10));
QApplication::processEvents();

10ミリ秒は、ウィジェットを正しくレンダリングするために必要な最短時間です。

誰かがこれを時間遅延なしで機能させる方法を知っていますか、または遅延が必要な理由を知っていますか?

回答

4 pptaszni Nov 20 2020 at 17:13

Qt GUIアプリケーションをテストするには、少なくともQApplicationインスタンスとイベントループが処理されている必要があります。最速の方法はQTEST_MAINマクロを使用することです。この回答は、マクロが正確に何をするかをわかりやすく説明しています。ただし、柔軟性を高めるために(GTest、GMockを使用するなど)QAplication、テストメインでインスタンスを作成することもできます(呼び出す必要はありませんexec)。

次に、イベントを処理するには、QTest :: qWaitを呼び出す必要があります。これにより、指定された時間、イベントが処理されます。qWaitFor述語を受け入れるものを使用することをお勧めします。これにより、テストで競合状態を回避できます。

特定のシナリオでは、何らかの信号が発信されると予想される場合、QSignalSpy :: waitの同様の機能を使用することもできます。

一部のパラメーターが1つのアイテムから別のアイテムに渡されるまで待機する場合の小さな例:

QSignalSpy spy(&widget1, &Widget1::settingsChanged);
widget2->applySettings();
ASSERT_TRUE(spy.wait(5000));
// do some further tests based on the content of passed settings
1 VincentFourmond Nov 20 2020 at 16:39

アプリケーションにexecを実行させたくないのはなぜですか?ウィジェットを表示するプロセスは「静的」ではありません。画面上にウィジェットを「描画」するのではなく、さまざまなイベントをリッスンし、ウィンドウマネージャーから描画イベントを受信するアプリケーションがあります。アプリケーションは、ウィンドウマネージャーがウィジェットを要求した場合にのみウィジェットを描画できます。

2番目のコードが機能する理由は、ウィンドウマネージャーが条件内で「描画」要求を送信するのを十分に長く待つためです。これは、常に機能することを保証するものではありません。

ウィジェットの表示を保証したい場合は、ループを開始して、少なくとも1つの描画イベントを受信するまで待つ必要がありますが、それでも絶対確実ではありません。

ypnos Nov 20 2020 at 16:58

Vincent Fourmondが専門的に説明しているように、ウィジェットは1回限りの取引ではありません。GUIは非ブロッキングであり、このためには、イベントループで実行する必要があります

このexec()メソッドは、ポーリングによって模倣したこのイベントループを開始します。Qtのイベントループを他のイベントループと組み合わせることができますが、より簡単な解決策をお勧めします。

プログラムの開始時にメソッドを呼び出して、イベントループ内でプログラムを続行します。これを行う方法については、ここで優れた答えを見つけてください。https://stackoverflow.com/a/8877968/21974

ユニットテストについて述べたように、ライフサイクルの最後(ウィジェットが破棄される前)にチェックを実行するために使用できるシグナルもありますQApplication::aboutToQuit。これは、最後のウィンドウが閉じられたときに発生します(プログラムまたはユーザーによって)。