续前面的聚类算法实验,想要达到可视化的实时更新,并且对聚类的图形进行染色,这里单独开辟一个线程刷新界面,这里为设定一个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;
}
以上就是双缓冲的基本实现,其他可以参照。