2012年12月7日 22:42:14
今天我在csdn网站上通过学习别人的博客学习到了动态画矩形,画线的方法,这使得我对Windows的消息循环机制有了更深刻的理解。首先来总结一下我今天的收获,呵呵有收获就是不错的,说明我进步了,感谢这两篇博文:
VC鼠标拖动动态画矩形框(http://blog.youkuaiyun.com/zhouxuguang236/article/details/7686163) 和 VC动态轨迹画线 (http://blog.youkuaiyun.com/akof1314/article/details/5547616),更感谢转载前一篇博文的作者(周旭光),是他给了我第二个博文的链接,使得我不用自己去搜索并尝试哪一篇的博文更便于我的学习。
好了下面开始言归正传:
所谓的动态画线,画矩形,画椭圆的本质就是在于消隐问题的解决以及对Windows消息循环机制的理解,消隐问题:因为MFC中有一个函数SetROP2,通过将该函数的参数设置为R2—NOT(当前绘制的像素值设为屏幕像素值的反色,这里面的“屏幕”二字是指你所绘制的图形所占据的那一部分屏幕区域,即直线所占的屏幕区域就是直线所在的那一段线的区域),利用这一点通过在同一区域重复画两次便可以将该区域的形状消隐。
而Windows消息循环机制更好的体现于MouseMove消息响应中,因为要实现动态画线、画矩形这就体现在鼠标在绘图区的移动上,鼠标在绘图区移动时,产生动态的效果,也就是说在mouse 移动的过程中始终在画线、画矩形,这就要求在MouseMove消息响应中有画线、画矩形的相应函数的调用,但正是因为mouse移动的过程中画了很多的线、矩形,所以我们就要在mouse移动的过程中将之前画出的线、矩形消隐掉,才能保证实现了自己所要实现的功能——动态画线、画矩形,但又没有产生多余的线和矩形。
消隐的问题和动态画图的问题关键在于MouseMove消息响应中的函数调用的顺序:
1.首先将上次所画的图形消隐掉
2.画出临时的图形
3.消息循环的机制:循环执行上述代码(这是Windows循环的机制,不需要自己代码实现)
在最后的LButtonUp消息响应中,需要将上面的MouseMove消息响应中循环的最后一次中最后所画的临时图形消隐掉,之后根据LButtonUp消息响应中point参数画出最终的图形。综上可知:MouseMove中的代码和LButtonUp中消隐临时图形的代码所要实现的功能就是动态这一过程,而图形的最终绘制还在与LButtonUp消息响应及其point参数。
代码如下:
-
- HCURSOR m_HCross;
- UINT m_drawType;
- CPoint m_OldPoint;
- CPoint m_startPoint;
- BOOL m_startRect;
- CGISView::CGISView()
- {
-
-
- m_startRect=FALSE;
- m_startPoint=0;
- m_OldPoint=0;
- m_drawType=0;
-
- m_HCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
-
- }
- void CGISView::OnLButtonDown(UINT nFlags, CPoint point)
- {
-
- m_startRect=TRUE;
- m_startPoint=point;
- m_OldPoint=point;
-
- ::SetCursor(m_HCross);
-
-
- CView::OnLButtonDown(nFlags, point);
- }
- void CGISView::OnMouseMove(UINT nFlags, CPoint point)
- {
-
-
- CClientDC dc(this);
- dc.SetROP2(R2_NOT);
- dc.SetROP2(R2_NOT);
-
-
-
-
-
-
-
- dc.SelectStockObject(NULL_BRUSH);
- if(TRUE==m_startRect)
- {
- switch(m_drawType)
- {
- case 1:
-
- ::SetCursor(m_HCross);
- dc.Rectangle(CRect(m_startPoint,m_OldPoint));
- dc.Rectangle(CRect(m_startPoint,point));
- m_OldPoint=point;
-
- break;
-
- case 2:
- ::SetCursor(m_HCross);
-
- dc.MoveTo(m_startPoint);
- dc.LineTo(m_OldPoint);
-
-
- dc.MoveTo(m_startPoint);
- dc.LineTo(point);
-
-
-
-
- m_OldPoint=point;
-
-
-
- break;
- case 3:
- ::SetCursor(m_HCross);
-
-
- m_OldPoint.y=m_OldPoint.x-m_startPoint.x+m_startPoint.y;
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
-
-
-
- point.y=point.x-m_startPoint.x+m_startPoint.y;
- dc.Ellipse(CRect(m_startPoint,point));
-
- m_OldPoint=point;
- break;
- case 4:
- ::SetCursor(m_HCross);
-
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- m_OldPoint=point;
- break;
- case 5:
-
- break;
-
- }
- void CGISView::OnLButtonUp(UINT nFlags, CPoint point)
- {
-
- m_startRect=FALSE;
- ::ClipCursor(NULL);
-
- CClientDC dc(this);
-
- dc.SelectStockObject(NULL_BRUSH);
- switch(m_drawType)
- {
- case 1:
-
-
-
- dc.Rectangle(CRect(m_startPoint,m_OldPoint));
-
- dc.Rectangle(CRect(m_startPoint,point));
-
-
- break;
-
- case 2:
-
-
- dc.MoveTo(m_startPoint);
- dc.LineTo(m_OldPoint);
-
-
- dc.MoveTo(m_startPoint);
- dc.LineTo(point);
- break;
- case 3:
-
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- break;
- case 4:
-
- dc.Ellipse(CRect(m_startPoint,m_OldPoint));
- dc.Ellipse(CRect(m_startPoint,point));
- break;
- case 5:
- dc.SetPixel(point,RGB(0,0,0));
- break;
-
- }
- CView::OnLButtonUp(nFlags, point);
- }
- void CGISView::OnRectangle()
- {
-
- m_drawType=1;
-
- }
-
- void CGISView::OnLine()
- {
-
- m_drawType=2;
- }
-
- void CGISView::OnEllipse()
- {
-
- m_drawType=4;
- }
-
- void CGISView::OnDot()
- {
-
- m_drawType=5;
-
- }
-
- void CGISView::OnCircle()
- {
-
- m_drawType=3;
- }
以上为自己根据实际编程练习和对博文的学习所领悟到的,如果有哪里理解的不对,还望大家指正,谢谢哈!(代码没有问题,可以正常运行。)
注:代码的排版,我多次修改,并确保整齐,但是一旦我发表后,代码的排版就会发生改变,有几行代码就会变得不规则。