在MFC下绘制直线,使用橡皮筋技术,可以使直线效果跟随鼠标移动
//OnLButtionDown m_ptOrigin = m_ptEnd = point; //OnMouseMove CClientDC dc(this); if (nFlags == MK_LBUTTON ) { dc.SetROP2(R2_NOT); dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); m_ptEnd = point; dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); } |
但是这个只能实现黑色直线的绘制,我们想要画其他颜色的线,并且希望使用不同类型的线和线宽,因此要建一个画笔,指定想要的画笔的类型,如实线、虚线、点线,指定线宽和画笔颜色。
void CGraphic1View::OnMouseMove(UINT nFlags, CPoint point) { if(MK_LBUTTON == nFlags) { CClientDC dc(this); int oldmode=dc.SetROP2(R2_NOTXORPEN); CPen pen(m_nLineStyle, m_nLineWidth, m_clr), *oldpen; oldpen = dc.SelectObject(&pen); dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); m_ptEnd=point; dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); dc.SelectObject(oldpen); dc.SetROP2(oldmode); ReleaseDC(&dc); } CScrollView::OnMouseMove(nFlags, point); } |
其中
CPen pen(m_nLineStyle, m_nLineWidth, m_clr), *oldpen; |
m_nLineStyle是线型,m_nLineWidth是线宽,m_clr是画笔颜色,也可以指定如下:
CPen pen(0, 0, RGB(255, 0, 0)), *oldpen; |
下面说一下,橡皮筋效果是如何实现的。当我们按下鼠标左键后,有m_ptOrigin = m_ptEnd = point;
这时鼠标移动就会发送WM_MOUSEMOVE消息,调用OnMouseMove进行处理,我们就在这个响应函数中实现橡皮筋的效果。if(MK_LBUTTON == nFlags)判断是否左键按下的鼠标移动。SetROP2函数主要用于设定当前前景色的混合模式。参数取值R2_NOT就是取反的意思,即前景色为背景色的反色,经常用R2_NOT来画橡皮线,因为两次取反可以还原背景色,但是只能话黑色的线。
而R2_NOTXORPEN画出来的颜色与R2_XORPEN相反,R2_XORPEN是屏幕颜色和画笔颜色的异或。OnMouseMove第一次被调用时,还没画线,所以屏幕的颜色是白色的,R2_XORPEN是当前画笔的颜色取反,那么R2_NOTXORPEN就是当前画笔颜色了。就是说第一次画的线是画笔的颜色。
第二次调用OnMouseMove时,m_ptOrigin和m_ptEnd两个点还没变,所以可以用这两个点再画线,将第一次画的线覆盖掉,变成画布的颜色,然后在新的point点和m_ptOrigin之间重新画线,颜色为画笔颜色。在旧的直线上面画线,因为线本来有颜色,所以R2_XORPEN(屏幕的颜色==画笔颜色)就会变成黑色(1 xor 1=0,0 xor 0=0),取反,即R2_NOTXORPEN为白色,就是画布的颜色,看起来就像消失了一样,其实只不过是线变成白色了(如果画笔不是白色,比如使用你系统设置了护眼配色,客户区变成不伤眼的浅绿色,这样显示出来的颜色还是白色,而不是客户区的颜色)。旧的直线删除了,就可以在新的点point上再次画线了。
扩展:如果想实现矩形、椭圆的橡皮筋效果将语句
dc.MoveTo(m_ptOrigin); dc.LineTo(m_ptEnd); |
换成:
dc.Rectangle(CRect(this->m_ptOrigin, m_ptEnd)); |
或者
dc.Ellipse(CRect(this->m_ptOrigin, m_ptEnd)); |
就可以了。