在我的绘画功能中,我通过在屏幕上绘制黑色矩形来获得清晰的屏幕,然后绘制一组水平和垂直线来显示一些图形。在我的应用程序中,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;
似乎每次我通过拖动滚动条滚动窗口时,屏幕都会闪烁。在我看来,当绘制背景时,它会在绘制线条之前立即显示在窗口上,然后绘制线条并显示在屏幕上。
是否有办法确保只有在绘制完所有线条后屏幕上的所有绘图才会更新?或者有什么办法可以延迟背景绘制的效果,直到所有线条都绘制完成?
最佳答案
是,使用双缓冲:将 WS_EX_COMPOSITED
窗口样式添加到您的窗口(除其他外,请参阅 MSDN )。它也可以手动完成,绘制使用CreateCompatibleBitmap()
创建的位图中的所有内容,然后使用BitBlt()
将其内容复制到屏幕DC .
此外,您要为每个绘画事件创建一个新画笔,这在资源和时间方面都是一项相当广泛的任务。仅创建一次,例如在 WM_CREATE
处理程序中创建它,并在每个 WM_PAINT
中重用它(当然这不是强制性的,现在您可能不会看到任何差异;如果您不这样做,请不要忘记调用 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;
}
关于c - 在窗口的某些区域绘制矩形导致屏幕闪烁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23130735/