1

次のコードを使用して、WM_PAINT メッセージ ハンドラーで多くの線を描画したいと考えています。

//DrawLine with double buffering
LRESULT CALLBACK CMyDoc::OnPaint(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
    std::vector<Gdiplus::Point> points;
    std::vector<Gdiplus::Point>::iterator iter1, iter2;
    HDC hdc, hdcMem;
    HBITMAP hbmScreen, hbmOldBitmap;
    PAINTSTRUCT ps;
    RECT    rect;

    hdc = BeginPaint(hWnd, &ps);

    //Create memory dc
    hdcMem = CreateCompatibleDC(hdc);
    GetClientRect(hWnd, &rect);
    hbmScreen = CreateCompatibleBitmap(hdc, rect.right, rect.bottom);
    hbmOldBitmap = (HBITMAP)SelectObject(hdcMem, hbmScreen);

    //Fill the rect with white
    FillRect(hdcMem, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));

    //Draw the lines
    Gdiplus::Graphics graphics(hdcMem);
    Gdiplus::Pen blackPen(Gdiplus::Color(255, 0, 0));

    points = m_pPolyLine->GetPoints();
    for (iter1 = points.begin(); iter1 != points.end(); iter1++) {
        for (iter2 = iter1 + 1; iter2 != points.end(); iter2++)
            graphics.DrawLine(&blackPen, *iter1, *iter2);
    }

    //Copy the bitmap from memory dc to the real dc
    BitBlt(hdc, 0, 0, rect.right, rect.bottom, hdcMem, 0, 0, SRCCOPY);

    //Clean up
    SelectObject(hdcMem, hbmOldBitmap);
    DeleteObject(hbmScreen);
    DeleteDC(hdcMem);

    EndPaint(hWnd, &ps);
    return 0;
}

ただし、ポイントのサイズが 20 を超えると、クライアント rect がちらつくだけです。その理由は、Gdiplus::DrawLines が遅すぎるためだと思います。

ちらつきの問題を解決する方法はありますか? ありがとう。

4

4 に答える 4

6

ちらつきは、描画が遅いことや、他のことが原因である可能性があります。一般に、次のことを試して確認してください。

  • メッセージに依存しないようにしてWM_ERASEBKGNDください。つまり、ゼロ以外を返すか、可能であれば指定NULLしてください。WNDCLASS::hbrBackground多くの場合、ペイント メソッドはダーティ リージョンのすべての背景をペイントするため、消去を行う必要はありません。

  • 消去が必要な場合は、多くWM_ERASEBKGNDの場合、ゼロ以外を返すように最適化できます。ペイント メソッドは、PAINTSTRUCT::fErase設定されている場合、通常のペイントされたコンテンツでカバーされていない領域もペイントすることで「消去」を保証します。

  • 合理的に可能であれば、1 回の呼び出しで同じピクセルを再描画しないようにペイント メソッドを記述します。たとえば、赤い境界線で青い四角形を作成するには、しないFillRect(red)でください。その後、その内部を で塗り直しFillRect(blue)ます。合理的に可能な限り、各ピクセルを 1 回ペイントするようにしてください。

  • PAINTSTRUCT::rcPaint複雑なコントロール/ウィンドウの場合、ペイント メソッドは、コントロール データを適切に整理することにより、ダーティ rect ( ) の外側の多くのペイントを簡単にスキップできるように最適化されることがよくあります。

  • コントロールの状態を変更するときは、コントロールの必要最小限の領域のみを無効にします。

  • トップレベル ウィンドウでない場合は、 の使用を検討してCS_PARENTDCください。ペイント メソッドが、クリッピング四角形をコントロールのクライアント四角形に設定するシステムに依存していない場合、このクラス スタイルによりパフォーマンスがいくらか向上します。

  • コントロール/ウィンドウのサイズ変更でちらつきが見られる場合は、 と を使用しないことを検討してCS_HREDRAWくださいCS_VREDRAW。代わりに、コントロールの関連部分をWM_SIZE手動で無効にします。これにより、多くの場合、コントロールの小さな部分のみを無効にすることができます。

  • コントロールのスクロールでちらつきが見られる場合は、クライアント全体を無効にするのではなくScrollWindow()、新しい (スクロールインされた) コンテンツを公開する小さな領域のみを使用して無効にします。

  • 上記のすべてが失敗した場合は、ダブル バッファリングを使用します。

于 2012-06-18T08:08:59.903 に答える
3

ダブルバッファを使用してください。これは、Win32 C++ アプリケーション、特に OnPaint 関数と DC 機能に関する問題です。

ダブルバッファの実装ですべてが問題ないかどうかを確認するのに役立ついくつかのリンクを次に示します。Flicker Free Drawing In MFC and SO question " Reduce flicker with GDI+ and C++ "

于 2012-06-18T03:46:51.833 に答える
-1

問題は、自分で WM_ERASEBKGND メッセージを処理していないことです。

于 2012-06-18T06:04:27.213 に答える