关于屏幕闪烁的问题

UmbrellaCEO 2003-02-12 02:19:08
当我快速刷新窗口内容的时候会出现严重闪烁的情况,如果才能避免呢?
例如:
unsigned int i=0;
while(i++<30000)
{
//此处在窗口上显示i的值
}
...全文
38 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
zswzwy 2003-02-12
  • 打赏
  • 举报
回复
闪屏问题及刷新效率
2003-01-01(Kang)
1 简单过程描述
在视图(Cview及其子类)每次重绘的过程中,都调用OnDraw( )函数。在调用Invalidate()、InvalidateRect()函数过程后,系统自动调用OnDraw()函数,完成视图的刷新显示。以InvalidateRect(LPCRECT lpRect, BOOL bErase = TRUE)为例说明简单过程,调用InvalidateRect()后,系统判断指定的矩形lpRect是否在视图的显示范围(滚动视图显示区域)内,如果在,就调用OnDraw()函数执行重绘,重绘后按照lpRect指针所指向的矩形指定的无效区域进行视图更新。
视图的更新需要一部分时间,所以我们要考虑减小视图每次更新矩形的区域,也就是减小InvalidateRect()中第一个参数lpRect的大小。所以我们应该在需要刷新时,计算刷新矩形的大小,然后调用InvalidateRect()函数。
2 闪屏问题的解决
闪屏问题的解决办法是采用双缓冲技术。即创建与设备DC兼容的位图,在位图中绘制,然后Copy到屏幕上。注意,要重载BOOL CDrawView::OnEraseBkgnd(CDC*)函数,返回TRUE;

BOOL CDrawView::OnEraseBkgnd(CDC*)
{
return TRUE;
}
不多叙述。
3 刷新效率
我们最理想的刷新元件的思路就是每次只绘制那些在无效矩形区域内的元件,其余的部分不变。实际的情况是我们在调用OnDraw()函数时,必须遍历所有的元件,然后根据情况选择重绘的元件,将其显示。有两种方法可以选择,一是遍历每个元件的时候判断它是否位于裁减区域内(其对应于无效矩形区域),如在就绘制,否则不进行绘制;第二种方法,思路差不多,是创建一个与裁减矩形同样大小的位图,在位图DC上绘制所有元件,这个在绘制时,超出位图矩形大小的元件就不被绘制,判断元件是否超出位图矩形的工作有系统来做。两种方法效率应该差不多,但第二种方法实现简便,效率相对优于第一种方法。
曾进行过如下测试:
每次无效矩形Crect(0,0,100,100)
for (int k=0; k<100 0000; k++)
{
pDrawDC->Rectangle(100,100,150,150);
}
在无效矩形外,执行1000,000次绘矩形操作,略有延迟。其实,循环体内,只进行的是系统的判断工作,没有绘制。
证明方法可行。
4实现过程的描述
为消除闪屏和充分考虑绘图效率,采用如下方法。
将每次要更新的矩形绘制在位图中,然后将其复制到OnDraw()函数的pDC中;每次执行元件移动,创建等操作时,定义无效矩形,调用InvalidateRect(rect,FALSE)函数。只有当视图ReSize时才全部元件重绘,效率能够得到足够的保证。
重载OnDraw()函数
CDC dc;
CDC* pDrawDC = pDC;
CBitmap bitmap;
CBitmap* pOldBitmap;

// only paint the rect that needs repainting
CRect client;
pDC->GetClipBox(client);
CRect rect = client;

DocToClient(rect);

if (!pDC->IsPrinting())
{
// draw to offscreen bitmap for fast looking repaints
if (dc.CreateCompatibleDC(pDC))
{
if (bitmap.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height()))
{
OnPrepareDC(&dc, NULL);
pDrawDC = &dc;

// offset origin more because bitmap is just piece of the whole drawing
dc.OffsetViewportOrg(-rect.left, -rect.top);
pOldBitmap = dc.SelectObject(&bitmap);
dc.SetBrushOrg(rect.left % 8, rect.top % 8);

// might as well clip to the same rectangle
dc.IntersectClipRect(client);
}
}
}

// paint background
CBrush brush;
if (!brush.CreateSolidBrush(pDoc->GetPaperColor()))
return;

brush.UnrealizeObject();
pDrawDC->FillRect(client, &brush);

if (!pDC->IsPrinting() && m_bGrid)
DrawGrid(pDrawDC);

pDoc->Draw(pDrawDC, this);

if (pDrawDC != pDC)
{
pDC->SetViewportOrg(0, 0);
pDC->SetWindowOrg(0,0);
pDC->SetMapMode(MM_TEXT);
dc.SetViewportOrg(0, 0);
dc.SetWindowOrg(0,0);
dc.SetMapMode(MM_TEXT);
pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(),
&dc, 0, 0, SRCCOPY);
dc.SelectObject(pOldBitmap);
}
UmbrellaCEO 2003-02-12
  • 打赏
  • 举报
回复
是这样的,我在编一个文件处理的程序,在写文件的时候需要一个象进度指示器一样的东西,但又不想用进度条,只能以“已处理的字节数”来表示,所以需要不断地在屏幕上输出数据。
fingerfox 2003-02-12
  • 打赏
  • 举报
回复
Invalidate(false);
问一下
这么干有意义麽?

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧