MFC橡皮筋画线实现.docx
《MFC橡皮筋画线实现.docx》由会员分享,可在线阅读,更多相关《MFC橡皮筋画线实现.docx(5页珍藏版)》请在冰豆网上搜索。
![MFC橡皮筋画线实现.docx](https://file1.bdocx.com/fileroot1/2022-11/25/7189ed6d-a4a4-46f6-973d-e4fefb66a2a9/7189ed6d-a4a4-46f6-973d-e4fefb66a2a91.gif)
MFC橡皮筋画线实现
首先创建一个名为TEXT的工程,再向视图类添加消息,在这里要说明的是为什么不是向框架类添加消息呢?
那是因为视图类是覆盖在框架类之上的,我们所看到的是视图类,就像有一堵墙,在这堵墙前面又有一堵墙挡住了它,所以我们所看到的是挡在前面的这堵墙.所以画线的操作是向视图类添加消息.
我们添加一个WM_LBUTTONDOWN和WM_LBUTTONUP的消息,这里说明一下添加一个消息会在三个地方有所添加,一个是在源文件中,如:
BEGIN_MESSAGE_MAP(CTextView,CView)
//{{AFX_MSG_MAP(CTextView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
//Standardprintingcommands
ON_COMMAND(ID_FILE_PRINT,CView:
:
OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,CView:
:
OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView:
:
OnFilePrintPreview)
END_MESSAGE_MAP()
第二个是在头文件中,如:
protected:
//{{AFX_MSG(CTextView)
afx_msgvoidOnLButtonDown(UINTnFlags,CPointpoint);
afx_msgvoidOnLButtonUp(UINTnFlags,CPointpoint);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
第三个,也是在源文件中的函数功能实现,如:
voidCTextView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_p=point;
CView:
:
OnLButtonDown(nFlags,point);
}
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
HDChdc;
hdc=:
:
GetDC(m_hWnd);
MoveToEx(hdc,m_p.x,m_p.y,NULL);
LineTo(hdc,point.x,point.y);
:
:
ReleaseDC(m_hWnd,hdc);
CView:
:
OnLButtonUp(nFlags,point);
}
这是我们利用向导添加系统消息,就是上述改动,但有时我们要手工添加消息,就有以下步骤,看和向导添加消息有什么不同,
1.首先在源文件中的开始位置定义一个用户消息,如#defineWM_MYMESSAGE WM_USER+1
2.然后在头文件中定义消息处理函数,这是和向导添加消息一样的(同样的位置),如:
afx_msgLRESULTOnMyMessage(WPARAMwParam,LPARAMlParam);
3.再就在源文件中添加自定义消息映射宏,这也是和向导添加消息一样的(同样的位置),如:
ON_MESSAGE(WM_MYMESSAGE,OnMyMessage)
4.最后在相关函数中,进行消息的发送操作,就可以消息有效了,如:
SendMessage(WM_MYMESSAGE);//消息的发送有三种方式,详细参见MSDN
下面我们来看画线操作的实现,参见voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)的代码,首先是添加类的变量,m_p在构造函数中初始化,再在voidCTextView:
:
OnLButtonDown(UINTnFlags,CPointpoint)中赋值,point也是一个类CPoint,它表示当前操作时,光标的位置.从代码中我们可以看到首先定义了一个HDC,它是设备描述表的句柄,我们在作画时也必须先定义一个作画的设备,才能往下进行操作,当然在这里我们也可以用如CClientDC,CDC,CWindowDC,来实现这一功能.HDC定义的一个变量用hdc=:
:
GetDC(m_hWnd);来得到当前视图类的句柄,相关操作后也要用:
:
ReleaseDC(m_hWnd,hdc);来释放.这里的画线是用GDI的方法来实现的.这里注意一下我们用的GetDC函数是WindowsGDI的函数,是一个全局函数.
上面提到了除了用HDC创建设备的方法还有其他方法.
我们换用CDC来实现述功能,源代码改成:
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CDC*pDC=GetDC();
pDC->MoveTo(m_p);
pDC->LineTo(point);
ReleaseDC(pDC);}
运行后我们可以看到利用CDC同样也能画线功能,但是我们会发现这里的GetDC()和ReleaseDC(pDC)前没有:
:
也就是说这里的这两个函数不是全局函数,其实这两个函数是封装在CDC这个类里的成员函数,而且MoveTo(m_p)和LineTo(point)也是成员函数,所以用指针调用.
接下来我们用CClientDC来实现.实际上我们参见MSDN的话就会发现,CClientDC是由CDC这个类派生出来的,所以它继承了CDC的所有功能,也有自己的一些功能实现.而且在CClientDC类中的构造函数中就调用了GetDC这个函数,在它的析构函数中也调用了ReleaseDC函数,这就使的当我们创建CClientDC对象时,就已经获取了视图类的句柄,当它执行完后又通过析构函数释放了句柄.下面我们看它怎么实现:
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CClientDCdc(this);
dc.MoveTo(m_p);
dc.LineTo(point);
}
如果我们细心的话,会发现上面实现的实在视图框架中才能画线,假如我们要实现在框架类中也能画线,该怎么实现呢?
其实很简单,只要把CClientDCdc(this);改成CClientDCdc(GetParent());就行了假如我们要实现在整个桌面上都能画线的话就改成CClientDCdc(GetDesktopWindow());从上我们可以看出我们画线的区域是要看我们是调用的哪个类的指针对象.如果我们想实现在非客户区也能实现画线的话就把CClientDCdc(this);改成CWindowDCdc(this);就能实现.
简单的画线可以实现了,我们了解画线的基本实现过程,如果我们要能实现更复杂的操作,就要我们添加相应的代码来实现了.如果我们想画出的线条具有不同的颜色该怎么办呢?
第一步,我们就要创建画笔,用CPen这个类,
第二步就要把创建的画笔选到设备描述表中去,用SelectObject()函数,注意的是SelectObject()返回的是选前画笔的指针,因为我们在做完操作后,还是要把原来的画笔选回的.具体的实现看下面的代码:
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CPenpen(PS_SOLID,0,RGB(0,255,0));
CClientDCdc(this);
CPen*pold=dc.SelectObject(&pen);
dc.MoveTo(m_p);
dc.LineTo(point);
dc.SelectObject(pold);
}
如果我们想得到其他颜色或者线形就参见MSDN,改变相应的参数就OK了.
我们想改变填充的颜色式样又怎么实现呢?
当然还是要先创建笔刷对象,这里注意我们用dc.FillRect(CRect(m_p,point),&brush);这个函数时并不需要把笔刷选到设备描叙表中,因为笔刷就直接用来填充了,如下面代码:
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CBrushbrush(RGB(0,255,0));
CClientDCdc(this);
dc.FillRect(CRect(m_p,point),&brush);
}
我们在这个基础上来实现位图画刷的功能,首先还是要添加一个位图资源或者导入一个位图资源,设其ID为IDB_BITMAP1;如下代码:
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CBitmapbitmap;
bitmap.LoadBitmap(IDB_BITMAP1);
CBrushbrush(&bitmap);
CClientDCdc(this);
dc.FillRect(CRect(m_p,point),&brush);
}
我们在说明一下画刷中的一个特例,就是透明画刷的实现,一般情况下我们要实现某一个类的一个功能就通过MSDN先到这个类的构造函数中去看有没有参数来实现这个功能,然后再到它的初使化函数中去看能不能通过初始化函数来实现,
voidCTextView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CClientDCdc(this);
CBrush*pbrush=CBrush:
:
FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
CBrush*pold=dc.SelectObject(pbrush);
dc.Rectangle(CRect(m_p,point));
dc.SelectObject(pold);
}
我们注意到,我们用了一个GetStockObject(NULL_BRUSH)函数来得到一个透明画刷,但是它返回的是一个HGDIOBJ类型,而我们需要调用的是一个CBrush类型,这里在CBrush类中FromHandle函数,它是一个静态的转化函数,从源代码可以看出它能把HBRUSH类型转化为CBrush类型,而GetStockObject(NULL_BRUSH)返回的是HGDIOBJ类型,所以我们用了一个强制转化符,因为这里是用矩形填充是后画盖住前画来实现透明画刷的,所以要选入设备描叙表,最后要选回原来的画刷.
这里说到了静态函数,注意静态函数不能调用非静态成员函数和变量的,而非静态成员函数是可以引用静态成员函数或变量的,但要切记静态成员变量必须初始化,在类的外部初始化如:
intpoint:
:
x=0;
前面我们所实现的还只是画一条直线,要画曲线该如何实现呢?
首先我们要添加一个BOOL型的变量,并初始化m_d=FALSE,然后添加一个WM_MOUSEMOVE的消息,添加了一个OnMouseMove()函数,根据BOOL行变量来判断,添加相关代码就可以实现了,如:
voidCSdView:
:
OnLButtonDown(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_p=point;
m_d=TRUE;
CView:
:
OnLButtonDown(nFlags,point);
}
voidCSdView:
:
OnLButtonUp(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
m_d=FALSE;
CView:
:
OnLButtonUp(nFlags,point);
}
voidCSdView:
:
OnMouseMove(UINTnFlags,CPointpoint)
{
//TODO:
Addyourmessagehandlercodehereand/orcalldefault
CClientDCdc(this);
if(m_d==TRUE)
{
dc.MoveTo(m_p);
dc.LineTo(point);
m_p=point;
}
CView:
:
OnMouseMove(nFlags,point);
}
当然还可以进行更复杂的绘图,另外还可以用SetROP2();函数来设置绘图模式,详细参见MSDN