解决CListCtrl闪烁及水平滚动条不能跟踪拖动的问题(MFC)

原创 2012年03月26日 19:51:50

       项目中用到一个界面如下图所示,在View上有个CPropertySheet,其上有几个CPropertyPage,每个属性页上有个CListCtrl,供用户查看信息。由于CListCtrl中的信息每隔200ms就要刷新一次,导致这个区域不停的闪烁。同时,由于空间不够,CListCtrl上有个水平滚动条,当我们想拉动滚动条到中间位置查看后面几列数据时,刚拉过去就由于刷新又被拉回起点,导致很难查看后面几列数据,我们将这个问题称为水平滚动条不能跟踪问题。本文主要就这两点来记录相关的解决方法。

(1)解决闪烁问题

      我们知道,造成绘图闪烁的原因是因为在每次重绘之前会调用OnEraseBkgnd用背景色对区域进行擦除(默认为白色),导致前后图像反差太大,引起视觉上的闪烁。要去除闪烁,就是要降低这种反差。一种较好的方法就是采用双缓冲绘图,即在内存中开辟一个画布,用来绘图,然后将绘制好的图形复制到设备中显示(http://www.diybl.com/course/3_program/c++/cppjs/200867/123361.html)。另外,防止CListCtrl闪烁的问题,网友也有总结(http://blog.sina.com.cn/s/blog_5ee42ba30100g50j.html)。

     在查阅上述资料,结合本身的问题,设计如下的解决方案,来解决闪烁问题。

    首先,由于显示数据全部在CListCtrl上更新,对于View、CPropertySheet、CPropertyPage而言,并没有什么改动,每次重绘时可以禁止其用背景色擦除区域,减少反差。分别重载这三者的OnEraseBkgnd消息函数,改成 return FALSE;

    其次,对于CListCtrl闪烁的问题,可以采用双缓冲来解决。如下所示:

void CMyListCtrl::OnPaint()
{
	//使用双缓冲的方法绘制背景
	CPaintDC dc(this); // device context for painting
	CRect rect;
	CRect headerRect;
	CDC MenDC;		//内存DC   
	CBitmap MemMap;

	GetClientRect(&rect);    
	GetDlgItem(0)->GetWindowRect(&headerRect);   
	MenDC.CreateCompatibleDC(&dc);   
	MemMap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height()); 
	MenDC.SelectObject(&MemMap);
	MenDC.FillSolidRect(&rect,RGB(255,255,255));   

	//调用默认的OnPaint(),把图形画在内存DC表上   
	DefWindowProc(WM_PAINT,(WPARAM)MenDC.m_hDC,(LPARAM)0);   

	//输出到显示设备
	dc.BitBlt(0,
		headerRect.Height(),   
		rect.Width(),   
		rect.Height(),   
		&MenDC,   
		0,     
		headerRect.Height(),   
		SRCCOPY);   
	MenDC.DeleteDC();
	MemMap.DeleteObject();
}

BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)
{
	// TODO: Add your message handler code here and/or call default

	//return CListCtrl::OnEraseBkgnd(pDC);
	return FALSE;
}
     至此,可解决整体的闪烁问题。

(2)解决水平滚动条不能跟踪问题

      对于这个问题,我一开始比较迷茫,不知道怎么解决,从网上搜了一下,有人提出用GetScrollPos + Scroll,也有人提出用EnsureVisible。第一个方法我试了,主要是记录当前滚动条的位置,然后在刷新后设置到记录的位置,这个方法并不能很好的回到记录的位置,且这样做的话会重新引入闪烁问题(滚动条从记录位置到起始位置再到记录位置,反差很大)。第二种方法貌似只能用于多行,对于多列好像不行。

     于是,我重新思考这个问题。我在程序里的做法是每次刷新时,首先删除所有的行项,然后重新插入包含新数据信息的行项。其实这个行数还是保持不变的,每次更新的只是一些Item的内容而已,于是我想能不能每次只是更新这些数据,不进行行项的删除和重新插入操作,除非有新的行项加入才进行这个操作。如果还无法回到滚动条位置,那么能否根据当前view的视图大小,计算当前需要更新的CListCtrl的Item项,即每次不对所有的Item列项进行更新数据,只对当前View显示视图区域内的内容进行更新(后来发现这点已经不必做了,第一点已经能够解决这个问题)。

      对程序做了更改后,可以实现水平滚动条的跟踪问题。

void UpdateItem()
{
   //......
     CString str;
     BOOL bInsertItem = FALSE;
     if(m_bInsertItem)
     {
        m_bInsertItem = FALSE;
	bInsertItem = TRUE;
	m_listInfo.DeleteAllItems();		//删除原有的数据
     }
     for(i=0; i<CNT; i++)
     {  
        str.Format(_T("%d"), i+1);			//序号
	if(bInsertItem)
	    m_listInfo.InsertItem(i, str);		//插入行,显示序号
	str.Format(_T("ID=%d"), xxx);
	m_listInfo.SetItemText(i, 1, str);
       //插入其他内容......
       //......
     }
} 



版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zwgdft/article/details/7394318

解决CListCtrl闪烁问题

当列表频繁插入数据时,难免会发生闪烁现象,以下使用的重绘的方式解决闪烁,用到的是双缓冲。 接管WM_ERASEBKGND消息,去掉默认的处理,改为不处理,即返回false BOOL CList...
  • rmaly
  • rmaly
  • 2014-03-19 10:11:24
  • 1013

MFC基础知识(四)——双缓冲解决刷屏时闪烁

本文主要介绍:在利用MFC画图或图像显示时,有时候需要调用OnDraw()函数刷新屏幕,而屏幕往往会发生闪烁,本文主要介绍利用双缓冲解决闪屏问题。 关于闪屏方面的介绍分析见博文: http://b...
  • hong__fang
  • hong__fang
  • 2015-03-11 16:34:26
  • 3314

防止CListCtrl闪烁的几种方法

1. 使用SetRedraw禁止窗口重绘,操作完成后,再恢复窗口重绘 m_ctlList.SetRedraw(FALSE); //以下为更新数据操作 //…… //恢复窗口重绘 m_ctlList.S...
  • jiangqin115
  • jiangqin115
  • 2015-04-06 18:15:25
  • 1503

防止CListCtrl闪烁的几种方法实现

网上看到了防止CLIstCtrl 闪烁的方法,挺详细的,就是第五种方法有点问题,做了下修改,就可以用了:1.使用SetRedraw禁止窗口重绘,操作完成后,再恢复窗口重绘m_ctlList.SetRe...
  • lin_angle
  • lin_angle
  • 2011-02-11 11:38:00
  • 2196

clistctrl出现水平滚动条

SetColumnWidth(1,LVSCW_AUTOSIZE_USEHEADER);
  • qdqht2009
  • qdqht2009
  • 2014-08-01 14:03:19
  • 894

MFC中屏幕刷新闪烁问题解决方法总结

在MFC中经常遇到屏幕刷新的问题,下面是几种解决方法。 1,刷新整个程序区域,有明显的闪烁情况     Invalidate( TRUE );     UpdateWindow();  ...
  • longzaitianya1989
  • longzaitianya1989
  • 2014-01-14 16:54:20
  • 11917

List Control的刷新闪烁

List   Control的刷新闪烁,style为ICON,我重写了OnCustomDraw事件,每次刷新对于List的每个item都会调一次OnCustomDraw,这样产生严重的闪烁双缓冲啊,绘...
  • wwwcs59
  • wwwcs59
  • 2009-07-20 18:57:00
  • 2969

MFC List Control快速更新时闪烁问题的解决办法

最近在做一个MFC项目时,需要对List Control控件快速刷新(大概50ms刷新一次)。然而,List Control在刷新时总是不停地闪烁,让人心里很不爽。起初以为是代码的问题,改了很多地方,...
  • swadpro
  • swadpro
  • 2015-05-25 19:27:39
  • 2524

SDK方式防止List Control控件更新闪烁

在WinSDK方式编程时,如果要有较多数据需要定时更新时(如每秒刷新一次),ListControl控件会出现闪烁的情况,下面给出一个解决方法,可以基本消除ListControl控件更新闪烁问题: ...
  • change518
  • change518
  • 2012-05-01 14:50:32
  • 2277
收藏助手
不良信息举报
您举报文章:解决CListCtrl闪烁及水平滚动条不能跟踪拖动的问题(MFC)
举报原因:
原因补充:

(最多只允许输入30个字)