Qtのアイドルイベント

こんにちはハブラ



インパルス



少し前に、WindowsでQtを使い始めました。 私の仕事は、アニメーションやその他の機能を備えたユーザーインターフェイスのリアルタイムレンダリングを備えたグラフィカルアプリケーションを開発することです。 この美しさはすべてDirectXを介して機能し、Qtはアニメーション、ウィンドウ、信号、その他の便利な機能をサポートします。



なぜこれが必要なのですか?



誰かがゲームを開発している場合、「アプリケーションのダウンタイム」中に画面が再描画されることを知っています。つまり、 ウィンドウへのメッセージキューが空の瞬間。 これにより、ウィンドウを非常に迅速に再描画できます。特に空のウィンドウでは、毎秒数千フレーム(垂直同期を無効にした状態)で描画できます。



どうしてそんなに必要なかったの?


むかしむかしMFCで働いて、オーバーロードされる可能性のあるOnIdle()関数があることを思い出しました。 インターネットやソースコードで大騒ぎしていたので、Qtでも似たようなものは見つかりませんでした。 動作すると思われる唯一の解決策は、0 ms間隔で開始するタイマーを作成することです。 次のようになりました。

  1. クラス QMyWindow : パブリック QWidget
  2. {
  3. Q_OBJECT
  4. int m_idleTimerId ;
  5. 公開 :
  6. QMyWindow ( QObject * parent ) : QWidget ( parent ) : m_idleTimerId ( -1 )
  7. {
  8. m_idleTimerId = startTimer ( 0 ) ;
  9. }
  10. void timerEvent ( QTimerEvent * event )
  11. {
  12. if ( event- > timerId ( ) == m_idleTimerId )
  13. {
  14. //アイドル処理コードはここにあります...
  15. }
  16. }
  17. } ;


著者によると、タイマーメッセージは、空のメッセージキューがあるときにアクティブになります。 しかし問題は、これらの同じタイマーメッセージがキューを「詰まらせる」ため、QResizeEventでさえすぐにハンドラに到達しないことです。



解決策が見つかりました



予期せぬ解決策-WinAPIのウィンドウレンダリングスキームを使用します。

  1. while ( msg。message ! = WM_QUIT )
  2. {
  3. if ( PeekMessage ( & msg、 NULL 、0U、0U、PM_REMOVE ) )
  4. {
  5. TranslateMessage ( & msg ) ;
  6. DispatchMessage ( & msg ) ;
  7. }
  8. 他に
  9. レンダリング( ) ;
  10. }


このコードは、最初にPeekMessageからメッセージを取得し、次にメッセージを処理してウィンドウハンドラーに送信し、キューが空の場合は要素を描画することを示しています。 Qtでは、次のようになります。

  1. WinPlatform w ;
  2. MwApplication a ( & w、argc、argv、 true ) ;
  3. a。 installEventFilter ( & w ) ;
  4. a。 postEvent ( & w、 new FLoadingEvent ( ) 、Qt :: LowEventPriority ) ;
  5. while ( w。isRunning ( ) || QApplication :: hasPendingEvents ( ) )
  6. {
  7. // QApplication :: sendPostedEvents();
  8. if ( QApplication :: hasPendingEvents ( ) )
  9. QApplication :: processEvents ( ) ;
  10. 他に
  11. w。 renderObjects ( ) ;
  12. }


要するに、いくつかのポイント:

  1. QCloseEventタイプのメッセージのフィルターを設定するか、lastWindowClosedシグナルを使用して、ウィンドウが閉じている場合にw.isRunningがfalseを返すようにします
  2. キュー内にある限りメッセージを処理するか、オブジェクトを描画します


hasPendingEvents()がwhile条件にある理由について個別に説明することは価値があります。 実際には、ウィンドウが閉じられたときに、deleteLaterを呼び出すことで削除用のキューを置くことができ、eventLoopに戻るときに削除されます。 起こりうる問題を回避するには、キューを最後まで処理する必要があります。



また、おそらくsendPostedEvents()の呼び出しでコメントアウトされた行に気づいたでしょう。 ドキュメントには、このプロシージャを呼び出さないと、遅延削除(deleteLater)で問題が発生する可能性があると書かれていますが、アプリケーションではすべてが機能しているようです。



おわりに



もちろん、少し松葉杖ができましたが、それでも機能します。 ご清聴ありがとうございました!



All Articles