如何使用 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 在窗口中显示位图(带有颜色值的数组)?的主要内容,如果未能解决你的问题,请参考以下文章
VC++ win32 API 编程:如何将图像从剪贴板中取出并显示在窗口中?
为啥在 glfw 窗口上没有使用 opengl 显示位图图像?在 C++ 中读取位图图像文件时出现问题