Win32令人困惑的闪烁

时间:2013-01-03 03:46:25

标签: c++ winapi

我有一个函数,其中一堆东西被绘制到屏幕外缓冲区。在函数结束时,它调用InvalidateRect。出于某种原因,有时它会在函数中间重绘,从而导致闪烁。这是函数的代码:

// Side Info
HBITMAP side = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEINFO));
hdcold = (HBITMAP)SelectObject(hbcmem, side);
BitBlt(hdcmem, 339, 26, 154, 300, hbcmem, 0, 0, SRCCOPY);
DrawLevelNumber(game.levelnumber);

if (color)
    sprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_COLOR_SPRITES));
else sprites = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BLACKWHITE_SPRITES));
hdcold = (HBITMAP)SelectObject(hbcmem, sprites);

// Find x and y coordinate for the top left of the visible screen
int x = game.Player_x, y = game.Player_y, ypos = 0;
if (x < 4)  x = 4;
if (x > 27) x = 27;
if (y < 4)  y = 4;
if (y > 27) y = 27;
x -= 4;
y -= 4;

// Draw lower layer
for (int i = 0; i < 9; i++)
{
    for (int j = 0; j < 9; j++)
    {
        if (game.Layer_Two[x + i][y + j] != 0)
        {
            int xpos = game.get_pos(game.Layer_Two[x + i][y + j], ypos, false);
            BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCCOPY);
        }
    }
}

// Draw upper layer
for (int i = 0; i < 9; i++)
{
    for (int j = 0; j < 9; j++)
    {
        if ((game.Layer_Two[x + i][y + j] != 0 && game.Layer_One[x + i][y + j] >= 64 && game.Layer_One[x + i][y + j] <= 111))
        {
            int xpos = game.get_pos(game.Layer_One[x + i][y + j], ypos, true);
            BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos + 96, ypos, SRCPAINT);
            BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCAND);
        } else {
            int xpos = game.get_pos(game.Layer_One[x + i][y + j], ypos, false);
            BitBlt(hdcmem, (i * 32) + 32, (j * 32) + 32, 32, 32, hbcmem, xpos, ypos, SRCCOPY);
        }
    }
}

// If it isn't started, show title
if (!game.started)
{

    HDC tmphdc = CreateCompatibleDC(hdcmem);
    HDC tmp = CreateCompatibleDC(tmphdc);
    RECT rc;
    GetClientRect(hWnd, &rc);
    string str = game.leveltitle.substr(0, game.leveltitle.length() - 1) + "\nPassword: " + game.password;
    TCHAR* tch = new TCHAR[str.length()];
    mbstowcs_s(NULL, tch, _tcslen(tch), str.c_str(), str.length());
    HFONT font = CreateFont(25, 0, 0, 0, FW_BOLD, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, NULL);
    SelectObject(tmp, font);
    DrawText(tmp, tch, str.length(), &rc, DT_CALCRECT);
    rc.right += 16;
    HBITMAP tmpbm = CreateCompatibleBitmap(hdcmem, rc.right, rc.bottom);
    HBITMAP tmpold = (HBITMAP)SelectObject(tmphdc, tmpbm);

    HBRUSH hbr = CreateSolidBrush(RGB(255, 255, 255));
    HPEN pen = CreatePen(PS_SOLID, 1, RGB(255, 255, 255));
    SelectObject(hdcmem, pen);
    SelectObject(hdcmem, hbr);
    Rectangle(hdcmem, 176 - (rc.right / 2), 243, 177 + (rc.right / 2), 248);
    hbr = CreateSolidBrush(RGB(128, 128, 128));
    pen = CreatePen(PS_SOLID, 1, RGB(128, 128, 128));
    SelectObject(hdcmem, pen);
    SelectObject(hdcmem, hbr);
    Rectangle(hdcmem, 176 - (rc.right / 2), 294, 177 + (rc.right / 2), 299);

    HBITMAP left = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_LEFT));
    hdcold = (HBITMAP)SelectObject(hbcmem, left);
    BitBlt(hdcmem, 176 - (rc.right / 2) - 4, 243, 4, 56, hbcmem, 0, 0, SRCCOPY);
    HBITMAP right = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_RIGHT));
    hdcold = (HBITMAP)SelectObject(hbcmem, right);
    BitBlt(hdcmem, 176 + (rc.right / 2) + 1, 243, 4, 56, hbcmem, 0, 0, SRCCOPY);

    SelectObject(tmphdc, font);
    SetTextColor(tmphdc, RGB(255, 255, 0));
    SetBkColor(tmphdc, RGB(0, 0, 0));
    DrawText(tmphdc, tch, str.length(), &rc, DT_CENTER);
    BITMAP structBitmapHeader;
    memset( &structBitmapHeader, 0, sizeof(BITMAP) );
    HGDIOBJ hBitmap = GetCurrentObject(tmphdc, OBJ_BITMAP);
    GetObject(hBitmap, sizeof(BITMAP), &structBitmapHeader);
    BitBlt(hdcmem, 176 - (rc.right / 2), 247, structBitmapHeader.bmWidth, structBitmapHeader.bmHeight, tmphdc, 0, 0, SRCCOPY);
}

// If paused
if (game.paused)
{
    RECT rc;
    rc.top = 32;
    rc.left = 32;
    rc.bottom = 330;
    rc.right = 330;
    BitBlt(hdcmem, 32, 32, 288, 288, NULL, 0, 0, BLACKNESS);
    HFONT font = CreateFont(50, 0, 0, 0, FW_NORMAL, false, false, false, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, NULL);
    SelectObject(hdcmem, font);
    SetTextColor(hdcmem, RGB(255, 0, 0));
    SetBkColor(hdcmem, RGB(0, 0, 0));
    DrawText(hdcmem, L"PAUSED", 6, &rc, (DT_CENTER + DT_SINGLELINE + DT_VCENTER));
}

nums = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_NUMBERS));
hdcold = (HBITMAP)SelectObject(hbcmem, nums);
for (int i = 100; i > 0; i /= 10) // Coins left
{
    int tmp;
    if (i == 100)
        tmp = game.coinsleft / 100;
    if (i == 10)
        tmp = ((game.coinsleft % 100) - (game.coinsleft % 10)) / 10;
    if (i == 1)
        tmp = game.coinsleft % 10;
    if (game.coinsleft < i && i > 1)
        tmp = 10;
    int ypos = game.get_num_pos(tmp, (game.coinsleft == 0));
    BitBlt(hdcmem, 369 + ((3 - log10((double)i)) * 17), 215, 17, 23, hbcmem, 0, ypos, SRCCOPY);

    if (i == 100)
        tmp = game.timeleft / 100;
    if (i == 10)
        tmp = ((game.timeleft % 100) - (game.timeleft % 10)) / 10;
    if (i == 1)
        tmp = game.timeleft % 10;
    if (game.timeleft < i && i > 1)
        tmp = 10;
    if (game.timelimit == 0)
        tmp = 11;
    ypos = game.get_num_pos(tmp, (game.timeleft < 16 || game.timelimit == 0));
    BitBlt(hdcmem, 369 + ((3 - log10((double)i)) * 17), 125, 17, 23, hbcmem, 0, ypos, SRCCOPY);
}

if (game.onhint)
{
    HBITMAP sidebg = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_SIDEBG));
    hdcold = (HBITMAP)SelectObject(hbcmem, sidebg);
    BitBlt(hdcmem, 353, 165, 127, 146, hbcmem, 0, 0, SRCCOPY);
} else {
    hdcold = (HBITMAP)SelectObject(hbcmem, sprites);                // LOWER SIDE INFO
    if (game.key1 > 0)
        BitBlt(hdcmem, 352, 247, 32, 32, hbcmem, 192, 160, SRCCOPY);
    else BitBlt(hdcmem, 352, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.key2 > 0)
        BitBlt(hdcmem, 384, 247, 32, 32, hbcmem, 192, 128, SRCCOPY);
    else BitBlt(hdcmem, 384, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.key3 > 0)
        BitBlt(hdcmem, 416, 247, 32, 32, hbcmem, 192, 224, SRCCOPY);
    else BitBlt(hdcmem, 416, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.key4)
        BitBlt(hdcmem, 448, 247, 32, 32, hbcmem, 192, 192, SRCCOPY);
    else BitBlt(hdcmem, 448, 247, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.water)
        BitBlt(hdcmem, 352, 279, 32, 32, hbcmem, 192, 256, SRCCOPY);
    else BitBlt(hdcmem, 352, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.fire)
        BitBlt(hdcmem, 384, 279, 32, 32, hbcmem, 192, 288, SRCCOPY);
    else BitBlt(hdcmem, 384, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.ice)
        BitBlt(hdcmem, 416, 279, 32, 32, hbcmem, 192, 320, SRCCOPY);
    else BitBlt(hdcmem, 416, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
    if (game.suction)
        BitBlt(hdcmem, 448, 279, 32, 32, hbcmem, 192, 352, SRCCOPY);
    else BitBlt(hdcmem, 448, 279, 32, 32, hbcmem, 0, 0, SRCCOPY);
}

RECT rc;
rc.left = 0;
rc.top = 0;
rc.right = 518;
rc.bottom = 401;
InvalidateRect(hWnd, &rc, false);

导致闪烁的原因是什么?

1 个答案:

答案 0 :(得分:2)

  1. 确保处理WM_ERASEBKGND消息并返回TRUE,这将阻止窗口基类绘制背景。

  2. 不是在绘图例程结束时调用InvalidateRect,而是将绘图代码放在WM_PAINT消息处理程序中,这样可以确保在重新绘制窗口时调用绘图代码。