为何使用Windows.h中StretchDIBits绘制位图时卡顿且出现条纹?
问题根源与修复方案
1. 像素格式不匹配(核心问题)
你设置的BITMAPINFO是24位色(biBitCount = 24),但填充像素时用unsigned int(32位)写入RGB值。24位位图每个像素占3字节(R、G、B各8位),32位是4字节(含Alpha通道),这会导致内存中像素数据错位,StretchDIBits读取时出现条纹。
修复:
将biBitCount改为32,同时确保缓冲区大小与32位像素匹配:
// 在WM_SIZE消息处理中修改 buffer_bitmap.bmiHeader.biBitCount = 32; buffer_sizes = BitmapWidth * BitmapHeight * sizeof(unsigned int);
2. 位图参数缺失与行对齐问题
Windows GDI要求位图显式指定总字节数(biSizeImage),同时每行字节数需按4字节对齐(32位像素天然满足,无需额外处理)。缺失该参数会导致绘制时数据读取错误。
修复:
在WM_SIZE中添加biSizeImage赋值:
buffer_bitmap.bmiHeader.biSizeImage = buffer_sizes;
3. 窗口重绘逻辑错误
你的WM_PAINT消息处理为空,窗口需要重绘时(如调整大小、被遮挡恢复)不会自动刷新画面,导致绘制不全。同时主循环直接调用StretchDIBits到屏幕DC,未与系统绘制时机配合,易出现画面撕裂。
修复:
- 在WM_PAINT中完成绘制,使用
BeginPaint/EndPaint获取正确DC:
case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); StretchDIBits(hdc, 0, 0, ClientWidth, ClientHeight, 0, 0, BitmapWidth, BitmapHeight, buffer_memory, &buffer_bitmap, DIB_RGB_COLORS, SRCCOPY); EndPaint(hwnd, &ps); } return 0;
- 主循环只负责更新画面数据,通过
InvalidateRect触发系统重绘:
// Source.cpp主循环修改 while (running == true) { if (!mywindow.windowpro()) { running = false; continue; } mywindow.backgroundcolor(225, 225, 225); InvalidateRect(CreateMyWindow, NULL, FALSE); // 触发WM_PAINT Sleep(1); // 避免CPU占用过高 }
4. 全局变量初始化问题
myhinstance未初始化会导致窗口类注册失败,需在窗口构造函数中赋值:
window::window() { myhinstance = GetModuleHandle(nullptr); // 新增初始化 WindowClass.lpszClassName = "Game_Engine"; // ... 其他原有代码 }
5. 全屏画面撕裂优化
全屏时刷新率更高,直接绘制易出现撕裂。通过上述WM_PAINT配合系统绘制时机的方式,可让窗口管理器自动处理同步,避免撕裂。
内容的提问来源于stack exchange,提问作者Codin Mark
相关产品推荐
相关产品推荐

