如何在窗口中加载位图?

时间:2016-06-23 18:34:19

标签: winapi bitmap

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

这是我的代码:

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打开时,它只占据左上角。如何让它拉伸到我的窗口大小或者至少一遍又一遍地拉到窗口?

1 个答案:

答案 0 :(得分:2)

  

如何让它拉伸到我的窗口大小

使用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结构在代码中检索),并且您知道窗口的尺寸(您可以使用{{3}在代码中检索该尺寸}或GetWindowRect())。因此,根据需要,可以根据不同的偏移量多次绘制相同的位图。首先在左上角绘制一次,然后向右移动位图宽度像素并再次绘制,重复直到移过窗口宽度像素。然后向左移动到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;
    }
    
  3. 现在,说到这里,还有一些补充说明:

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

    2. LoadBitmap()已被弃用,您应该使用GetClientRect()代替,例如:

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

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