孙鑫VC学习笔记:第十一讲 (二) 图形的保存与重绘方法一

发布时间:2016-12-8 22:15:43 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"孙鑫VC学习笔记:第十一讲 (二) 图形的保存与重绘方法一",主要涉及到孙鑫VC学习笔记:第十一讲 (二) 图形的保存与重绘方法一方面的内容,对于孙鑫VC学习笔记:第十一讲 (二) 图形的保存与重绘方法一感兴趣的同学可以参考一下。

图形的保存和重绘 编写画图代码,设定一个标识,在OnLButtonDown中保存鼠标按下去的点,在OnLButtonUp中捕获鼠标弹起的点,利用switch语句分别画图。这是上节课的内容,上节课还讲了窗口重绘的原理,实际上分为两步, 首先擦除以前的背景,然后再进行窗口重绘。 所以当拖动窗口改变窗口大小时,窗口要发生重绘,首先会擦除以前的背景,于是先前所画图像会消失。 解决办法是将画图代码写在OnDraw()函数中,窗口每次重绘都会调用该函数重新绘制图像。 但是怎么保存每次重绘图像需要的代码呢? 事实上,要画的图形由三个因素决定:  1.图形类型(点、直线、矩形、椭圆)  2.图形绘制初始点  3.图形绘制终点  所以我们可以用数组类保存三个变量:m_nDrawType,m_ptOrigin,m_ptEnd。 首先需要新建一个Class type为Generic Class的名为CGraph类, 在CGraph中增加三个成员变量UINT m_nDrawType,CPoint m_pOrigin,CPoint m_pEnd, 并在不带参数构造函数中将三个成员变量初始化。 然后构造一个带参数的构造函数 CGraph(UINT m_nDrawType,CPoint m_pOrigin,CPoint m_pEnd); 用来接收三个变量值,代码如下:  CGraph::CGraph(UINT m_nDrawType,CPoint m_pOrigin,CPoint m_pEnd)  {   this->m_nDrawType=m_nDrawType;   this->m_pOrigin=m_pOrigin;   this->m_pEnd=m_pEnd;  }   至此,我们可以用CGraph类保存绘制一个图形的三要素,根据这三要素可以绘制我们所作的图形。 -------------------------------------------------------------------------------- 但是如果我们绘制了多个图形怎么办? 如果用CGraph类对象的一个数组,那么它只能保存有限个对象, 而我们在绘制图形的时候,并不能限定只能绘制多少个图形。 用链表可以实现动态存储,但是操作十分复杂, 于是我们想到了MFC提供一集合类,如前面用到过的CStringArray,可以动态存储CString对象 这里要用到的是另一个集合类,CPtrArray,它用来动态保存CGraph对象。 (它的用法大家可以参见 MSDN或右边。) 于是在OnLButtonUp函数中画完图形之后 ,我们想创建一个CGraph对象, 把画这个图形所必须的三要素保存到这个对象之中。 如果我们直接在尾部增加下面两行代码:   graph(m_nDrawType,m_ptOrigin,point)  m_ptrArray.Add(&graph); 但是运行程序之后,我们所绘制的图形没能在OnDraw函数中重绘。 这是因为我们在OnLButtonUp函数中创建的CGraph对象在本函数结束时被销毁,内存被回收。 --------------------------------------------------------------------------------- 解决办法:   在OnLButtonUp函数中创建的CGraph对象指针,然后用new方法为它在堆中分配内存。  因为new方法分配的内存在堆中,除非显式地调用Delete方法去释放它,  否则其生命周期直到程序结束时才结束 。  CGraph *=new CGraph(m_nDrawType,m_ptOrigin,point);  m_ptrArray.Add(pGraph);    虽然pGraph 指针在函数结束时也会析构,但是没有关系,m_ptrArray已经保存了该指针,  而new所建立的对象是在堆上的,除非显式地调用Delete方法去释放它,  否则其生命周期直到程序结束时才结束 。 窗口重绘会调用OnDraw函数,所以要在此函数中增加画图代码,代码如下: 注:  1. m_ptrArray.GetSize()从得到数组长度,构造for循环  2. ((CGraph*)m_ptrArray.GetAt(i))->得到CGraph类的各变量,  3. 其中m_ptrArray.GetAt(i)返回CObject*,要强制转换成CGraph*。 -------------------------------------------------------------------------------- 下面研究一下,OnDraw函数为什么能在窗口重绘过程中被调用 OnDraw函数不是WM_PAINT的相应函数,为什么能在窗口重绘过程中被调用? 下面是一段MFC资源文件中的代码:(是WM_PAINT消息响应函数OnPaint()) void CView::OnPaint()  {  // standard paint routine   CPaintDC dc(this);   OnPrepareDC(&dc);   OnDraw(&dc);  } 从上面的代码我们知道,原来在基类View类中调用了OnDraw函数,所以我们认为OnDraw专门用来重绘的 其实我们也可以增加WM_PAINT消息响应,自己在其响应函数写重绘窗口的代码。 前面讲过,在响应WM_PAINT时候,只能利用BeginPaint()获得dc的句柄,用EndPaint()释放dc句柄。 而上面代码并没有发现BeginPaint()与EndPaint(),查看一下CPaintDC 就知道, CPaintDC 类的构造函数中调用了BeginPaint(),析构函数中调用了EndPaint()。 注意:CPaintDC只能在OnPaint中使用,因为在MSDN中这样说了: CClientDC objects encapsulate working with a device context that represents only the client area of a window. The CClientDC constructor calls the GetDC function, and the destructor calls the ReleaseDC function. CWindowDC objects encapsulate a device context that represents the whole window, including its frame. 如果要在OnPaint以外地方获得dc句柄的话,调用GetDC ,释放用ReleaseDC。

上一篇:SequenceFile doesn't work with GzipCodec without native-hadoop code的解决办法
下一篇:大家都来DIY自己的Blog啦

相关文章

相关评论