VC双缓冲实现
续前面的聚类算法实验,想要达到可视化的实时更新,并且对聚类的图形进行染色,这里单独开辟一个线程刷新界面,这里为设定一个100ms的计时器不停的invalidate(),然后刷新,这时候发现屏幕上的图形一闪一闪的,或者一行一行的刷新,这样效果不是很理想,这时想到了java里双缓冲的一种实现方法,java中调用repaint()的时候中间会先进行update(),然后在进行paint(),这里MFC调用invalidate()的时候会先调用OnEraseBkgnd(CDC* pDC)函数进行背景填充,然后调用OnDraw(CDC* pDC)函数进行重新绘制。闪烁现象就是因为擦除、重绘这两种的颜色反差导致的,所以这里要取消这种反差。
实现方法就是不进行擦除,每次重绘的时候在内存中绘制出一张和客户区同样大小的图片,背景颜色及为客户区的颜色,其他元素是你绘制上去的,绘制好这么一张图片之后直接利用CDC的BitBlt方法将内存位图绘制在客户区,这样就消除了闪烁,也及实现了双缓冲,聚类算法实验中实现代码如下:
void CDataMiningExample1View::OnDraw(CDC* pDC) { CDataMiningExample1Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 /* int i,length=m_cCluster.m_dataPoints.size(),k=kMeans.size(); //绘制每个点 for (i=0;i<length;i++) { if (m_bEmplify) { m_cCluster.m_dataPoints[i]->drawSelf(pDC); } else { m_cCluster.m_dataPoints[i]->drawNormalSelf(pDC); } } for (i=0;i<k;i++) { kMeans[i]->drawSelf(pDC); } */ CRect rect; GetClientRect(&rect); //获取客户区的大小 CDC dcmem; //创建一个内存DC CBitmap bmp; //创建一个内存位图 dcmem.CreateCompatibleDC(pDC); //创建一个内存DC bmp.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height()); //创建一个内存位图 dcmem.SelectObject(&bmp); //关联内存DC和内存位图 dcmem.FillSolidRect(rect,pDC->GetBkColor());//这个相当于擦除的步骤,背景保持背景颜色 int i,length=m_cCluster.m_dataPoints.size(),k=kMeans.size(); //绘制每个点 for (i=0;i<length;i++) { if (m_bEmplify) { m_cCluster.m_dataPoints[i]->drawSelf(&dcmem); } else { m_cCluster.m_dataPoints[i]->drawNormalSelf(&dcmem); } } for (i=0;i<k;i++) { kMeans[i]->drawSelf(&dcmem); } //以上是绘制部分 pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcmem,0,0,SRCCOPY);//内存位图显示出来 dcmem.DeleteDC(); bmp.DeleteObject();//清理工作 }
BOOL CDataMiningExample1View::OnEraseBkgnd(CDC* pDC) { // TODO: 在此添加消息处理程序代码和/或调用默认值 //return CScrollView::OnEraseBkgnd(pDC); return TRUE; }
以上就是双缓冲的基本实现,其他可以参照。