博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
解决CListCtrl闪烁及水平滚动条不能跟踪拖动的问题
阅读量:5106 次
发布时间:2019-06-13

本文共 2442 字,大约阅读时间需要 8 分钟。

分类: 
 
3007人阅读 
(4) 
 

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

(1)解决闪烁问题

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

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

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

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

 

[cpp] 
 
  1. void CMyListCtrl::OnPaint()  
  2. {  
  3.     //使用双缓冲的方法绘制背景  
  4.     CPaintDC dc(this); // device context for painting  
  5.     CRect rect;  
  6.     CRect headerRect;  
  7.     CDC MenDC;      //内存DC     
  8.     CBitmap MemMap;  
  9.   
  10.     GetClientRect(&rect);      
  11.     GetDlgItem(0)->GetWindowRect(&headerRect);     
  12.     MenDC.CreateCompatibleDC(&dc);     
  13.     MemMap.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());   
  14.     MenDC.SelectObject(&MemMap);  
  15.     MenDC.FillSolidRect(&rect,RGB(255,255,255));     
  16.   
  17.     //调用默认的OnPaint(),把图形画在内存DC表上     
  18.     DefWindowProc(WM_PAINT,(WPARAM)MenDC.m_hDC,(LPARAM)0);     
  19.   
  20.     //输出到显示设备  
  21.     dc.BitBlt(0,  
  22.         headerRect.Height(),     
  23.         rect.Width(),     
  24.         rect.Height(),     
  25.         &MenDC,     
  26.         0,       
  27.         headerRect.Height(),     
  28.         SRCCOPY);     
  29.     MenDC.DeleteDC();  
  30.     MemMap.DeleteObject();  
  31. }  
  32.   
  33. BOOL CMyListCtrl::OnEraseBkgnd(CDC* pDC)  
  34. {  
  35.     // TODO: Add your message handler code here and/or call default  
  36.   
  37.     //return CListCtrl::OnEraseBkgnd(pDC);  
  38.     return FALSE;  
  39. }  
     至此,可解决整体的闪烁问题。

 

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

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

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

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

 

[cpp] 
 
  1. void UpdateItem()  
  2. {  
  3.    //......  
  4.      CString str;  
  5.      BOOL bInsertItem = FALSE;  
  6.      if(m_bInsertItem)  
  7.      {  
  8.         m_bInsertItem = FALSE;  
  9.     bInsertItem = TRUE;  
  10.     m_listInfo.DeleteAllItems();        //删除原有的数据  
  11.      }  
  12.      for(i=0; i<CNT; i++)  
  13.      {    
  14.         str.Format(_T("%d"), i+1);         //序号  
  15.     if(bInsertItem)  
  16.         m_listInfo.InsertItem(i, str);      //插入行,显示序号  
  17.     str.Format(_T("ID=%d"), xxx);  
  18.     m_listInfo.SetItemText(i, 1, str);  
  19.        //插入其他内容......  
  20.        //......  
  21.      }  
  22. }   

 

转载于:https://www.cnblogs.com/danxin5/p/3768368.html

你可能感兴趣的文章
UseIIS
查看>>
为什么int型最大的数是2147483647
查看>>
数据库连接的三层架构
查看>>
集合体系
查看>>
vi命令提示:Terminal too wide
查看>>
nyoj 5 Binary String Matching(string)
查看>>
引用 移植Linux到s3c2410上
查看>>
BizTalk 2010 单机安装
查看>>
人与人之间的差距是从大学开始的
查看>>
vue 开发过程中遇到的问题
查看>>
[Swift]LeetCode341. 压平嵌套链表迭代器 | Flatten Nested List Iterator
查看>>
[Swift]LeetCode223. 矩形面积 | Rectangle Area
查看>>
[Javascript] Identify and Deal with NaN in JavaScript
查看>>
MySQL5.7开多实例指导
查看>>
贪心——洛谷P1016 旅行家的预算
查看>>
【学习整理】树状数组 区间修改+查询
查看>>
你知道电脑硬盘怎么分区吗?
查看>>
去除Visual Studio引号中的内容和注释中出现的波浪下划线
查看>>
C#多线程方法 可传参
查看>>
[zz]一个简单加密病毒的框架
查看>>