Winapi 在油漆上闪烁

Winapi 在油漆上闪烁,winapi,visual-c++,mfc,gdi,Winapi,Visual C++,Mfc,Gdi,我有一个CWind班的孩子,我正在订阅OnPaint活动: BEGIN_MESSAGE_MAP(MyListBox, CWnd) ON_WM_PAINT() END_MESSAGE_MAP() 若在OnPaint处理程序中,我在窗口中绘制一些简单的东西,比如边框,那个么一切都很好。但是如果我加上睡眠(50)(通过这样做,我模拟了一些硬绘图操作)我的窗口将闪烁。我不明白为什么会这样。。。可能的问题是OnPaint函数经常被调用,大约每秒调用2-3次 更新:我正在使用双分叉:首先我在Pai

我有一个CWind班的孩子,我正在订阅OnPaint活动:

BEGIN_MESSAGE_MAP(MyListBox, CWnd)
    ON_WM_PAINT()
END_MESSAGE_MAP()
若在OnPaint处理程序中,我在窗口中绘制一些简单的东西,比如边框,那个么一切都很好。但是如果我加上睡眠(50)(通过这样做,我模拟了一些硬绘图操作)我的窗口将闪烁。我不明白为什么会这样。。。可能的问题是OnPaint函数经常被调用,大约每秒调用2-3次

更新:我正在使用双分叉:首先我在PaintDeviceContent中绘制窗口内容,然后将此DC复制到窗口的DC

更新2:以下是代码:

void CDirectionsListBox::OnPaint() 
{ 
    CRect rectClient;
    GetClientRect(rectClient);

    CPaintDC dc(this); // device context for painting

    CDC DCMem;
    DCMem.CreateCompatibleDC( &dc );

    // Draw window here, workign with DCMem

    dc.BitBlt(0, 0, rectClient.Width(), rectClient.Height(), &DCMem, 0, 0, SRCCOPY);
}

窗口闪烁的原因是它试图显示尚未完成绘制的内容


当使用MFC绘图时,如果绘图操作非常简单,则需要手动将正在绘制的窗口缓冲到两倍。本质上,您要做的是在内存中创建一个绘图上下文,并以此为基础进行绘图。绘制完成后,您可以将内存上下文中的内容复制到窗口上下文中。

默认情况下,通过使用背景笔刷清除客户端区域来绘制背景。你想把它关掉。处理
WM_ERASEBKGND
并且什么也不做,因为您无论如何都要在任何现有图像的顶部进行blit


另请参见

我相信问题在于你睡在OnPaint中模拟复杂的绘图。如果使用OnPaint绘制,则希望它快速返回以将控制权交还给windows消息泵。您真的应该在其他地方对backbuffer进行绘图,并且在OnPaint方法中,只将backbuffer内容blit到窗口。您建议将“昂贵”的绘图放在helper方法中,并将其称为异步?这确实取决于您的应用程序需要,但可能是。没有理由使其异步。只是不要在擦除和blit之间进行复杂的渲染。避免这种情况的最佳方法是完全消除擦除,但在
OnPaint
开始时快速删除旧图像也会达到预期效果(以浪费GPU带宽为代价,用于擦除和重新照亮现有数据)请在复制设备上下文的位置显示代码。问题是,并非每次发生
OnPaint
时都会出现闪烁。但是如果我增加执行时间,每次都会出现闪烁。所以我想这与函数执行时间有某种联系,但为什么-这是我无法理解的。。我试过处理
WM_ERASEBKGND
但仍然闪烁,不管我返回的是真是假……这是正确的答案。如果它对您没有帮助,那么您的实现还有一些其他不相关的问题。MFC中的双缓冲主要涉及三个方面:将所有内容绘制成位图(例如,
CMemDC
),避免调用基类(或者确保
WM_PAINT
消息与缓冲的HDC一起发送),从
WM_ERASEBKGND
@Seekeer返回TRUE:当然,在blit影响闪烁之前,您在
OnPaint
中花费的时间,因为这决定了被擦除的背景在屏幕上的时间。如果在刷新周期中同时擦除和blit,则被擦除的背景不会超出视频卡的范围(不会进入物理显示)。如果在擦除和blit之间有延迟,则屏幕上会出现已擦除的屏幕数帧,并且用户可以注意到。