21

C++/MFC アプリケーションで GDI+ を使用していますが、ウィンドウのサイズが変更されるたびにちらつきを避けることができないようです。

私はすでにこれらの手順を試しました:

  • で TRUE を返しましたOnEraseBkGnd()
  • で NULL を返しましたOnCtlColor()
  • このコードに従ってダブルバッファリングを使用しました:

void vwView::OnDraw(CDC* pDC) 
{
   CRect rcClient;
   GetClientRect(rcClient);

   Bitmap bmp(rcClient.Width(), rcClient.Height());
   Graphics graphics(&bmp);

   graphics.DrawImage(m_image, rcClient.left, rcClient.top);

   Graphics grph(pDC->m_hDC);
   grph.DrawImage(&bmp, 0, 0);
}

私は何か間違ったことをしていますか?または、これを達成する別の方法はありますか?

4

6 に答える 6

43

ちらつきを完全に回避するには、画面の更新の合間にすべての描画を完了する必要があります。Windowsは、通常のウィンドウペイントでこれを実現する簡単な手段を提供していません(VistaはDWMを介して複合描画を提供しますが、Vistaを実行しているシステムでもこれに依存することはできません)。したがって、ちらつきを最小限に抑えるためにできる最善の方法は、すべてをできるだけ早く描画し(更新サイクル内ですべての描画を完了する可能性を高めることでティアリングを減らす)、オーバードロー(画面の一部を描画してから他の何かを描画する)を回避することです。上:部分的に描画された画面をユーザーに提示するリスク)。

これまでにここで紹介したテクニックについて説明しましょう。

  • 何もしないOnEraseBkgnd():ウィンドウの無効な領域がウィンドウの背景色で塗りつぶされるのを防ぐことにより、過剰描画を回避するのに役立ちます。ダブルバッファ描画の場合のように、とにかくWM_PAINT処理中に領域全体を再度描画する場合に便利ですが、 WM_PAINTメソッドの後に描画を防止することでオーバードローを回避するための注意事項を参照してください。

  • OnCtlColor()に対してNULLを返す:これは実際には何もしないはずです...フォームに子コントロールがない限り。その場合は、代わりにWM_PAINTメソッドの後に描画を防止することでオーバードローを回避するための注意事項を参照してください。

  • ダブルバッファドローイング:実際の画面上のドローイングを単一のBitBLTに減らすことにより、ティアリング(および潜在的にオーバードローも)を回避するのに役立ちます。ただし、描画に必要な時間がかかる可能性があります。ハードウェアアクセラレーションは使用できません(ただし、GDI +では、ハードウェア支援描画が使用される可能性は非常に低くなります)。再描画ごとにオフスクリーンビットマップを作成して入力する必要があります。再描画するたびに、ウィンドウ全体を再描画する必要があります。効率的なダブルバッファリングに関する注意事項を参照してください。

  • BitBltにGDI+ではなくGDI呼び出しを使用する:これは多くの場合良い考えです-Graphics::DrawImage()非常に遅くなる可能性があります。一部のシステムでは、通常のGDIBitBlt()呼び出しの方が高速であることがわかりました。これを試してみてください。ただし、最初に他のいくつかの提案を試した後でのみです。

  • サイズ変更のたびに完全な再描画を強制するウィンドウクラススタイルの回避(CS_VREDRAWCS_HREDRAW :これは役立ちますが、サイズが変更されたときにウィンドウ全体を再描画する必要がない場合に限ります。

WM_PAINTメソッドの前に描画を防止することにより、オーバードローを回避するための注意事項

ウィンドウの全部または一部が無効になると、ウィンドウは消去されて再描画されます。すでに述べたように、無効な領域全体を再描画する場合は、消去をスキップできます。ただし、子ウィンドウを使用している場合は、親ウィンドウが画面の領域も消去していないことを確認する必要があります。WS_CLIPCHILDRENスタイルは、すべての親ウィンドウで設定する必要があります。これにより、子ウィンドウ(ビューを含む)が占める領域が描画されなくなります。

WM_PAINTメソッドの後に描画を防止することでオーバードローを回避するための注意事項

フォームで子コントロールをホストしている場合は、WS_CLIPCHILDRENスタイルを使用して、子コントロールが描画ないようにします(その後、子コントロールによって描画されすぎないようにします。これは、BitBltルーチンの速度に多少影響することに注意してください。

効率的なダブルバッファリングに関する注意

現在、ビューがそれ自体を描画するたびに、新しいバックバッファイメージを作成しています。より大きなウィンドウの場合、これは割り当てられて解放される大量のメモリを表す可能性があり、重大なパフォーマンスの問題が発生します。動的に割り当てられたビットマップをビューオブジェクトに保持し、必要に応じてビューのサイズに合わせて再割り当てすることをお勧めします。

ウィンドウのサイズが変更されている間、これは現在のシステムと同じ数の割り当てになることに注意してください。新しいサイズごとに、それに一致する新しいバックバッファビットマップを割り当てる必要があるためです。寸法を切り上げることで、多少の苦痛を和らげることができます。 4、8、16などの次に大きい倍数に変更し、サイズの小さな変更ごとに再割り当てを回避できるようにします。

最後にバックバッファにレンダリングしてからウィンドウのサイズが変更されていない場合は、ウィンドウが無効になったときにウィンドウを再レンダリングする必要はありません。レンダリング済みの画像を画面。

また、画面のビット深度に一致するビットマップを割り当てます。現在使用しているコンストラクターはBitmap、デフォルトで32bpp、ARGBレイアウトになります。これが画面と一致しない場合は、変換する必要があります。GDIメソッドを使用してCreateCompatibleBitmap()、一致するビットマップを取得することを検討してください。

最後に...あなたのサンプルコードはまさにそれであり、例示的なスニペットだと思います。ただし、既存の画像を画面にレンダリングする以外に実際に何もしていない場合は、バックバッファを維持する必要はまったくありません。画像から直接Bltするだけです(事前に画像の形式をに変換します)。画面に一致します)。

于 2008-10-14T00:13:16.693 に答える
4

DCへの書き込みには、GDI +ではなく旧式のGDIを使用してみてください。特に、すでにイメージをバッファリングしているためです。Bitmap :: LockBitsを使用して生のビットマップデータにアクセスし、BITMAPINFO構造を作成し、SetDIBitsToDeviceを使用してビットマップを表示します。

于 2008-10-13T15:53:24.423 に答える
3

Direct3Dを使用して、vsync がいつ発生したかなどを「伝える」ことで、ある程度の牽引力を得ることができるため、適切なタイミングで BitBlt/update を実行できます。テアリングを避けるために GDI vsync を参照してください(ただし、場合によっては、1 つの小さな BitBlt にまとめることで「十分」になる場合があります)。

また、GDI BitBlt が画面の vsync と同期されていないように見えることにも注意してください。 BitBlt よりも高速を参照してください。

また、CAPTUREBLT (透明なウィンドウをキャプチャできるようにする) を使用すると、マウスがちらつくことにも注意してください (エアロが使用されていない場合)。

于 2012-05-09T14:38:40.300 に答える
3

ウィンドウのウィンドウ クラスのスタイルに CS_VREDRAW および CS_HREDRAW フラグが含まれていないことを確認してください。

http://msdn.microsoft.com/en-us/library/ms633574(VS.85).aspxを参照してください。

于 2008-10-13T16:30:20.713 に答える
0

フォームに子ウィンドウはありますか?ウィンドウマネージャーは、WM_ERASEBKGNDメッセージを送信して親ウィンドウに背景を消去させることから始め、次にwM_PAINTメッセージを送信します。おそらくこれはwx::OnDrawメソッドにマップされます。次に、各子コントロールを繰り返し処理し、子コントロールに自分でペイントさせます。

これがシナリオの場合...Vistaの新しいエアロルックを使用すると、エアロデスクトップウィンドウマネージャーがウィンドウ合成を自動的に行うため、問題が解決します。古いウィンドウマネージャーでは、そのピタです。

于 2008-10-13T15:58:23.507 に答える