C++ 停止显示位图

标签 c++ windows bitmap

如何停止在我的 Win32 项目中显示位图。我有一个在 WM_PAINT 中调用的方法,称为 LoadBitmap。它的代码如下所示:

bool LoadBitmap(LPTSTR szfilename, HDC winhdc, int x, int y) {
    HBITMAP bitmap;
    bitmap = (HBITMAP)LoadImage(NULL, szfilename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
    if (bitmap == NULL) {
        ::MessageBox(NULL, _T("Bitmap failed"), NULL, MB_OK);
        return false;
    }

    HDC hdc;
    hdc = ::CreateCompatibleDC(winhdc);
    if (hdc == NULL)
    {
        ::MessageBox(NULL, _T("HDC FAILED"), NULL, MB_OK);
        return false;
    }

    BITMAP qbitmap;
    int ireturn = GetObject(reinterpret_cast<HGDIOBJ>(bitmap), sizeof(BITMAP), reinterpret_cast<LPVOID>(&qbitmap));
    if (!ireturn) {
        ::MessageBox(NULL, _T("RETURN FAILED"), NULL, MB_OK);
        return false;
    }
    HBITMAP holdbitmap = (HBITMAP)::SelectObject(hdc, bitmap);
    if (holdbitmap == NULL) {
        ::MessageBox(NULL, _T("HOLD FAILED"), NULL, MB_OK);
        return false;
    }

    BOOL qRetBlit = ::BitBlt(winhdc, x, y, qbitmap.bmWidth, qbitmap.bmHeight, hdc, 0, 0, SRCCOPY);
    if (!qRetBlit)
    {
        ::MessageBox(NULL, _T("BLIT FAILED"), NULL, MB_OK);
        return false;
    }
    ::SelectObject(hdc, holdbitmap);
    ::DeleteDC(hdc);
    ::DeleteObject(bitmap);
    return true;

}

注意 x 和 y 不断变化。 但是,当 x 和 y 发生变化时,它们之前的实例会保留下来。

位图在新位置绘制后如何停止显示?

最佳答案

如果有背景画笔,则每次绘制调用都会删除旧位图。如果没有背景,则手动删除它,例如使用 FillRect 这里是双缓冲的示例,假设没有背景画笔。

case WM_PAINT:
{
    ...
    PAINTSTRUCT ps;
    HDC hdc = BeginPaint(hwnd, &ps);
    RECT rc = ps.rcPaint;
    HDC memdc = CreateCompatibleDC(hdc);
    HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
    HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);

    //double-buffer ready, do custom paintings here:
    FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
    LoadBitmap(filename, memdc, x, y);

    //BitBlt to hdc
    BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);

    //cleanup:
    SelectObject(hdc, oldbitmap);
    DeleteObject(membitmap);
    DeleteDC(memdc);
    EndPaint(hwnd, &ps);
    return 0;
}

编辑 *************

只加载一次位图文件会更快。对于每个绘制请求,我们只需要绘制位图,而不是每次都加载图像+绘制。

您可以在窗口过程中将HBITMAP 句柄声明为静态值。在WM_CREATE中设置一次,在WM_NCDESTROY中清除。现在我们可以在侧窗过程中的任何地方使用它们:

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
    static HBITMAP hbitmap_background = NULL;
    static HBITMAP hbitmap_sprite = NULL;

    switch (msg)
    {

    case WM_CREATE:
    {
        hbitmap_background = (HBITMAP)LoadImage(NULL, 
            L"background.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        if (!hbitmap_background)
            OutputDebugStringW(L"!hbitmap_background\n");

        hbitmap_sprite = (HBITMAP)LoadImage(NULL, 
            L"sprite.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
        if (!hbitmap_sprite)
            OutputDebugStringW(L"!hbitmap_sprite\n");
    }

    case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hwnd, &ps);
        RECT rc = ps.rcPaint;

        //setup double-buffering:
        HDC memdc = CreateCompatibleDC(hdc);
        HBITMAP membitmap = CreateCompatibleBitmap(hdc, rc.right, rc.bottom);
        HGDIOBJ oldbitmap = SelectObject(memdc, membitmap);

        //double-buffer ready, do custom paintings here:
        FillRect(memdc, &rc, GetSysColorBrush(COLOR_3DFACE));
        DrawBitmap(hbitmap_background, memdc, 0, 0);
        DrawBitmap(hbitmap_sprite, memdc, 0, 0);

        //BitBlt to hdc
        BitBlt(hdc, 0, 0, rc.right, rc.bottom, memdc, 0, 0, SRCCOPY);

        //cleanup:
        SelectObject(hdc, oldbitmap);
        DeleteObject(membitmap);
        DeleteDC(memdc);
        EndPaint(hwnd, &ps);
        return 0;
    }

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;

    case WM_NCDESTROY:
    {
        //cleapup bitmap handles
        if (hbitmap_background)
            DeleteObject(hbitmap_background);

        if (hbitmap_sprite)
            DeleteObject(hbitmap_sprite);
    }

    }

    return DefWindowProc(hwnd, msg, wp, lp);
} 

我们可以改变DrawBitmap让它只需要HBITMAP句柄

void DrawBitmap(HBITMAP hbitmap, HDC hdc, int x, int y)
{
    if (!hbitmap)
    {
        OutputDebugStringW(L"error\n");
        return;
    }

    BITMAP bm;
    GetObject(hbitmap, sizeof(BITMAP), &bm);    
    HDC memdc = CreateCompatibleDC(hdc);
    HGDIOBJ oldbitmap = SelectObject(memdc, hbitmap);
    BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, memdc, 0, 0, SRCCOPY);
    SelectObject(memdc, oldbitmap);
    DeleteDC(memdc);
}

注意,在这个例子中我假设 background.bmp 非常大,而 sprite.bmp 非常小。如果以相反的方式绘制,则背景将隐藏 Sprite 。

关于C++ 停止显示位图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36076861/

相关文章:

c++ - 迭代可变参数模板类的基类

c++ - Rcpp 找不到 gsl 库

c - 我可以在文件系统驱动程序中的 ZwCreateFile/InitializeObjectAttributes 中设置/检查用户定义的标志吗?

适用于 UWP 和经典桌面的 C++ 通用 Windows DLL

java - 从 url 加载位图太慢

c++ - boost::ref 没有发生匹配调用错误,但 std::ref 没有

c++ - 在 c/c++ 中更改 Windows 服务的状态

windows - 如何在 Windows 上使用 GUI 添加或删除 git 标签?

Android 位图图像大小

android - 如何在webview中截取 map 的截图