CListView自画表格线,频繁插入导致表格线闪烁,讨论和解决

尘雨 2006-12-29 10:13:00
环境:SDI程序,View的基类是CListView.显示方式是Report,不使用Grid网格样式
ListView里只有2列
1.在View中设置一个定时器,每10毫秒或者50毫秒插入项,插入的位置是0,最上面
2.在没有网格的情况下,CListView会闪烁,原因在于显示2列的区域会先被擦除为背景色,然后再写项,通过重写OnEraseBackground,时之在填充背景色的时候只填充Client区域排除2列所占区域的区域,而不对2列所占区域进行重绘。解决了
第二条的闪烁问题,使用SetRedraw是不能解决的。请注意这一点

3。增加listview的网格样式,出现闪烁,表格线在闪烁。此时的闪烁与第二条无关,即使OnEraseBackground改为return TRUE也不能消除,说明与擦除背景无关
于是,重写OnPaint,不使用网格样式,而是通过绘图方式,首先使用默认的基类OnPaint,把项的文字部分显示,然后开始绘制表格,只绘制在当前可视的范围。此方法属于自画表格。但是问题依旧。再次更改,使用双缓冲绘制,先在memdc中绘制好表格,然后把该memdc与clientdc的相对应区域(此时该区域的文字绘制已经由基类的OnPain完成)进行SRCPAINT进行处理,实现两个DC叠加,
但是仍然会有一定闪烁。

欢迎高手参与讨论或者帮忙提出解决方案,再次感谢。
也请贴网址的高手注意,该问题的目的是解决自画表格线的情况下频繁在顶端插入数据时的闪烁,或者是使用grid样式时,频繁插入数据导致闪烁。如果贴出的网址代码,确实包含了该问题的解决,就最好。也请大家说两句。让我们这些初学者多学习学习

...全文
475 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
尘雨 2006-12-30
  • 打赏
  • 举报
回复
问题还在解决中,这两天太忙估计到一月份结贴
Elysium 2006-12-29
  • 打赏
  • 举报
回复
学习
会思考的草 2006-12-29
  • 打赏
  • 举报
回复
映射WM_ERASEBKGND,注释掉对父类函数的调用直接返回TRUE。用这个方法请注意在绘制之前擦除上一次的东西。推荐这个方法和memory dc一起用,这样就不需要计算哪些东西要擦除哪些不要擦除了。
尘雨 2006-12-29
  • 打赏
  • 举报
回复
谢谢楼上的,明天上班我测试一下,你和我今天的一个思路有点类似,不过你的代码更细致一些
crumpy 2006-12-29
  • 打赏
  • 举报
回复
用NM_CUSTOMDRAW试过吗?
尘雨 2006-12-29
  • 打赏
  • 举报
回复
本人的想法是写一个可以在频繁增加数据的时候不会产生闪烁的CListView,目前的大多数源代码例子注重ListView的各种功能和样式上。
而我的需求则侧重这一点,相信大多数作通信开发或者数据库开发的朋友应该都知道使用CListView和CEdit显示实时数据时的问题。
抛砖引玉,希望能有启发式的想法能够看到
尘雨 2006-12-29
  • 打赏
  • 举报
回复
ListView的Grid样式的表格线也是有闪烁问题,我自画的原因第一试图解决闪烁,第二默认的网格样式不好看,我用dc.MoveTo;dc.LineTo来画,因为只画有列的并且在当前可见的视区域,所以效率是可以接受的
yjgx007 2006-12-29
  • 打赏
  • 举报
回复
表格线也是自画的?
一分之千 2006-12-29
  • 打赏
  • 举报
回复
双缓存使用这种方法试试~
void CxxxView::OnInitialUpdate()
{
...
if (m_pdcMemory->GetSafeHdc() == NULL) {
CClientDC dc(this);
OnPrepareDC(&dc);
... m_pdcMemory->CreateCompatibleDC(&dc);
// makes bitmap same size as display window
m_pBitmap->CreateCompatibleBitmap(&dc, rectMax.right,
rectMax.bottom);
}
}


void CxxxView::OnPaint()
{
CPaintDC dc(this); // device context for painting
OnPrepareDC(&dc);
CRect rectUpdate;
dc.GetClipBox(&rectUpdate);
CBitmap* pOldBitmap = m_pdcMemory->SelectObject(m_pBitmap);
m_pdcMemory->SelectClipRgn(NULL);
m_pdcMemory->IntersectClipRect(&rectUpdate);
CBrush backgroundBrush((COLORREF) ::GetSysColor(COLOR_WINDOW));
CBrush* pOldBrush = m_pdcMemory->SelectObject(&backgroundBrush);
m_pdcMemory->PatBlt(rectUpdate.left, rectUpdate.top,
rectUpdate.Width(), rectUpdate.Height(),
PATCOPY);
OnDraw(m_pdcMemory);
dc.BitBlt(rectUpdate.left, rectUpdate.top,
rectUpdate.Width(), rectUpdate.Height(),
m_pdcMemory, rectUpdate.left, rectUpdate.top,
SRCCOPY);
m_pdcMemory->SelectObject(pOldBitmap);
m_pdcMemory->SelectObject(pOldBrush);
}
尘雨 2006-12-29
  • 打赏
  • 举报
回复
楼上的想法从另外一个角度考虑,是一个可以折中解决的方案。值得借鉴。

至于表格线的闪烁问题,已经找到。

1。当item增加的时候,列表框的其他记录也一起向下滚动,item的文字和这个item的背景被绘制,其他项目也相应向下重新绘制。
2。此时我再画网格线的时候是正常的,但由于item的文字部分的背景色并非是透明的,在下一个绘制的时候,这个item的背景色遮盖了原先的网格线,其后再次绘制网格线,交替作用下,网格线的闪烁产生了,此时文字和文字背景没有产生闪烁。

由于listview的WM_ERASEBKGND消息我已经处理过了。但每个item的文字背景却不受此影响,依然会再绘制的时候覆盖上次画上的网格线。问题的关键在于如何处理item的文字背景时之比其所在rect要小一些,不会覆盖网格线,或者是item的文字背景想办法处理成透明的。

明天再试试,可否解决
会思考的草 2006-12-29
  • 打赏
  • 举报
回复
如果是这种快速的插入删除,可以借鉴cache的思想,不要每次有改动就执行真正的插入删除并重绘,可以设定一个缓存,记录下插入删除的操作,譬如大小为100个,每100个操作就重绘一次。
会思考的草 2006-12-29
  • 打赏
  • 举报
回复
如果是这种快速的插入删除,可以借鉴cache的思想,不要每次有改动就执行真正的插入删除并重绘,可以设定一个缓存,记录下插入删除的操作,譬如大小为100个,每100个操作就重绘一次。
尘雨 2006-12-29
  • 打赏
  • 举报
回复
楼上的想法不错,可能大多数时候,我们不需要那么频繁的更新,一秒一次是可以的。
我这里用timer是为了模拟如果是通信服务端,显示数据传输的时候,子线程通过Post消息方式来显示信息。通信的频繁的时候,肯定要少于一秒的。

使用timer的目的仅仅是为了模拟快速插入项的这种情况
dirdirdir3 2006-12-29
  • 打赏
  • 举报
回复
插入的时候不更新,每一秒钟才更新一次表格会好点吧
尘雨 2006-12-29
  • 打赏
  • 举报
回复
映射WM_ERASEBKGND,注释掉对父类函数的调用直接返回TRUE。用这个方法请注意在绘制之前擦除上一次的东西。推荐这个方法和memory dc一起用,这样就不需要计算哪些东西要擦除哪些不要擦除了
------------------------------------------------------------------------------------你的意思是我在绘制表格的时候,原先的有表格的地方要擦除掉?这个问题我要测试一下。

此外customdraw的处理,我大概测试了一下,发现当列表框开始滚动的时候,

pLVCD->nmcd.dwDrawStage这个始终是1,也就是CDDS_PREPAINT

此时绘制表格的时机还要继续捉摸


15,979

社区成员

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

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