【发布时间】:2017-10-05 03:32:31
【问题描述】:
首先,我是新来的,所以你好!
我正在开发一个小型轻量级控件库。每个控件都是名为“GraphicElement”的类的一个实例,并且没有句柄。我创建了一个事件调度程序,它按预期工作,但我在绘制控件时遇到了困难。它们存放在一棵树上,当我穿过这棵树时,我会画它们。我还使用后台缓冲区来确保窗口的内容不会闪烁。
一切正常,但是当我移动其中一个控件时,会发生这种情况:
.
当然,我可以使整个窗口无效并重新绘制,这从理论上解决了我的问题,但我想避免这样做,尤其是在没有必要和性能原因时。
这是一个例子:
我想移动 R2,然后重新绘制空白点(我指的是 R2 的旧位置)而不重新绘制 R4 和 R5(可能还有许多其他位置)。
如何重新绘制“消失”的背景部分?我是否必须重新绘制整个背景,以及我的所有控件? 我不会在这里发布我的所有代码,因为它很长,而且它还处理其他事情,如事件,但正如我之前所说,我在遍历树时绘制我的控件,所以它没有什么疯狂的。
提前感谢您的帮助,如果我不清楚,请见谅。
编辑:这是一些代码,但正如我之前所说,如果我使窗口的客户区无效,它就像一个魅力,但我想避免这样做。
当 Windows 发送 WM_PAINT 消息时调用此方法(“render”):
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);
这是“预绘制”方法:
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
【问题讨论】:
-
没有代码我们无法告诉你你做错了什么。
-
改进不大。创建minimal reproducible example。
-
代码真的很长,拆分成多个文件,很难把它压缩成一个“最小”的例子,但我会试一试......
-
您在正确的轨道上,但是您忘记了使 R2 曾经是的屏幕部分无效。否则屏幕的该部分将不会重绘,因此仍会显示 R2 的剩余部分。
-
非常感谢您的评论。如果我理解正确,我将不得不重绘那部分背景以及 R1 和 R3。如果我设置背景图像怎么办?这是否意味着每次在窗口上移动某些东西时我都必须重新绘制它?或者我可以使用 BitBlt 绘制它的一部分?以及如何有效地检测重叠矩形?