【问题标题】:How can I load a bitmap inside my window?如何在我的窗口中加载位图?
【发布时间】:2016-06-23 18:34:18
【问题描述】:

我正在尝试将位图加载到我创建的窗口中。位图应该是窗口的背景(稍后我想在其上添加标签和进度条)。

这是我的代码:

HINSTANCE hInst;
LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);

INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
WNDCLASSEX  WndCls;
static WCHAR szAppName[] = L"BitmapIntro";
MSG         Msg;

hInst = hInstance;
WndCls.cbSize = sizeof(WndCls);
WndCls.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
WndCls.lpfnWndProc = WindProcedure;
WndCls.cbClsExtra = 0;
WndCls.cbWndExtra = 0;
WndCls.hInstance = hInst;
WndCls.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndCls.hCursor = LoadCursor(NULL, IDC_ARROW);
WndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
WndCls.lpszMenuName = NULL;
WndCls.lpszClassName = szAppName;
WndCls.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);
RegisterClassEx(&WndCls);

CreateWindowEx(WS_EX_OVERLAPPEDWINDOW,
    szAppName,
    L"Bitmaps Fundamentals",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL);

while (GetMessage(&Msg, NULL, 0, 0))
{
    TranslateMessage(&Msg);
    DispatchMessage(&Msg);
}

return static_cast<int>(Msg.wParam);
}

LRESULT CALLBACK WindProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
HDC hDC, MemDCExercising;
PAINTSTRUCT Ps;
HBITMAP bmpExercising;

switch (Msg)
{
case WM_DESTROY:
    PostQuitMessage(WM_QUIT);
    break;
case WM_PAINT:

    hDC = BeginPaint(hWnd, &Ps);

    // Load the bitmap from the resource
    bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP3));
    // Create a memory device compatible with the above DC variable
    MemDCExercising = CreateCompatibleDC(hDC);
    // Select the new bitmap
    SelectObject(MemDCExercising, bmpExercising);

    // Copy the bits from the memory DC into the current dc
    BitBlt(hDC, 10, 10, 450, 400, MemDCExercising, 0, 0, SRCCOPY);

    // Restore the old bitmap
    DeleteDC(MemDCExercising);
    DeleteObject(bmpExercising);
    EndPaint(hWnd, &Ps);
    break;
default:
    return DefWindowProc(hWnd, Msg, wParam, lParam);
}
return 0;
}

问题是,PNG尺寸比窗口小,所以当PNG打开时,它只占据左高角。我怎样才能让它伸展到我的窗口大小,或者至少一遍又一遍地绘制它直到它填满窗口?

【问题讨论】:

  • StretchBlt。包括所有丑陋的伪影和质量下降。

标签: winapi bitmap


【解决方案1】:

我怎样才能让它伸展到我的窗口大小

使用StretchBlt() 代替BitBlt()

case WM_PAINT:
{    
    // Get the window dimensions
    RECT r;
    GetClientRect(hWnd, &r);

    // Load the bitmap from the resource
    HBITMAP bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP3));

    // Get the bitmap dimensions
    BITMAP bmp;
    GetObject(bmpExercising, sizeof(BITMAP), &bmp);

    PAINTSTRUCT Ps;
    HDC hDC = BeginPaint(hWnd, &Ps);

    // Create a memory device compatible with the above DC variable
    HDC MemDCExercising = CreateCompatibleDC(hDC);

    // Select the new bitmap
    HBITMAP hOldBmp = SelectObject(MemDCExercising, bmpExercising);

    // Copy the bits from the memory DC into the current dc
    StretchBlt(hDC, 0, 0, r.right - r.left, r.bottom - r.top, MemDCExercising, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);

    // Restore the old bitmap
    SelectObject(MemDCExercising, hOldBmp);

    // Destroy the memory device
    DeleteDC(MemDCExercising);

    // Destroy the bitmap
    DeleteObject(bmpExercising);

    EndPaint(hWnd, &Ps);
    break;
}

或者至少一遍又一遍地绘制它直到它填满窗口?

有两种不同的处理方式。

  1. 在启动时,加载位图并使用CreatePatternBrush() 在其周围创建一个HBRUSH,然后在注册窗口类时将其分配给WNDCLASS::hbrBackground 字段。让操作系统使用位图为您绘制窗口背景。

    HBITMAP bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP3));
    WndCls.hbrBackground = CreatePatternBrush(bmpExercising);
    
  2. 如果您想手动绘制位图,请让您的绘制处理程序在几个循环中调用BitBlt()。您知道位图的尺寸(您可以使用GetObject()BITMAP 结构在代码中检索),并且您知道窗口的尺寸(您可以使用GetWindowRect()GetClientRect() 在代码中检索) .因此,只需根据需要在不同的偏移量处多次绘制相同的位图。首先在左上角绘制一次,然后向右移动位图宽度像素并再次绘制它,重复直到移动超过窗口宽度像素。然后向左移回 0 并向下移动位图高度像素并再次重复整个宽度线,重复直到超过窗口高度像素。

    case WM_PAINT:
    {    
        // Get the window dimensions
        RECT r;
        GetClientRect(hWnd, &r);
    
        // Load the bitmap from the resource
        HBITMAP bmpExercising = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BITMAP3));
    
        // Get the bitmap dimensions
        BITMAP bmp;
        GetObject(bmpExercising, sizeof(BITMAP), &bmp);
    
        PAINTSTRUCT Ps;
        HDC hDC = BeginPaint(hWnd, &Ps);
    
        // Create a memory device compatible with the above DC variable
        HDC MemDCExercising = CreateCompatibleDC(hDC);
    
        // Select the new bitmap
        HBITMAP hOldBmp = SelectObject(MemDCExercising, bmpExercising);
    
        int width = r.right - r.left;
        int height = r.bottom - r.top;
    
        // Copy the bits from the memory DC into the current dc
        for(int y = 0; y < height; y += bmp.bmHeight)
        {
            for(int x = 0; x < width; x += bmp.bmWidth)
            {
                BitBlt(hDC, x, y, bmp.bmWidth, bmp.bmHeight, MemDCExercising, 0, 0, SRCCOPY);
            }
        }
    
        // Restore the old bitmap
        SelectObject(MemDCExercising, hOldBmp);
    
        // Destroy the memory device
        DeleteDC(MemDCExercising);
    
        // Destroy the bitmap
        DeleteObject(bmpExercising);
    
        EndPaint(hWnd, &Ps);
        break;
    }
    

现在,话虽如此,这里有一些补充说明:

  1. 您不应该在您的绘图处理程序中加载位图。在创建窗口之前加载一次,然后为每个绘制操作重复使用相同的HBITMAP,直到窗口被销毁,然后释放位图。

  2. LoadBitmap() 已弃用,您应该改用LoadImage(),例如:

    HBITMAP bmpExercising = (HBITMAP) LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP3), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
    
  3. 您说“位图应该是窗口的背景”,因此您应该绘制位图以响应 WM_ERASEBKGND 消息而不是 WM_PAINT 消息。

    case WM_ERASEBKGND:
    {    
        HDC hDC = (HDC) wParam;
    
        // draw the bitmap on hDC as needed...
    
        return 1;
    }
    

【讨论】:

    猜你喜欢
    • 2010-12-15
    • 2017-07-10
    • 2015-06-10
    • 2012-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    相关资源
    最近更新 更多