一、实验目的
1)有四个以上文档。
2)第一个视图类的基类是CEditView。
3)在第二个文档中,画出一个图,要求有5种以上图形,图自己设计,可以是房子、树、鱼、动物等。
4)在第三个文档中,实现动画画图,图案是一个自己设计的图形,比如是一个五角星或花,之后按下鼠标就拖出一个图形,不能是简单的圆、矩形和直线,要求设置不同颜色的画笔和画刷。
5)在第四个文档中,单击菜单中的某一项可以打开对话框,包括菜单、对话框等资源。
6)在第四个文档中,对话框中至少5种控件分别存放学生的姓名(学号、年龄)、班级、党员,专业、爱好、住址等信息,每种控件的信息读取后在编辑框中显示出来。
7)在第四个文档中,实现串行化,可以输入、保存并显示学生或员工信息。
二、多个类的继承关系画出结构图。
三、每个类的定义,包括.h文件和.cpp文件。
1)第一视图类的基类是CEditView,在创建多文档时已完成(具体操作请 看实验步骤及方法中(1))。
2)第二个文档:
①.在MyMdiView2.h里的public添加代码:
public:
int m_picture;
POINT startpoint;
POINT endpoint;
bool lbutton;
int keyFlag;
CPen *cpen;
CPen *erasePen; //定义画笔类对象
CBrush *cbrush9; //定义画刷类对象
CBrush* cbrush1;
CBrush* cbrush2; //红色
CBrush* cbrush3;
CBrush* cbrush4;
bool lMouseFlag; //表示鼠标左键是否按下
bool rMouseFlag; //表示鼠标右键是否按下
②在MyMidView2.cpp添加代码。
#include "stdafx.h"
#include "MyMdi.h"
#include "MyMdiView2.h"
#include "MyMdiDoc2.h"
// CMyMdiView2
IMPLEMENT_DYNCREATE(CMyMdiView2, CScrollView)
CMyMdiView2::CMyMdiView2()
{
keyFlag=0;
rMouseFlag=false;
lbutton=false;
cpen=new CPen(PS_SOLID,0,RGB(255,0,0));
erasePen=new CPen(PS_SOLID,20,RGB(255,255,255));
cbrush9=new CBrush(RGB(0,255,0));
cbrush1 = new CBrush(RGB(255, 192, 203));//粉刷
cbrush2 = new CBrush(RGB(255, 0, 0));//红刷
cbrush3 = new CBrush(RGB(139, 69, 19));//棕刷
cbrush4 = new CBrush(RGB(255, 165, 0));//橘刷
}
CMyMdiView2::~CMyMdiView2()
{
delete cpen;
delete erasePen;
delete cbrush9;
delete cbrush2;
delete cbrush1;
delete cbrush3;
delete cbrush4;
}
BEGIN_MESSAGE_MAP(CMyMdiView2, CScrollView)
//{{AFX_MSG_MAP(CMyMdiView2)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
//}}AFX_MSG_MAP
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
//ON_COMMAND_RANGE(ID_FLOWER,ID_RECT,OnOperPictureChange)
END_MESSAGE_MAP()
void CMyMdiView2::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal;
// TODO: calculate the total size of this view
sizeTotal.cx = sizeTotal.cy = 100;
SetScrollSizes(MM_TEXT, sizeTotal);
}
void CMyMdiView2::OnDraw(CDC* pDC)
{
CMyMdiDoc2 * pDoc = (CMyMdiDoc2 *)GetDocument();
if(keyFlag!=0)
{
pDC->SelectObject(cpen);
pDC->SelectObject(cbrush9);
if(keyFlag==1) {
pDC->SelectObject(cpen);//黑色
pDC->SelectObject(cbrush2);
pDC->Ellipse(startpoint.x , startpoint.y , endpoint.x , endpoint.y );//圆
pDC->SelectObject(cbrush3);
pDC->Ellipse(startpoint.x+20, startpoint.y+20, endpoint.x-20, endpoint.y-20);//圆
pDC->SelectObject(cbrush4);
pDC->Ellipse(startpoint.x + 40, startpoint.y + 40, endpoint.x - 40, endpoint.y - 40);//圆
}}
CRect rect;
GetClientRect(&rect);
// 创建画笔和画刷
CPen pen1(PS_SOLID, 2, RGB(0, 0, 0)); // 黑色画笔
CBrush brush1(RGB(255, 200, 150)); // 主体颜色
CBrush brush2(RGB(0, 255, 0)); // 绿色,用于房顶
CBrush brush3(RGB(200, 200, 200)); // 灰色,用于烟筒
CPen* oldpen1 = pDC->SelectObject(&pen1);
// 绘制房子主体
pDC->SelectObject(&brush1);
pDC->Rectangle(100, 200, 300, 400); // 矩形主体
// 绘制房顶
pDC->SelectObject(&brush2);
POINT roofPoints[] = { {100, 200}, {200, 100}, {300, 200} };
pDC->Polygon(roofPoints, 3);
// 绘制门
CBrush brush4(RGB(100, 50, 0)); // 棕色,用于门
pDC->SelectObject(&brush4);
pDC->Rectangle(170, 300, 230, 400);
// 绘制窗户
CBrush brush5(RGB(200, 255, 255)); // 浅蓝色,用于窗户
pDC->SelectObject(&brush5);
pDC->Rectangle(120, 250, 180, 300);
pDC->MoveTo(150, 250);
pDC->LineTo(150, 300);
pDC->MoveTo(120, 275);
pDC->LineTo(180, 275);
// 绘制烟筒
pDC->SelectObject(&brush3);
pDC->Rectangle(220, 100, 240, 150);
pDC->SelectObject(oldpen1);
// 创建画笔
CPen pen2(PS_SOLID, 2, RGB(255, 0, 0)); // 红色画笔
CPen* oldpen2 = pDC->SelectObject(&pen1);
// 绘制玫瑰花瓣
pDC->Ellipse(100, 100, 150, 150);
pDC->Ellipse(100, 150, 150, 200);
pDC->Ellipse(150, 100, 200, 150);
pDC->Ellipse(150, 150, 200, 200);
pDC->Ellipse(125, 125, 175, 175);
// 创建黄色画刷
CBrush yellowBrush(RGB(255, 255, 0));
// 选中黄色画刷并绘制玫瑰花芯
CBrush* oldBrush = pDC->SelectObject(&yellowBrush);
pDC->Ellipse(135, 135, 165, 165);
pDC->SelectObject(oldBrush); // 恢复之前的画刷
pDC->SelectObject(oldpen2);
pDC->SetWindowOrg(rect.left,rect.top);
pDC->SetViewportOrg(rect.left,rect.top);
pDC->SetViewportExt(rect.right,rect.bottom);
pDC->SetWindowExt(rect.right/2,rect.bottom/2);
CPen pen3(PS_SOLID, 1, RGB(0, 0, 0));
CBrush brush6(RGB(128, 128, 128));
CBrush brush7(RGB(255, 255, 255));
CBrush brush8(RGB(255, 0, 0));
CPen* oldpen = pDC->SelectObject(&pen1);
int offsetX = 300;
int offsetY = 200;
pDC->SelectObject(&brush6);
pDC->Ellipse(115 + offsetX, 250 + offsetY, 336 + offsetX, 285 + offsetY); // 雪人影子
pDC->SelectObject(&brush7);
pDC->Ellipse(27 + offsetX, 99 + offsetY, 233 + offsetX, 280 + offsetY); // 雪人身子
pDC->Ellipse(81 + offsetX, 22 + offsetY, 177 + offsetX, 118 + offsetY);
pDC->SelectObject(&brush8);
pDC->Ellipse(113 + offsetX, 54 + offsetY, 129 + offsetX, 70 + offsetY); // 雪人眼睛
pDC->Ellipse(145 + offsetX, 54 + offsetY, 161 + offsetX, 70 + offsetY);
CPoint points[3];
points[0].x = 139 + offsetX;
points[0].y = 79 + offsetY;
points[1].x = 171 + offsetX;
points[1].y = 75 + offsetY;
points[2].x = 139 + offsetX;
points[2].y = 94 + offsetY;
pDC->Polygon(points, 3);
CBrush brush9(RGB(255, 0, 0));
pDC->SelectObject(&brush4);
CPoint hatPoints[3];
hatPoints[0].x = 72 + offsetX;
hatPoints[0].y = 22 + offsetY;
hatPoints[1].x = 127 + offsetX;
hatPoints[1].y = -30 + offsetY;
hatPoints[2].x = 197 + offsetX;
hatPoints[2].y = 22 + offsetY;
pDC->Polygon(hatPoints, 3);
}
void CMyMdiView2::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMyMdiDoc2 * pDoc = (CMyMdiDoc2 *)GetDocument();
lMouseFlag=true;
SetCapture(); //捕获鼠标动作
if(nFlags)
keyFlag=1;
else keyFlag=0;
startpoint=point;
endpoint=point;
CScrollView::OnLButtonDown(nFlags, point);
}
void CMyMdiView2::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMyMdiDoc2 * pDoc = (CMyMdiDoc2 *)GetDocument();
if(lMouseFlag)
{ endpoint=point;
Invalidate(true);
}
CView::OnLButtonUp(nFlags, point);
if(rMouseFlag==true)
{
//SetCursor(LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CURSOR1))); // 设置鼠标形状
CDC* pDC = GetDC(); // 获取设备上下文
pDC->SelectObject(erasePen);
pDC->SelectObject(cbrush9);
pDC->SetROP2(R2_COPYPEN);// 设置为覆盖绘图方式
pDC->Rectangle(point.x+10,point.y+10,point.x,point.y);
ReleaseDC(pDC); // 释放设备上下文
}
CScrollView::OnMouseMove(nFlags, point);
}
void CMyMdiView2::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CMyMdiDoc2 * pDoc = (CMyMdiDoc2 *)GetDocument();
ReleaseCapture();
endpoint=point;
Invalidate(true); //参数为true则用白刷子刷新用户区后再画,为false则在原来基础上面画图。
lMouseFlag=false;
CScrollView::OnLButtonUp(nFlags, point);
}
void CMyMdiView2::OnRButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
rMouseFlag=true;
SetCapture(); //捕获鼠标动作
startpoint=point;
endpoint=startpoint;
CScrollView::OnRButtonDown(nFlags, point);
}
void CMyMdiView2::OnRButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
ReleaseCapture(); // 释放鼠标捕获
rMouseFlag=false;
CScrollView::OnRButtonUp(nFlags, point);
}
3)在第三个文档里:
1.在MyMidDoc3.h中的public下进行定义
CString m_di;
CString m_str;//字符串化
2.在MyMidDoc3.cpp中以下代码
#include"CDIgInput.h"//添加对应的头文件
BOOL CMyMidDoc3::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
m_str = "可以点击'编辑'下拉菜单下的'信息录入',显示信息录入表格
return TRUE;
}
BEGIN_MESSAGE_MAP(CMyMidDoc3, CDocument)
ON_COMMAND(ID_Sh, &CMyMidDoc3::OnSh)
END_MESSAGE_MAP()
#ifdef _DEBUG
// CMyMidDoc3 序列化
//字符串化
void CMyMidDoc3::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: 在此添加存储代码
ar << m_di;
}
else
{
// TODO: 在此添加加载代码
ar >> m_di;
}
}
#endif
void CMyMidDoc3::OnSh()
{
// TODO: 在此添加命令处理程序代码
CDIgInput inputDlg; //创建一个 CInputDlg类的对象
if (inputDlg.DoModal() == IDOK)//显示对话框
{
m_str = "";//获取输入的字符串
m_di = inputDlg.m_Edit5;
UpdateAllViews(NULL);//更新视图
}
3、在MyMidView3.cpp文件中添加从文档读取的数据
void MyMidView3::OnDraw(CDC* pDC)
{
//CDocument* pDoc = GetDocument();
CMyMidDoc3* pDoc = (CMyMidDoc3*)GetDocument();
ASSERT_VALID(pDoc);
// TODO: 在此添加绘制代码
CString str = pDoc->m_str; // 从文档类中读取数据
pDC->TextOut(5,10,str);
CString str1 = pDoc->m_di;// 从档类中读取数据
pDC->TextOut(100,50,str1);
}
4. DlgInput.cpp : implementation file
#include "stdafx.h"
#include "MyMdi.h"
#include "DlgInput.h"
void CDlgInput::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDlgInput)
DDX_Control(pDX, IDC_BUTTON2, m_Button2);
DDX_Control(pDX, IDC_COMBO4, m_Combo4);
DDX_Control(pDX, IDOK, m_ok);
DDX_Control(pDX, IDC_COMBO3, m_Combo3);
DDX_Control(pDX, IDC_COMBO2, m_Combo2);
DDX_Control(pDX, IDC_COMBO1, m_Combo1);
// DDX_Radio(pDX, IDC_RADIO1, m_Radio1);
DDX_Text(pDX, IDC_EDIT1, m_Edit1);
DDX_Text(pDX, IDC_EDIT5, m_Edit5);
DDX_Text(pDX, IDC_EDIT2, m_Edit2);
DDX_Text(pDX, IDC_EDIT3, m_Edit3);
DDX_Check(pDX, IDC_CHECK1, m_bcheck);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDlgInput, CDialog)
//{{AFX_MSG_MAP(CDlgInput)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CDlgInput::OnInitDialog()
{
CDialog::OnInitDialog();
// m_Button2.SetCheck(1);
// TODO: Add extra initialization here
m_bcheck=TRUE;
UpdateData(FALSE);
m_Combo1.AddString("数据科学与大数据技术");
m_Combo1.AddString("计算机科学与技术");
m_Combo1.AddString("医学信息工程");
m_Combo1.AddString("通信工程");
m_Combo2.AddString("1班");
m_Combo2.AddString("2班");
m_Combo2.AddString("3班");
m_Combo3.AddString("河北省保定市");
m_Combo3.AddString("河北省石家庄市");
m_Combo3.AddString("河北省张家口市");
m_Combo4.AddString("游泳");
m_Combo4.AddString("羽毛球");
m_Combo4.AddString("篮球");
m_Combo4.AddString("唱歌");
// 将成员变量的值更新到对话框的控件上
UpdateData(FALSE);
return TRUE; //return TRUE unless you set the focus to a contr
}
void CDlgInput::OnButton2()
{
// TODO: Add your control notification handler code here
CString cs4,cs5,cs6,cs7;
CString allCs1;
CString allCs2;
CString allCs;
m_Combo4.GetWindowText(cs4);//爱好
UpdateData(TRUE);
m_Combo1.GetWindowText(cs5);//专业
m_Combo2.GetWindowText(cs6);//班级
m_Combo3.GetWindowText(cs7);//地址
allCs1 = allCs1+"姓名:"+m_Edit1 +" " + "学号:" + m_Edit2 +" " + "年龄:" + m_Edit3 + " "+"\n爱好:" + cs4 +" "+ "专业:" + cs5+" "+ "班级:" + cs6+ " "+"地址:" + cs7;//名字 学号 专业
CString cs;
if (m_bcheck == 1) { cs = "是党员"; }
else { cs= "不是党员"; }
allCs2 = allCs2 + " "+cs;
allCs = allCs + " " + allCs2;
m_Edit5=m_Edit5+allCs1;
m_Edit5=m_Edit5+allCs;
UpdateData(FALSE);
}
void CDlgInput::OnOK()
{
UpdateData(TRUE);
CString cs;
if (m_bcheck == 1) { cs = "是党员"; }
else { cs= "不是党员"; }
CDialog::OnOK();
}
4)在为了使CMyMdiDoc2类和CMyMdiView2在CMyMdiApp类中成为可识别的对象类,必须在CMyMdiApp.cpp文件中包含CMyMdiDoc2类和CMyMdiView2的说明头文件CMyMdiDoc2.h和CMyMdiView2.h,加入代码。第三个文档也是如此。
#include "MyMdiView.h"
#include "MyMdiDoc2.h"
#include "MyMdiView2.h"
#include "MyMdiDoc3.h"
#include "MyMdiView3.h"
四、实验步骤及方法
-
在Visual C++ 6.0中,创建一个多文档应用程序MyMdi,在“MFC应用程序向导—步骤四”中,单击“高级”按钮,弹出“高级选项”对话框,在文件扩展名中输入mmd,在主框标题框中输入Xx,在过滤器名框中输入“MyMdi文件(*.mmd)”,在“MFC应用程序向导—步骤6”对话框中,为CMyMdiView类设置基类为CEditView,其他的都保留默认设置,最后点击完成即可,第一种文档已经创建成功,运行无错即可向下进行。在MFC类向导窗口中,点击Add Class按钮,选择New子菜单,弹出New Class对话框,在Name 框中输入新的文档类名称CMyMdiDoc2,在Base class框中输入选择CDocument,点击“确定”按钮,用同种方法在应用程序中添加CScrollView的派生类MyMdiView2,用上述方法也创建CMyMdiDoc3和MyMdiView3
-
在Resource.h文件中,手动添加下列代码:
#define IDR_XXTYPE 129
#define IDR_XXTYPE2 130
#define IDR_XXTYPE3 131
手工加入第二个资源模板字符串。具体方法:从工作空间的资源视图选择String,打开字串表资源,找到IDR_MYMIDTYPE的代码,进行复制粘贴在此基础上修改。
因为本应用程序支持多种文档,所以在应用程序的Initlnstance()函数中,需要定义的文档模板对象,打开MyMdi.cpp文件,添加代码如下:
CMultiDocTemplate* pDocTemplate;
pDocTemplate = new CMultiDocTemplate(
IDR_MYMDITYPE,
RUNTIME_CLASS(CMyMdiDoc),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMyMdiView));
AddDocTemplate(pDocTemplate);
CMultiDocTemplate* pDocTemplate2;
pDocTemplate2 = new CMultiDocTemplate(
IDR_MYMDITYPE2,
RUNTIME_CLASS(CMyMdiDoc2),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(CMyMdiView2));
AddDocTemplate(pDocTemplate2);
CMultiDocTemplate* pDocTemplate3;
pDocTemplate3= new CMultiDocTemplate(
IDR_MYMDITYPE3,
RUNTIME_CLASS(MyMdiDoc3),
RUNTIME_CLASS(CChildFrame), // custom MDI child frame
RUNTIME_CLASS(MyMdiView3));
AddDocTemplate(pDocTemplate3);
- 为了使MyMdiDoc2类和XxView2在MyMdiApp类中成为可识别的对象类,必须在MyMdi.cpp文件中包含MyMdiDoc2类和MyMdiView2的说明头文件XxDoc2.h和XxView2.h,加入代码。第三个也是如此。
#include "MyMdiDoc.h"
#include "MyMdiView.h"
#include "MyMdiDoc2.h"
#include "MyMdiView2.h"
#include "MyMdiDoc3.h"
#include "MyMdiView3.h"
7)对与第三个文档,点击编辑菜单中的信息录入,测就出现了对话框,同时实现了显示信息可输入、串行化,保存等功能。
- 为程序添加对话框,在资源视图中找到Dialog新插入一个为IDD_CDlgInput并且在对话框中学生录入信息所需要的控件,进行整理(图8-3),为其分别连接建立类向导同时为其中的控件添加相关联的成员变量(图8-4)。
在资源视图中找到Menu,将菜单IDR_MYMIDTYPE复制命名一份,ID为IDR_MYMIDTYPE。在新创建的编辑在当中加入“信息录入”,并将起ID设置为ID_Sh。
- 为程序添加对话框,在资源视图中找到Dialog新插入一个为IDD_CDlgInput并且在对话框中学生录入信息所需要的控件,进行整理(图8-3),为其分别连接建立类向导同时为其中的控件添加相关联的成员变量(图8-4)。
为程序添加对话框,在资源视图中找到Dialog新插入一个为IDD_CDlgInput并且在对话框中学生录入信息所需要的控件,进行整理,为其分别连接建立类向导同时为其中的控件添加相关联的成员变量。
- 然后利用类向导为对话框生成CDialog类的派生类CDlgInput。
- 最后在相对应的文件添加代码(具体内容请查看类的定义)。
- 运行程序(具体结果请查看测试结果里的内容)。
- 对个文档进行操作,无误后,该程序测运行操作成功。
五、调试分析与测试结果
1)调试分析
在写代码中编译运行会出现错误,可以根据编译器提示语句找到相关部分进行修改。多次且随时编译运行来增加程序的可靠性和正确性。
2)结果:就不展示了
六.程序调试心得体会(困难及经验)
(1)困难:
①.程序的断言总是出错,存在报警 |
(2)经验:①. 打代码是要仔细,注意大小写问题,和字母拼写问题。 ②.注意逻辑问题,避免出现不必要的错误。 ③.要注意引用对应的头文件。 |
七.参考文献:
李忠华 《面向对象程序设计》
郑光勇《C++面向对象程序设计》