c - 在窗口的某些区域绘制矩形导致屏幕闪烁

标签 c windows winapi

在我的绘画功能中,我通过在屏幕上绘制黑色矩形来获得清晰的屏幕,然后绘制一组水平和垂直线来显示一些图形。在我的应用程序中,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/

相关文章:

c - 如何使用 esp_bt_gap_read_rssi_delta 函数从 ESP32 获取蓝牙经典 RSSI?

c - 这是在 C 中创建数组的有效方法吗?

java - 了解用于 Java 转换的部分 C 代码

C11threads.h库

C++:在 Windows 上使用 C++ 读写 BMP 文件的最简单方法是什么?

c - 使用c通过tcp套接字处理图像

windows - git添加错误: Could not open directory: Permission Denied

python - 从 python 源构建 Windows 可执行文件

c - 如何从 C 代码中的 SystemInformation::KeyboardSpeed (Windows API) 获取值?

c++ - Win32 : How to access Windows Listview Header Control Filters