gpt4 book ai didi

c++ - 有没有办法在更改与 HDC 关联的位图大小后更新 Graphics 对象?

转载 作者:行者123 更新时间:2023-11-30 04:48:29 24 4
gpt4 key购买 nike

<强>1。问题

我有两个缓冲区。主缓冲区,显示在屏幕上,辅助缓冲区在其中绘制所有内容,然后传递给主缓冲区。

Graphics 对象是从辅助缓冲区创建的,该缓冲区与大小为 800x600 的位图相关联。当然,当您调整窗口大小时,位图的大小也必须更改,以防止出现裁剪问题。辅助 HDC 得到更新,位图被复制到主 HDC。

问题是在与生成剪裁的辅助 HDC 关联的图形对象中留下了一些东西。尽管已更新为更大的区域 (1000x1000),但绘图区域仍保持 800x600。

我的问题是我应该在 Graphics 对象内部更新什么(不必从现有 HDC 显式地重新创建它)以使其绘图区域适合位图大小。

<强>2。我尝试了什么

我尝试的第一件事是从更新的 HDC 重新创建 Graphics 对象。此方法有效并且绘图区域适合位图的大小。然而,它不符合设计标准。图形应该是可重复使用的。

我还尝试使用 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 中当前更新的位图的大小。如代码中所示,位图已正确更新。 Graphics 对象没有。它的行为就像它仍然记得导致此行为的先前 BitMap 中的某些值。

最佳答案

windowHdc = GetDC(hWnd);
HDC secondaryBuffer = CreateCompatibleDC(windowHdc);
HBITMAP map = CreateCompatibleBitmap(windowHdc, width, height);
SelectObject(secondaryBuffer, map);
return secondaryBuffer;
GetDCBeginPaint 获得的

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 即可更新绘图。

对于双缓冲,或在 Canvas 上绘图,您可以创建一个内存位图并重新使用它。如果窗口大小发生变化,则必须为旧位图调用 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 不创建任何东西。它只返回对系统使用的现有句柄的引用。完成此 handle 后,松开它。没有办法进一步优化它。

可以为您的程序创建其他 GDI 对象,如画笔或位图,并且可以重复使用它们。创建/销毁一支笔只需要几纳秒,因此通常不值得增加存储这些对象和跟踪的复杂性。

主要的瓶颈是在屏幕上绘图时,例如画一条线。你必须与显卡和显示器对话,这需要一段时间。您可以使用双缓冲在位图上绘制,然后在屏幕上绘制 BitBltBitBlt 也可能很慢,具体取决于系统。

对于动画,如果您看到闪烁,请使用双缓冲。

为了获得更好的性能,您可以使用更新的技术,例如 Direct2D

如果动画仍然太慢,请考虑使用第二个线程来运行任何数学类型的计算(第二个线程不应引用任何窗口句柄,例如 GetDC 中的 HDC > 或 BeginPaint)

关于c++ - 有没有办法在更改与 HDC 关联的位图大小后更新 Graphics 对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55774506/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com