C++ 使用Win32 API和GDI绘制窗口的无效区域
首先,我是新来的,世界你好 我正在开发一个轻量级控件库。每个控件都是名为“GraphicElement”的类的实例,没有句柄。我创建了一个事件调度器,它按预期工作,但我很难画出我的控件。它们存放在一棵树上,我在穿过这棵树的时候画它们。我还使用了一个后缓冲区来确保窗口的内容不会闪烁 一切正常,但当我移动其中一个控件时,会发生以下情况: 当然,我可以使整个窗口失效并重新绘制,这在理论上解决了我的问题,但我希望避免这样做,尤其是在没有必要的情况下,以及出于性能原因 下面是一个例子: 我想移动R2,然后重新绘制空白点(我指的是R2的旧位置),而不需要重新绘制R4和R5(可能还有其他很多) 如何重新绘制“消失”的背景部分?我是否需要重新绘制整个背景,以及所有控件? 我不会在这里发布我所有的代码,因为它相当长,而且它还处理其他事情,比如事件,但正如我前面所说的,我在遍历树时绘制控件,所以它没有什么疯狂之处 提前感谢您的帮助,如果我不清楚,请原谅 编辑:这里有一些代码,但正如我之前所说的,如果我使窗口的客户端区域无效,它会像一个符咒一样工作,但我想避免这样做 当Windows发送WM_PAINT消息时,将调用此方法(“渲染”):C++ 使用Win32 API和GDI绘制窗口的无效区域,c++,winapi,gdi,C++,Winapi,Gdi,首先,我是新来的,世界你好 我正在开发一个轻量级控件库。每个控件都是名为“GraphicElement”的类的实例,没有句柄。我创建了一个事件调度器,它按预期工作,但我很难画出我的控件。它们存放在一棵树上,我在穿过这棵树的时候画它们。我还使用了一个后缓冲区来确保窗口的内容不会闪烁 一切正常,但当我移动其中一个控件时,会发生以下情况: 当然,我可以使整个窗口失效并重新绘制,这在理论上解决了我的问题,但我希望避免这样做,尤其是在没有必要的情况下,以及出于性能原因 下面是一个例子: 我想移动R2,
m_hdcMem = CreateCompatibleDC(hdc);
m_bmpMem = CreateCompatibleBitmap(hdc, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top);
m_bmpOld = (HBITMAP)SelectObject(m_hdcMem, m_bmpMem);
m_background->predraw(m_hdcMem); // draws the client area, which is an instance of GraphicElement
BitBlt(hdc, m_rect.left, m_rect.top, m_rect.right - m_rect.left, m_rect.bottom - m_rect.top, m_hdcMem, 0, 0, SRCCOPY);
SelectObject(m_hdcMem, m_bmpOld);
DeleteObject(m_bmpMem);
DeleteDC(m_hdcMem);
这里是“预绘制”方法:
我不知道你所说的“轻量级控件没有句柄”是什么意思,但我猜它们是简单的C++类(而不是真的)控件,必须在父窗口的客户端区域绘制。 “问题”在于
WM_PAINT
消息的优先级较低,如果窗口的客户端区域中有无效部分,则在应用程序生成之前发送该消息
您应该首先阅读的文档是:
我建议的实现是两种方法的结合,因为我已经多次使用它,而且效果非常好:
- 处理
消息(以及WM_PAINT
/BeginPaint()
函数)以绘制整个客户端窗口(或其中的一部分,如果需要更“优化”的实现,则使用EndPaint()
结构的PAINTSTRUCT
成员)。请注意,rcPaint
消息的发送可能是由于移动、调整大小、将窗口置于前台或显示先前被另一个窗口遮挡的部分窗口(这是由于用户操作)以及以编程方式使其全部或部分无效。因此,您应该绘制此消息作为响应父窗口及其当前位置的所有控件WM_PAINT
- 使用
/GetDC()
功能仅绘制受添加、删除或移动控件等操作影响的窗口部分。此类绘制立即进行,而不是等待ReleaseDC()
消息发送。您应该填充控件以前占用的区域,并将控件绘制到新位置。您不应该使在客户区域的任何部分注明日期,因为这将导致发送另一条WM_PAINT
消息WM_PAINT
- 控制绘图函数应采用
参数(以及所需的任何其他参数),以便两种绘图方法均可使用(由HDC
或BeginPaint()
函数返回的句柄)GetDC()
另一种更简单的实现方式(仅使用“绘画”而不使用“绘画”)可以是:
- 调整控件大小或移动控件时,仅使控件占用的旧区域和新区域无效
消息的处理通常如上所述,但应进行修改,以便仅填充WM_PAINT
结构的PAINTSTRUCT
成员中的矩形,并仅绘制与上述矩形相交的控件rcPaint
WM_PAINT
消息的优先级较低,如果窗口的客户端区域中有无效部分,则在应用程序生成之前发送该消息
您应该首先阅读的文档是:
我建议的实现是两种方法的结合,因为我已经多次使用它,而且效果非常好:
- 处理
消息(以及WM_PAINT
/BeginPaint()
函数)以绘制整个客户端窗口(或其中的一部分,如果需要更“优化”的实现,则使用EndPaint()
结构的PAINTSTRUCT
成员)。请注意,rcPaint
消息的发送可能是由于移动、调整大小、将窗口置于前台或显示先前被另一个窗口遮挡的窗口部分,这是由于用户操作,以及以编程方式使整个或部分窗口无效。因此,为了响应此消息,您应该在当前位置绘制父窗口和所有控件WM_PAINT
- 使用
/GetDC()
函数仅绘制受添加、删除或移动控件等操作影响的窗口部分。这种绘图是立即进行的,而不是等待<ReleaseDC()
draw(hdc); // draws the current control for (std::vector<GraphicElement*>::iterator it = m_children.begin(); it != m_children.end(); ++it) (*it)->predraw(hdc); // "predraws" the other controls
InvalidateRect(m_parentHwnd, lpRect, FALSE); // If I invalidate the whole window, my code works perfectly, but I'd like to know how to paint parts of my window