有没有办法在更改与 HDC 关联的位图大小后更新图形对象?
Is there a way to update Graphics object after changing size of bitmap assosiated with HDC?
1. 问题
我有两个缓冲区。主缓冲区,显示在屏幕上,辅助缓冲区用于绘制所有内容,然后传递到主缓冲区。
Graphics 对象是从辅助缓冲区创建的,辅助缓冲区与大小为 800x600 的位图相关联。当然,当您调整窗口大小时,必须更改位图的大小以防止出现剪切问题。 更新辅助 HDC,并将位图复制到主 HDC。
问题是图形对象中还残留了一些与生成剪切的辅助 HDC 关联的内容。绘图区域仍保持 800x600,尽管已更新为更大的 (1000x1000)。
我的问题是我应该在图形对象中更新什么(不必从现有 HDC 显式重新创建它)以使其绘图区域适合位图大小。
2. 我尝试过什么
我尝试的第一件事是从更新的 HDC 重新创建图形对象。此方法有效,并且绘图区域适合位图的大小。但是,它不符合设计标准。图形应该是可重用的。
我还尝试使用 SetClip 方法更新图形对象的剪切区域。虽然这似乎不是问题所在。
这就是我创建缓冲区的方式。
HDC CoreWindowFrame::InitPaint(HWND hWnd)
{
windowHdc = GetDC(hWnd);
HDC secondaryBuffer = CreateCompatibleDC(windowHdc);
HBITMAP map = CreateCompatibleBitmap(windowHdc, width, height);
SelectObject(secondaryBuffer, map);
return secondaryBuffer;
}
此函数在调整大小时调用
void CoreWindowFrame::UpdateBitmap(int width, int height)
{
HBITMAP map = CreateCompatibleBitmap(windowHdc, width, height);
SelectObject(secondaryBuffer, map);
}
这是消息处理:
case WM_SIZE:
ConsoleWrite("WM_SIZE RECIEVED");
width = *((unsigned short*)&lParam);
height = ((unsigned short*)&lParam)[1];
UpdateBitmap(width, height);
break;
case WM_PAINT:
ConsoleWrite("WM_PAINT RECIEVE");
windowGraphics->Clear(Color(255, 255, 255));
Pen* testPen = new Pen(Color(255, 0, 0), 1.0F);
windowGraphics->DrawLine(testPen, 0, 0, calls*3, 100);
BitBlt(windowHdc, 0, 0, updatedWidth, updatedHeight, secondaryBuffer, 0, 0, MERGECOPY);
3. 预期成果
图形对象应该是可重用的,并且每次刷新某些内容时都不应将其丢弃并替换为新对象。因此,如果调整大小或更改任何内容,则必须相应地对其进行更新。我希望该区域适合辅助 HDC 中当前更新的位图的大小。如代码所示,位图已正确更新。图形对象没有。它的行为就像它仍然记得导致此行为的上一个位图中的一些值一样。
windowHdc = GetDC(hWnd); HDC secondaryBuffer = CreateCompatibleDC(windowHdc); HBITMAP map = CreateCompatibleBitmap(windowHdc, width, height); SelectObject(secondaryBuffer, map); return secondaryBuffer;
从GetDC
或BeginPaint
获得HDC
不能重复使用,如注释中所述。
但是,您可以重用内存位图(从CreateCompatibleBitmap
)和重用内存 dc(从CreateCompatibleDC
获得),尽管重用内存 dc 通常没有意义。
此外,需要清理以避免资源泄漏。完成GetDC
后呼叫ReleaseDC
。有关相关的发布/删除函数,请参阅文档。
对于简单的绘画例程,请执行此操作:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
Gdiplus::Graphics gr(hdc);
Gdiplus::Pen testPen(Gdiplus::Color(255, 0, 0), 1.0F);
gr.Clear(Gdiplus::Color::White);
gr.DrawLine(&testPen, 0, 0, 100, 100);
EndPaint(hwnd, &ps);
return 0;
}
通常你不需要做更多的事情。只需调用InvalidateRect
以响应WM_SIZE
即可更新油漆。
对于双缓冲或在画布上绘图,可以创建内存位图并重复使用它。如果窗口大小发生更改,则必须为旧位图调用DeleteObject
,并根据新大小创建新的位图。或者,您可以创建与最大窗口大小匹配的位图,然后将此位图用于所有窗口大小。
请参阅下面的示例以获取双缓冲区绘制(但是在这种情况下不需要重复使用hbitmap
)
HBITMAP hbitmap = NULL;
void InitPaint(HWND hwnd)
{
HDC hdc = GetDC(hwnd);
//create a bitmap with max size:
int w = GetSystemMetrics(SM_CXFULLSCREEN);
int h = GetSystemMetrics(SM_CYFULLSCREEN);
hbitmap = CreateCompatibleBitmap(hdc, w, h);
ReleaseDC(hwnd, hdc);
}
void cleanup()
{
if (hbitmap)
DeleteObject(hbitmap);
}
...
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RECT rc; GetClientRect(hwnd, &rc);
int w = rc.right;
int h = rc.bottom;
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP oldbmp = (HBITMAP)SelectObject(memdc, hbitmap);
Gdiplus::Graphics gr(memdc);
Gdiplus::Pen testPen(Gdiplus::Color(255, 0, 0), 1.0F);
gr.Clear(Gdiplus::Color(255, 255, 255));
gr.DrawLine(&testPen, 0, 0, w, h);
BitBlt(hdc, 0, 0, w, h, memdc, 0, 0, SRCCOPY);
//cleanup:
SelectObject(memdc, oldbmp);
DeleteDC(memdc);
EndPaint(hwnd, &ps);
return 0;
}
总结:
GetDC
不会创造任何东西。它仅返回对系统使用的现有句柄的引用。完成此句柄后,将其释放。没有办法进一步优化这一点。
可以为程序创建其他 GDI 对象(如笔或位图),并且可以重复使用它们。创建/销毁一支笔只需要几纳秒,因此通常不值得增加存储这些对象和跟踪的复杂性。
主要的瓶颈是当你在屏幕上画画时,例如画一条线。您必须与显卡交谈并与显示器交谈,这需要一段时间。可以使用双缓冲在位图上绘制,然后在屏幕上BitBlt
。BitBlt
也可能很慢,具体取决于系统。
对于动画,如果看到闪烁,请使用双缓冲。
为了获得更好的性能,您可以使用较新的技术,例如Direct2D
如果动画仍然太慢,请考虑使用第二个线程来运行任何数学类型计算(第二个线程不应引用任何窗口句柄,例如来自GetDC
或BeginPaint
的HDC
)
- C / C++ 移位/偏移/向左或向右移动位图?
- 如何在快板的屏幕中显示子位图的绘制?
- CreateDIBSection为同一图像返回不一致的位图位值
- C++ 位图中的 ttc 字体
- 使用 GDI+ 旋转位图,然后转换为 HDC
- 难以从 CImageList 设置菜单项位图
- 如何将位图拉伸到父面板(wxWidgets 自定义)
- 如何使用 freetype2 访问单色位图中的像素状态
- 将位图 (bmp) 转换为具有透明度的 png (Windows c++)
- 安卓工作室 |CPP 文件错误错误: 位图库中对"AndroidBitmap_unlockPixels"的未定义引用
- 位图到垫子/2D 数组
- Gdiplus位图没有Alpha通道
- 如何从路径字符串加载Gdiplus::位图
- 在C++中使用Gdiplus创建透明位图
- 用C++压缩内存中的位图
- C++gdi::内存中的位图到PNG图像
- LoadImage 函数不适用于 ImageMagick 创建的位图图像
- (位图)LoadImage() 返回 NULL,GetLastError() 返回 0
- 将Qt qml文件转换为位图图像
- 有没有办法在更改与 HDC 关联的位图大小后更新图形对象?