21

ウィジェットがペイント イベントを受け取るのはどのような場合で、OS によってどのように変化するのか疑問に思っています。

paintEvent の Qt ドキュメントには、次のように書かれています

ペイント イベントは、ウィジェットのすべてまたは一部を再描画する要求です。これは、次のいずれかの理由で発生する可能性があります。

repaint() または update() が呼び出された、

ウィジェットが隠されていましたが、今では明らかになりました。または

他の多くの理由。

これまでのところ、paintEvent にいくつかのトレースを入れましたが、

void Widget::paintEvent(QPaintEvent *e)
{
    static int count = 0;
    qDebug("paintEvent, %d", count++);
}

これが私が見つけたものです(少なくともWindows 7では):

paintEvent は、ウィジェットがフォーカスを失った/獲得したときに呼び出されます。別のウィジェットがウィジェットを通過するとき、ペイント イベントは呼び出されません。Windows 7 の合成が原因かどうかはわかりません。paintEvent は、最小化されたウィンドウが復元されたときにも呼び出されます。サイズ変更時に paintEvent が呼び出されます。

動作はOSに依存していますか?

4

1 に答える 1

21

はい、あなたが説明した意味で、それはオペレーティングシステムに依存しています。

Windows Vista および 7 にあるデスクトップ ウィンドウ マネージャー (DWM) は、デスクトップの構成、Aero ガラス効果、およびその他のあらゆる種類のアイ キャンデーを担当する doohickey であり、以前のバージョンの Windows で使用されていたモデルとは少し異なる動作をします。 . ご想像のとおり、別のウィンドウに隠れて表示されていない場合でも、ウィンドウのビットマップがキャッシュされます。つまり、キャッシュされたビットマップからそれらをブリットできるため、それらを再描画する必要はありません (したがって、ペイント イベントは発生しません)。これは、各アプリケーション自体を再描画するよりも潜在的に最適化されるだけでなく、DWM がキャッシュされたビットマップを使用する Aero フリップなどを実装できるようにもなります。

これに対する例外は、たとえばCS_SAVEBITSクラス スタイルの場合と同様です。DWM がキャッシュしたビットマップが無効になった場合 (ウィンドウ イメージが変更されたなど)、ビットマップは破棄され、ウィンドウを再描画するように求められます。

この理論をテストするには、DWM コンポジションをオフにし (「Windows クラシック」テーマに切り替えます)、ウィンドウを覆い隠して、ペイント イベントを受け取るかどうかを確認します。以前のすべてのバージョンの Windows で行ったのと同じように、そうする必要があります。

しかし、より重要な点は、ペイント イベントを特定の順序で受け取ることに依存してはならないということです。ペイント イベントについて想定すべき唯一のことは、オペレーティング システムがウィンドウを再描画する必要があるときに受け取るということです。そうでなければ、それはあなたを悩ませません。技術的な制約の可能性を超えて、ドキュメントがこの点について曖昧であることに満足しているのはそのためだと思います。

これが、ペイント イベント ハンドラー内にロジックを入れるべきではない理由です。そのメソッドが担当する唯一のことは、現在の状態でウィンドウを再描画することです。その状態は別の場所に保存する必要があります。このルールも交換可能です。ペイント イベント ハンドラのでペイントを行うべきではありません。

もちろん、ウィンドウを無効にすることでいつでも強制的にペイント イベントを発生させることができます (Qt にはこのためのinvalidateorrefreshメソッドがあると確信しています。ドキュメントを確認してください)。このイベントを処理するメソッドで。

于 2012-07-25T08:49:02.453 に答える