如何使用 Window API 在窗口中显示位图(带有颜色值的数组)?

Posted

技术标签:

【中文标题】如何使用 Window API 在窗口中显示位图(带有颜色值的数组)?【英文标题】:How can I display a bitmap (array with color values) in a window using Window API? 【发布时间】:2019-05-20 19:04:33 【问题描述】:

我想使用BitBlt 将颜色值缓冲区移动到窗口,只有窗口显示为空。当我从How can I load a bitmap inside my window?(使用我自己的示例 .bmp 文件)编译并运行代码时,窗口也显示为空。

经过一些测试,问题似乎出在SelectObject()。根据文档,当返回值为 NULL 时,会发生错误:https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-selectobject。返回值为NULL,但GetLastError() 给出0,表示没有出错。这里有什么问题?

    case WM_CREATE:
        std::fill(arr, arr + sizeof(arr), RGB(255,0,0));
        hBitmap = CreateBitmap(240, 120, 1, sizeof(COLORREF), (void*) arr);
        UpdateWindow(hwnd);
        break;
    case WM_PAINT:
        PAINTSTRUCT ps;
        BITMAP bitmap;
        HGDIOBJ oldBitmap;
        HDC hdcMem;
        HDC hdc;

        hdc = BeginPaint(hwnd, &ps);

        hdcMem = CreateCompatibleDC(hdc);
        oldBitmap = SelectObject(hdcMem, hBitmap);
        std::cout << (oldBitmap == NULL) << std::endl;
        std::cout << GetLastError();

        GetObject(hBitmap, sizeof(bitmap), &bitmap);
        BitBlt(hdc, 0, 0, bitmap.bmWidth, bitmap.bmHeight, hdcMem, 0, 0, SRCCOPY);

        SelectObject(hdcMem, oldBitmap);
        DeleteDC(hdcMem);

        EndPaint(hwnd, &ps);
        break;

(顺便说一句:每次我需要hInstance 时,我都使用main() 而不是WinMain()GetModuleHandle(NULL)。由于窗口功能正常,我怀疑它与此无关,但我会提到无论如何。)

---已解决!---

我现在已经开始工作了 :) 对于看到这个的其他人,这就是我所做的更改:

    case WM_CREATE:
        std::fill(arr, arr + 240 * 120, RGB(255,0,0));
        hBitmap = CreateBitmap(240, 120, 1, sizeof(COLORREF) * 8, (void*) arr);
        UpdateWindow(hwnd);
        break;

【问题讨论】:

那个空窗口的颜色是什么? 白色,和我有空窗时一样。 std::fill(arr, arr + sizeof(arr), RGB(255,0,0)); 不正确,sizeof(COLORREF) 也无效,因为它应该是位深度 SelectObject() 返回被替换的对象,可能为空。并且 GDI 不使用GetLastError() 来报告错误。因此,无法区分返回的空对象和实际错误。不过,唯一可能发生的错误是,如果您传入了无效的 HDC 以进行选择。您没有检查 BeginPaint()CreateCompatibleDC() 的返回值是否有错误 谢谢,我是 Windows API 的新手,所以我不知道 :) (顺便说一句:sizeof(arr) 的错误对我来说太愚蠢了,我用 @ 工作过很多次987654340@ 和 fill() 之前。) 【参考方案1】:

如果arr是指针,则使用元素总数(240 * 120

如果arr 是一个数组,sizeof 将返回总大小(以字节为单位)。而是使用sizeof(arr)/sizeof(*arr) 来查找数组的计数(数组元素的总数或像素总数)。例如,假设 arr 的元素是 32 位的,那么您正在查看 240 * 120 像素,其中每个像素是 4 字节或 32 位。

CreateBitmap 的第 4 个参数需要以位为单位的大小,因此它应该是 sizeof(*arr) * 8 或只有 32。

uint32_t arr[240 * 120];
std::fill(arr, arr + sizeof(arr)/sizeof(*arr), RGB(255, 0, 0));
//or std::fill(arr, arr + 240 * 120, RGB(255, 0, 0));
hBitmap = CreateBitmap(240, 120, 1, 32, (void*)arr);

请注意,这将生成蓝色位图,而不是红色,因为它使用 BGR 格式而不是 RGB。

看来您已经知道如何使用内存 dc。您可以使用CreateCompatibleBitmap 创建位图,然后选择该位图到内存dc,并使用标准GDI 函数,例如FillRect。这将避免计算位和字节时的陷阱。

【讨论】:

非常感谢,我现在已经搞定了 :) sizeof(arr) 的错误有点愚蠢,我之前曾多次与 fill()sizeof() 合作过,但那CreateBitmap() 使用位而不是字节,我不知道也不会想到 :)

以上是关于如何使用 Window API 在窗口中显示位图(带有颜色值的数组)?的主要内容,如果未能解决你的问题,请参考以下文章

win32api:在文本行中合并位图

VC++ win32 API 编程:如何将图像从剪贴板中取出并显示在窗口中?

为啥在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题

如何使用 DirectShow API 捕获桌面位图,不包括我的捕获应用程序?

如何使用 GDI 将 RGB 位图绘制到窗口?

怎样用window api实现程序全屏显示