首先,我是新来的,所以你好世界!
我正在开发一个轻量级的控件库。每个控件都是名为“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);
这是方法“predraw”:
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
答案 0 :(得分:1)
我不知道“没有句柄的轻量级控件”是什么意思,但我猜它们是简单的C ++类(而不是真正的“控件”)必须在父窗口的客户区域上绘制。
“问题”是WM_PAINT
消息是低优先级消息,如果窗口在其客户区域中具有无效部分,就在应用程序产生之前发送。
您应首先阅读的文档是: Painting and Drawing
我建议的实现,因为我已经使用了很多次并且工作得很好,是两种方法的组合:
WM_PAINT
消息(以及BeginPaint()
/ EndPaint()
函数)以使用rcPaint
成员绘制整个客户端窗口(或其中的一部分) PAINTSTRUCT
结构,如果需要更“优化”的实现)。请注意,WM_PAINT
消息可能会因为移动,调整大小,将窗口置于前台,或者显示先前被另一个窗口遮挡的窗口的一部分而发送,这是由于用户操作,除了以编程方式使其全部或部分无效。因此,为了响应此消息,您应该绘制父窗口和当前位置的所有控件。GetDC()
/ ReleaseDC()
函数仅绘制受添加,删除或移动控件等操作影响的窗口部分。这种绘图立即发生,而不是等待发送WM_PAINT
消息。您应填充控件先前占用的区域,并将控件绘制到新位置。您不应该使客户区的任何部分无效,因为这会导致发送另一条WM_PAINT
消息。HDC
参数(在任何其他需要的参数中),以便两种绘图方法(BeginPaint()
或{{1]返回的句柄可用功能)。我已经使用这种技术制作图像处理应用程序(例如让用户选择图像的一部分并绘制/恢复选定的矩形)和无人值守的监视器应用程序。
另一种更简单的实现(仅使用“绘画”但不使用“绘图”)可以是:
GetDC()
消息,但应对其进行修改,以便仅填充WM_PAINT
结构的rcPaint
成员中的矩形,并仅绘制控件与上面的矩形相交。