MFC编程,Cview类OnDraw重绘时,视图内容消失问题的解决

来源:互联网 发布:常州巨人网络待遇 编辑:程序博客网 时间:2024/05/19 14:17

      问题描述:在进行MFC绘图编程时(以简单的绘制线条为例),视图窗口的大小变化会引起调用OnDraw()。默认的OnDraw()会重绘显示出一个空白的视图,因此必须重写这个方法以显示文档的视图。

   解决思路:通过查阅资料发现,这种问题通常的处理方法是在文档中记录绘图数据,在窗口重绘时使用这些数据恢复图像。我认为使用这种方法时,在绘图的同时考虑记录数据将增加不少代码复杂度(因我了解的不够及水平有限,这种观点可能有误),同时在复杂的图像所需要记录的数据量将很大。另外,还有一种“内存缓存画图”的方式,考虑到MFC时 文档/视图 类,视图CView负责数据的显示和修改,文档CDocument类负责数据的存储和加载,从而把数据管理和显示方法分离开来。我们在CDocument类中添加一个CBitMap对象,将每次中间绘图时的客户区的内容保存成BitMap,当所有的操作都执行好以后,将最终的BitMap拷贝到屏幕中,这就是所谓的内存缓存画图方式。我比较倾向于用这种方式解决重绘问题,但我所查到的网上所提供的代码都只能解决绘图时的“闪烁”问题(参考搜索“C++双缓冲绘图”)。因此我基于后者的缓冲绘图思想,以绘制线条为例,编写代码解决重绘问题。
具体实现过程及代码如下(工程名为LocateByLh):
1、在CLocateByLhDoc类中创建CBitmap类型的m_bmpBuf用于保存视图(同时也可以用于缓冲绘图),同时在CLocateByLhView类中添加一个bool型变量。
public:CBitmap m_bmpBuf;
/////////////////////////
private:bool bFlag;
/////////////////////////
2、在OnDraw()方法内添加m_bmpBuf输出代码和只在首次执行的m_bmpBuf初始化代码(设置bFlag就是为了只执行一次)。
void CLocateByLhView::OnDraw(CDC* pDC){CLocateByLhDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data here
//重绘显示bitmap,思路是创建一个临时的dcMem,先把m_bmpBuf作为画布放入其中,然后拷贝到pDC中显示出来
CDC dcMem;CRect rect;GetClientRect(&rect);dcMem.CreateCompatibleDC(NULL);dcMem.SelectObject(&pDoc->m_bmpBuf);pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);dcMem.DeleteDC();
//初始化一个白色填充的m_bmpBuf,
if(bFlag){CLocateByLhDoc *pDoc = GetDocument();CDC dcMem2;dcMem2.CreateCompatibleDC(NULL);pDoc->m_bmpBuf.CreateCompatibleBitmap(pDC,2500,1500);dcMem2.SelectObject(&pDoc->m_bmpBuf);dcMem2.FillSolidRect(0,0,2500,1500,RGB(255,255,255));dcMem2.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);dcMem2.DeleteDC();bFlag=false;}}
3、鼠标左键弹起事件中的绘图线条代码,
void CLocateByLhView::OnLButtonUp(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultCLocateByLhDoc *pDoc = GetDocument();CDC* pDC = GetDC();CDC dcMem;CRect rect;GetClientRect(&rect);dcMem.CreateCompatibleDC(NULL);
//注释部分采用的是非缓冲画图,直接用pDC进行绘图,然后复制到m_bmpBuf//CPen pen(PS_SOLID,2,RGB(255,0,0));//pDC->SelectObject(&pen);//pDC->MoveTo(m_ptOrigin);//pDC->LineTo(point);//dcMem.SelectObject(&pDoc->m_bmpBuf);
//dcMem.BitBlt(0,0,rect.Width(),rect.Height(),pDC,0,0,SRCCOPY);
//在虚拟的dcMem中绘图,然后一次性输出显示,同时更新了m_bmpBufdcMem.BitBlt(0, 0, rect.Width(), rect.Height(), pDC, 0, 0, SRCCOPY);dcMem.SelectObject(&pDoc->m_bmpBuf);dcMem.MoveTo(m_ptOrigin);//绘制线条代码dcMem.LineTo(point);//绘制线条代码pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,SRCCOPY);dcMem.DeleteDC();ReleaseDC(pDC);CView::OnLButtonUp(nFlags, point);}
总结:
代码中所涉及的函数如BitBlt,FillSolidRect等很具有特性,对问题的解决造成了很大的困扰,通过在代码的调试中不断的摸索才渐渐熟悉了这些特性,进而解决问题。代码肯定存在不完善的地方,希望大家能给予指正,共同进步!


0 0