0

2 つのソース イメージ (塗りつぶしと塗りつぶしなし) を使用してプログレス バーを描画する WIN32 所有者描画の静的コントロールがあります。最初のドローでうまく機能します:

case WM_DRAWITEM:
    {
        DRAWITEMSTRUCT* draw = (DRAWITEMSTRUCT*)lparam;
        // Manually draw the progress bar.
        if( draw->hwndItem == hwndProgress )
        {
            // Progress bar is 526 pixels wide.
            int left = progressPercent * 526 / 100;
            // Paint sections of window with filled and unfilled bitmaps
            // based on progress bar position.
            HDC hdcMem = ::CreateCompatibleDC(draw->hDC);
            ::SelectObject(hdcMem, hBmpProgressFull);
            ::BitBlt(draw->hDC, 0, 0, left, 36, hdcMem, 0, 0, SRCCOPY);
            ::DeleteDC(hdcMem);
            HDC hdcMem2 = ::CreateCompatibleDC(draw->hDC);
            ::SelectObject(hdcMem2, hBmpProgressEmpty);
            ::BitBlt(draw->hDC, left, 0, 526-left, 36, hdcMem2, left, 0, SRCCOPY);
            ::DeleteDC(hdcMem2);
            return TRUE;
        }
    }
    return 0;

しかし、うまく消したり塗り直したりすることができないようです。SendMessage を WM_PAINT と RedrawWindow で試しましたが、どちらもうまくいきませんでした:

bool SetLoginProgressBar(float value)
{
    if( hwndProgress != NULL )
    {
        progressPercent = (int)(value * 100.0);
        //::RedrawWindow(hwndProgress, NULL, NULL, RDW_INVALIDATE|RDW_INTERNALPAINT);
        ::SendMessage(hwndProgress, WM_PAINT, NULL, NULL);
    }
    return true;
}

新しい値でウィンドウを再描画する代わりに、最初に描画された画像をそこに置き、それ以降の描画コマンドを無視します。0%、50% などの初期値の進行状況を正しく描画し、WM_DRAWITEM メッセージ ハンドラー コードが呼び出されていることを確認できます。

では、WIN32 でこのコントロールに消去と再描画を指示する正しい方法は何ですか?

BeginPaint/EndPaint のようなことをしたり、渡された DRAWITEMSTRUCT の hDC を削除したりする必要がある可能性はありますか?

4

2 に答える 2

6

DC を破棄する前に、メモリ DC からビットマップを選択解除していません。おそらく、ビットマップが Windows で再度選択できない状態になっているため、BitBlts が失敗しています。

PS RedrawWindow は、この状況で使用するものです。InvalidateRect も機能しますが、メッセージ ループが実行されている場合のみです。これは別の観察につながります。長時間実行されている操作の途中である場合、メッセージ ループに戻らない可能性があり、進行状況ウィンドウの更新を含め、アプリがハングしているように見えます。

于 2011-06-24T18:49:10.370 に答える
3

InvalidateRect()呼び出す必要がある関数です。

メッセージを送信したり投稿したりすることはありませんWM_PAINT。必要なときにウィンドウ マネージャーがメッセージを送信します (たとえば、ウィンドウをウィンドウの上にドラッグします)。再描画がウィンドウ マネージャが認識していない変更によるものである場合は、 を呼び出して再描画サイクルを強制しますInvalidateRect()。合格NULLするlpRectと、クライアント領域全体が再描画されます。再描画サイクルの開始時に背景を強制的に消去するには、TRUEforを渡します。bErase

を呼び出すInvalidateRect()と、WM_PAINTメッセージがメッセージ キューに置かれ、InvalidateRect()関数呼び出しが返されます。次にメッセージ キューをクリアすると、メッセージが処理されWM_PAINTます。

Petzold の Programming Windows の本を入手して、すべてを読むことをお勧めします。

于 2011-06-24T18:30:45.763 に答える