2012-02-06 130 views
1

我有一个孩子CWind类,在那里我订阅的OnPaint事件的:在闪烁的OnPaint

BEGIN_MESSAGE_MAP(MyListBox, CWnd) 
    ON_WM_PAINT() 
END_MESSAGE_MAP() 

如果在OnPaint处理我画的东西在窗口简单,像边境,一切都很好。但如果我添加Sleep(50);(通过这样做,我模拟一些硬绘制操作),我的窗口将闪烁。我不明白为什么会发生这种情况......可能是问题在于OnPaint函数经常被调用,大约每秒2-3次。

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

UPDATE2:这里是代码:

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); 
} 
+0

请显示复制设备上下文的代码。 – dwo 2012-02-07 20:35:14

回答

1

你的窗口闪烁的原因是因为它试图以显示未画完还的事情。

使用MFC进行绘图时,如果绘图操作不平凡,则需要手动将要绘制的窗口双缓冲。本质上,你想要做的是在内存中创建一个绘图上下文,然后画出来。当绘图完成时,将在内存上下文中找到的内容复制到窗口上下文中。

+0

我忘了说,我正在使用双缓冲... – Seekeer 2012-02-06 09:13:00

+0

我相信问题在于你睡在OnPaint模拟复杂的绘图。如果你使用OnPaint来绘制你想要快速返回的控制权给Windows消息泵。你真的应该在其他地方将图形绘制到你的后台缓冲区,并且在OnPaint方法中,只会将后台缓冲区的内容闪烁到窗口中。 – Dervall 2012-02-06 09:15:41

+0

您建议将“昂贵”的绘图放在助手方法中,并将其称为异步? – Seekeer 2012-02-06 09:25:21

4

默认情况下,通过使用背景画笔清除客户区域来绘制背景。你想关闭它。处理WM_ERASEBKGND并且什么都不做,因为无论如何你都会在任何现有图像的顶部溢出。

另请参阅How to avoid flicker while handling WM_ERASEBKGND in Windows dialog

+0

The问题在于每次发生“OnPaint”时都不会发生闪烁。但是如果我增加'OnPaint'执行时间 - 每次都会发生闪烁。 所以我想这是以某种方式与函数执行时间连接,但为什么 - 那是我不明白的.. 我已经尝试处理'WM_ERASEBKGND'但闪烁仍然存在,无关紧要,我返回TRUE或FALSE .. – Seekeer 2012-02-08 06:20:17

+0

This是正确的答案。如果它没有帮助你,那么你的实现还有其他一些不相关的问题。 MFC中的双缓冲大概有三件事:将所有东西绘制成一个位图(例如'CMemDC'),避免调用基类(或者确保发送'WM_PAINT'消息与缓冲的HDC耦合),返回TRUE 'WM_ERASEBKGND'。 – l33t 2012-02-08 12:18:57

+1

@Seekeer:当然,在blit之前花在'OnPaint'上的时间会影响闪烁,因为这决定了擦除背景在屏幕上的时间。如果在刷新周期中擦除和擦除,擦除的背景永远不会超过视频卡(不会进入物理显示器)。如果在擦除和blit之间存在延迟,则擦除的屏幕将在显示器上出现几帧,并且由用户注意。 – 2012-02-08 14:49:51