MFC动态画直线并且具有窗口重绘功能和保存在磁盘上
作者:互联网
动态画直线
(1)设置拖曳标记以及光标句柄。在视图类CMyDrawView的头文件中添加如下成员变量的定义
public:
int m_down;
int m_up;
int m_uy1;
int m_ux1;
int m_dy1;
int m_dx1;
(2)在视图类CMyDrawView的构造函数中初始化拖曳标记,设置十字光标。
CMyLineView::CMyLineView()
{
// TODO: add construction code here
m_bDragging=false;
m_hCross=AfxGetApp()->LoadStandardCursor(IDC_CROSS);
}
(3)利用ClassWizard类向导为视图类添加按下鼠标左键WM_LBUTTONDOWN、移动鼠标WM_MOUSEMOVE和释放鼠标左键WM_LBUTTONUP的消息处理函数。
void CMyLineView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_down=1;
m_dx1=point.x;
m_dy1=point.y;
SetCapture();
::SetCursor(m_hCross);
m_ptOrigin=point;
m_bDragging=TRUE;
CView::OnLButtonDown(nFlags, point);
}
void CMyLineView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_down)
{
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin=point;
}
if(m_up)
{
CMyLineDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->AddLine(m_dx1,m_dy1,m_ux1,m_uy1);
CClientDC dc1(this);
dc1.MoveTo(m_dx1,m_dy1);
dc1.LineTo(m_ux1,m_uy1);
m_dx1=NULL;
m_dy1=NULL;
m_ux1=NULL;
m_uy1=NULL;
m_up=0;
}
CView::OnMouseMove(nFlags, point);
}
void CMyLineView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
Invalidate();
m_up=1;
m_down=0;
m_ux1=point.x;
m_uy1=point.y;
if(m_bDragging)
{
m_bDragging=false;
ReleaseCapture();
}
CView::OnLButtonUp(nFlags, point);
}
窗口重绘
为线段定义新类CLine。执行Insert|New Class命令,弹出New Class对话框。在Class type框选择Generic Class,在Name框输入CLine,在Base class框输入CObject,单机OK按钮,自动生成类CLine的头文件Line.h和实现文件Line.cpp。
为类CLine定义成员变量和成员函数。一条线段需要起点和终点两个点的坐标来确定,在头文件Line.h中定义两个表示起点和终点的成员变量m_pt1和m_pt2和m_pt3和m_pt4,其类型为CPoint类。定义成员函数DrawLine()根据两点画一条直线。
class CLine : public CObject
{
private:
int m_pt1;
int m_pt2;
int m_pt3;
int m_pt4;
public:
CLine();
virtual ~CLine();
CLine(int pt1,int pt2,int pt3,int pt4);
void DrawLine(CDC pDC);
};
在实现源文件Line.cpp中编写如下成员函数的实现代码:
CLine::CLine(int pt1,int pt2,int pt3,int pt4)
{
m_pt1=pt1;
m_pt2=pt2;
m_pt3=pt3;
m_pt4=pt4;
}
void CLine::DrawLine(CDC pDC)
{
pDC->MoveTo(m_pt1,m_pt2);
pDC->LineTo(m_pt3,m_pt4);
}
一般使用数组来保存多条线段的数据,可将存放每条线段数据的变量的指针存到CObArray类的对象中。所以,在CMyDrawDoc文档类中定义以下成员变量和成员函数,并包含CLine类定义的头文件Line.h。
#include"Line.h"
#include<afxtempl.h>
class CMyLineDoc : public CDocument
{
protected:
CTypedPtrArray<CObArray,CLine>m_LineArray;
public:
CLine GetLine(int nIndex);
void AddLine(int pt1,int pt2,int pt3,int pt4);
int GetNumLines();
};
在实现源文件MyDrawDoc.cpp中编写如下成员函数的实现代码:
void CMyLineDoc::AddLine(int pt1,int pt2,int pt3,int pt4)
{
CLine* pLine=new CLine(pt1,pt2,pt3,pt4);
m_LineArray.Add(pLine);
SetModifiedFlag();
}
CLine* CMyLineDoc::GetLine(int nIndex)
{
if(nIndex<0||nIndex>m_LineArray.GetUpperBound())
return NULL;
return m_LineArray.GetAt(nIndex);
}
int CMyLineDoc::GetNumLines()
{
return m_LineArray.GetSize();
}
当拖动鼠标时,除了绘制线段,还要保存当前线段的起点和终点坐标。所以,在视图类CMyDrawView的鼠标移动消息处理函数OnMouseMove()中添加如下代码:
void CMyLineView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_down)
{
CClientDC dc(this);
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin=point;
}
if(m_up)
{
CMyLineDoc* pDoc=GetDocument();
ASSERT_VALID(pDoc);
pDoc->AddLine(m_dx1,m_dy1,m_ux1,m_uy1);
CClientDC dc1(this);
dc1.MoveTo(m_dx1,m_dy1);
dc1.LineTo(m_ux1,m_uy1);
m_dx1=NULL;
m_dy1=NULL;
m_ux1=NULL;
m_uy1=NULL;
m_up=0;
}
CView::OnMouseMove(nFlags, point);
}
为了在改变程序窗口大小后或重新打开窗口时显示窗口中原有的图形,需要在OnDraw()函数中添加代码,重新绘制前面利用鼠标所绘制的线段。
void CMyLineView::OnDraw(CDC* pDC)
{
CMyLineDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
int nIndex=pDoc->GetNumLines();
TRACE(“nIndex1=%d\n”,nIndex);
while(nIndex–)
{
TRACE(“nIndex2=%d\n”,nIndex);
pDoc->GetLine(nIndex)->DrawLine(pDC);
}
}
序列化,即将画的保存在磁盘上
按照序列化的条件,在CLine类的声明头文件Line.h中添加函数Seralize()的声明和DECLARE_SERIAL宏。
class CLine : public CObject
{
private:
int m_pt1;
int m_pt2;
int m_pt3;
int m_pt4;
public:
CLine();
virtual ~CLine();
CLine(int pt1,int pt2,int pt3,int pt4);
void DrawLine(CDC pDC);
void Serialize(CArchive &ar);
DECLARE_SERIAL(CLine)
};
在实现源文件Line.cpp中的成员函数定义前添加IMPLEMNT_SERIAL宏。
IMPLEMENT_SERIAL(CLine,CObject,1)
编写CLine类的序列化函数Serialize()的实现代码,如下所示:
void CLine::Serialize(CArchive &ar)
{
if(ar.IsStoring())
ar<<m_pt1<<m_pt2<<m_pt3<<m_pt4;
else
ar>>m_pt1>>m_pt2>>m_pt3>>m_pt4;
}
为所有线段数据的读写:
void CMyLineDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
m_LineArray.Serialize(ar);
}
else
{
// TODO: add loading code here
m_LineArray.Serialize(ar);
}
}
在Workspace(工作区)中右击文档派生类CMyDrawDoc,在弹出的菜单中选择Add Virtual Function命令,在随之打开的对话框中选中DeleteContents项,然后单击Add and Edit按钮,添加如下代码:
void CMyLineDoc::DeleteContents()
{
// TODO: Add your specialized code here and/or call the base class
int nIndex=GetNumLines();
while(nIndex–)
delete m_LineArray.GetAt(nIndex);
m_LineArray.RemoveAll();
CDocument::DeleteContents();
}
最后,为程序设计提示文档保存功能
void CMyLineDoc::AddLine(int pt1,int pt2,int pt3,int pt4)
{
CLine pLine=new CLine(pt1,pt2,pt3,pt4);
m_LineArray.Add(pLine);
SetModifiedFlag();
}
标签:MFC,point,int,void,CLine,磁盘,pt4,pt3,重绘 来源: https://blog.csdn.net/qq_46647978/article/details/111051237