VC++大数据量绘图时无闪烁刷屏技术实现
void CWaveShowerView::GetScreenRect() { CWnd* pStatic = GetDlgItem(IDC_SCREEN); pStatic->GetWindowRect(&rect); ScreenToClient(&rect); rect.top+=4; rect.left+=4; rect.bottom-=4; rect.right-=4; m_Y0=(rect.bottom-rect.top)/2+rect.top; m_DX=rect.Width(); m_DY=rect.Height()/2; value=new CPoint[m_DX]; } void CWaveShowerView::CleanScreen() { CDC* pDC=GetDC(); CPen pen1(PS_SOLID,1,RGB(0,0,0)); CPen* oldPen1=pDC->SelectObject(&pen1); for(int i=rect.top;i<rect.bottom;i++) { pDC->MoveTo(rect.left,i); pDC->LineTo(rect.right,i); } pDC->SelectObject(&oldPen1); CPen pen2(PS_SOLID,1,RGB(0,0,255)); CPen* oldPen2=pDC->SelectObject(&pen2); pDC->MoveTo(rect.left,m_Y0); pDC->LineTo(rect.right,m_Y0); pDC->SelectObject(&oldPen2); ReleaseDC(pDC); } void CWaveShowerView::DrawPoint(CPoint pt, COLORREF color) { CDC* pDC=GetDC(); pDC->SetPixel(rect.left+pt.x,m_Y0-pt.y,color); ReleaseDC(pDC); } |
接下来,在视类的OnInitialUpdate()初始化函数中添加代码以进行数据显示的各项前期准备工作,并在“打开数据文件”菜单的响应函数中添加代码以读取文件的内码。
void CWaveShowerView::OnInitialUpdate() { CFormView::OnInitialUpdate(); GetParentFrame()->RecalcLayout(); ResizeParentToFit(); GetScreenRect(); for(int i=0;i<m_DX;i++) value[i].x=value[i].y=0; SetTimer(0,10,NULL); } void CWaveShowerView::OnOpenData() { CString FileName=""; CFile file; CFileDialog dlg(TRUE,"*","*.*", OFN_HIDEREADONLYOFN_OVERWRITEPROMPT,"所有文件(*.*)*.*",NULL); if(dlg.DoModal()==IDOK) { KillTimer(1); FileName=dlg.GetPathName(); file.Open(FileName,CFile::modeReadWrite); m_BufLen=file.GetLength(); buffer= new unsigned char[m_BufLen+m_DX+10]; file.Read(buffer,m_BufLen); file.Close(); SetTimer(1,10,NULL); } } |
下面将要添加的定时器响应函数正是本文的重点,为方便对比起见,笔者写了两个OnTimer响应函数,前一个是采用常规的普通方法描点的,运行起来可以很明显地看到画面的闪烁跳动。而后一种则是采用本文所述方法采用的内存画图的方法,运行后几乎画面无闪烁。下面便是两段对比代码的原码部分:
//代码一:有闪烁的代码 void CWaveShowerView::OnTimer(UINT nIDEvent) { if(nIDEvent==0) { CleanScreen(); for(int i=0;i<m_DX;i++) DrawPoint(value[i],RGB(0,255,0)); } if(nIDEvent==1) { m_dx+=2; for(int i=0;i<m_DX;i++) { value[i].x=i; if(m_dx+i<0) buffer[m_dx+i]=128; if(m_dx+i<-m_DX) m_dx-=2; if(m_dx+i>m_BufLen) buffer[m_dx+i]=128; if(m_dx+i>m_BufLen+m_DX) m_dx-=2; value[i].y=m_DY*(buffer[m_dx+i]-128)/256; } } CFormView::OnTimer(nIDEvent); } //代码二:无闪烁的代码 void CWaveShowerView::OnTimer(UINT nIDEvent) { if(nIDEvent==0) { CDC* pDC=GetDC(); CDC dc; CBitmap bitmap; CBitmap* pOldBitmap; CRect client; pDC->GetClipBox(client); //检取无效区 //创建一个与pDC兼容的内存设备环境 if(dc.CreateCompatibleDC(pDC)) { //创建一与pDC兼容的位图,大小为整个客户区 if(bitmap.CreateCompatibleBitmap(pDC,rect.Width(), rect.Height())) { //使dc与pDC具有同样的映射关系 OnPrepareDC(&dc,NULL); //将位图选入内存环境 pOldBitmap=dc.SelectObject(&bitmap); //使dc的整个客户区都成无效区 dc.SelectClipRgn(NULL); //再“与上”检取的无效区,使内存环境与 //pDC检取的无效区相等 dc.IntersectClipRect(client); } } CleanScreen(); for(int i=0;i<m_DX;i++) DrawPoint(value[i],RGB(0,255,0)); dc.SelectObject(pOldBitmap); ReleaseDC(pDC); } if(nIDEvent==1) { m_dx+=2; for(int i=0;i<m_DX;i++) { value[i].x=i; if(m_dx+i<0) buffer[m_dx+i]=128; if(m_dx+i<-m_DX) m_dx-=2; if(m_dx+i>m_BufLen) buffer[m_dx+i]=128; if(m_dx+i>m_BufLen+m_DX) m_dx-=2; value[i].y=m_DY*(buffer[m_dx+i]-128)/256; } } CFormView::OnTimer(nIDEvent); } |
虽然通过上述几步可以实现所有的功能,但为了防止内存泄露和养成良好的编程习惯,我们还须做些工作,在视类的构造函数中释放我们曾经申请过的内存以及定时器:
天极yesky
Tags:
作者:佚名评论内容只代表网友观点,与本站立场无关!
评论摘要(共 0 条,得分 0 分,平均 0 分)
查看完整评论