在我的绘画功能中,我通过在屏幕上绘制黑色矩形来清晰屏幕,然后绘制一组水平和垂直线以显示一些图形。在我的应用程序中,x轴非常长。所以我使用水平滚动来允许用户在x轴上查看数据。下面是绘制背景和线条的程序的一部分,如上所述。
case WM_PAINT:
HRGN hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
PAINTSTRUCT ps;
if (GetUpdateRgn(m_hWnd, hrgnUpdate, FALSE) != NULLREGION)
{
if (BeginPaint(m_hWnd, &ps))
{
HBRUSH hBr;
hBr = CreateSolidBrush(RGB(0,0,0));
RECT rect;
// Set rect to window size
// Draw black background. This will also work like erasing previous data.
FillRect( m_hDC, &rect, hBr ) ;
COLORREF testColor = RGB(0,255,0);
HPEN hPen = CreatePen(PS_SOLID, 0, testColor);
HPEN hOldPen = (HPEN) SelectObject(m_hDC, hPen);
// Draw Numbers of Horizontal and Vertical lines using MoveToEx and LineTo.
}
EndPaint(m_hWnd, &ps);
}
break;
看来每次我通过拖动滚动条滚动窗口,屏幕都会闪烁。在我看来,当绘制背景时,它会在绘制线条之前立即显示在窗口上,然后绘制线条并显示在屏幕上。
无论如何,只有在绘制完所有线后才能确保所有绘图更新在屏幕上?或者有没有办法延迟背景绘制的效果,直到绘制完所有的线条?
答案 0 :(得分:4)
是使用双缓冲:在窗口中添加WS_EX_COMPOSITED
窗口样式(除其他外,请参阅MSDN)。它可以通过手工完成,也可以在使用CreateCompatibleBitmap()
创建的位图内部绘制所有内容,然后使用BitBlt()
将其内容复制到屏幕DC。
此外,您正在为每个绘画事件创建一个新画笔,这在资源和时间方面都是一个非常广泛的任务。只需创建一次,例如在WM_CREATE
处理程序中,并在每个WM_PAINT
中重复使用它(当然它不是强制性的,现在可能你没有看到任何差异;如果你不&# 39;然后不要忘记致电DeleteObject()
释放他们):
case WM_CREATE:
// Add your existing code for this event
hBackgroundBrush = CreateSolidBrush(RGB(0, 0, 0));
hForegroundPen = CreatePen(PS_SOLID, 0, RGB(0, 255, 0));
break;
您的代码尚未完成,所以我不能说,但您还应该释放已分配的资源(并恢复绘图对象)。
正如大卫在评论中指出的那样,你不应该混合前景和背景画。它现在完成的方式是首先绘制背景(按窗口本身),然后用WM_PAINT
消息(FillRect()
)删除。您有两种方法可以改进:在适当的位置处理背景绘制(然后,如注释中建议的,在WM_ERASEBKGRND
事件处理程序内)或避免Windows绘制控件背景并在WM_PAINT
内执行所有操作事件处理程序让我们看看两者:
case WM_ERASEBKGND:
{
GetClientRect(m_hWnd, &rect);
FillRect((HDC)wParam), &rect, hBackgroundBrush);
return (LRESULT)1;
}
case WM_PAINT:
{
HRGN hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
PAINTSTRUCT ps;
if (GetUpdateRgn(m_hWnd, hrgnUpdate, FALSE) != NULLREGION) {
if (BeginPaint(m_hWnd, &ps)) {
HPEN hOldPen = (HPEN)SelectObject(m_hDC, hForegroundPen);
// Do painting here
SelectObject(m_hDC, hOldPen);
EndPaint(m_hWnd, &ps);
}
}
break;
}
第二种情况在某种程度上更简单,只是对WM_ERASEBKGND
不执行任何操作(但通知Windows您处理了这种情况)并按原样保留WM_PAINT
:
case WM_ERASEBKGND:
return (LRESULT)1;
case WM_PAINT:
{
HRGN hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
PAINTSTRUCT ps;
if (GetUpdateRgn(m_hWnd, hrgnUpdate, FALSE) != NULLREGION) {
if (BeginPaint(m_hWnd, &ps)) {
FillRect(m_hDC, &rect, hBackgroundBrush);
HPEN hOldPen = (HPEN)SelectObject(m_hDC, hForegroundPen);
// Do painting here
SelectObject(m_hDC, hOldPen);
EndPaint(m_hWnd, &ps);
}
}
break;
}