可视化:单文档和多文档

单文档:SDI

一个应用程序一次只能打开一个文档,如记事本,一个记事本窗口只能打开一个文档,新建时会覆盖之前的。

多文档:MDI

可打开多个,如word.

对话框、单文档、多文档区别

对话框模板适合于做交互界面
文档模板适合于做文件处理
多文档模板适合于做多文件处理

文档五个重要类:(文档/视图框架)

CWinAPP:应用程序对象,负责初始化程序(进程启动终止),保存视图与文档等对象间的关系,处理消息循环、将消息调度到需要的目标窗口,命令行参数。

CFrameWnd:框架窗口对象,提供一个应用程序主窗口。包含菜单,工具条,最大小化按钮,标题栏,系统菜单,视图的显示及位置等。许多默认为MFC应有的功能都是在该类中实现。

CDocument:存视图空白区数据。通常保存在它的成员变量中。

  • 重要函数:
  1. UpdateAllViews():该函数调用各个视图的OnUpdate()
  2. SetModifiedFlag()

还可由函数GetFirstViewPosition()获得视图指针,对其操作

CView:视图对象。(显示文档类数据)类基类为CWnd,所以它具有CWnd所有功能如创建、移动、显示、隐藏窗口。CView可以接受所有windows消息,而CDocument不行。它实现文档类需要的功能,如可获得指向文档类的指针:GetDocument(),再获取文档类成员变量就获得数据了。

  • 重要函数:
  1. OnDraw():并不显示调用,通常由Invalidate(),updateAllView()等函数调用。

CDocTemplate:将独立的文档、视图、框架对象联系起来,每一种类型文档对应一个文档模板,它管理该类型所有文档。文档、视图、框架对象都由它创建。它实现文档类需要的功能。如建立保存文档,获取文档字符串GetDocString()等。

在应用程序类的InitInstance()中:p284

CSingleDocTemplate *tmp=new CSingleDocTemplate(…)

消息映射

本质上是一个数组,保存:

  • 所处理的消息
  • 消息应用的控件ID
  • 消息传递的参数
  • 返回值

一般用类向导定义,手动添加的话是在BEGIN_MASSAGE_MAP与END_MESSAGE_MAP宏之间添加ON_COMMAND(应用控件ID,CView::OnChange),第二个参数为添加消息映射的类的成员方法。

SDI程序的消息传递过程:

(1)WM_COMMAND消息:按视图、文档、模板、框架窗口、应用程序对象、默认的DefWindowProc传送,一旦一个对象接收了就不会再往后传。

(2)标准windows消息如键盘鼠标消息传给视图,大多其它消息传给框架窗口,文档对象和应用程序对象从不接收非命令消息。

编程实例:

(1)新建基于单文档的MFC项目,命名为SingleDocument。

其中SingleDocument.cpp处理CWinApp类

(2)为SingleDocumentDoc类添加成员变量CString m_str,用于存储显示文本。在类视图中添加。

(3)为实现。。。在SingleDocumentDoc的构造函数中初始化m_str为该字符串,为了使再新建一个文档也能出现该字符,在OnNewDocument中也定义m_str的值:

SingleDocumentDoc.cpp中:

CSingleDocumentDoc::CSingleDocumentDoc() noexcept
{
	// TODO: 在此添加一次性构造代码
	m_str = _T("您好,单文档界面的例程!");
}

BOOL CSingleDocumentDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: 在此添加重新初始化代码
	// (SDI 文档将重用该文档)
	m_str = _T("您好,单文档界面的例程!");
	return TRUE;
}

(3)实现由对话框与用户交互,改变显示文本:

在资源视图中插入Dialog,为对话框添加类:基类为CDialog,命名为DlgInput,在其中添加编辑框,为编辑框控件添加相关联CString变量m_input,则m_inout的值为输入在编辑框中的值

在主菜单中编辑菜单项中添加一项菜单项改变文本,修改ID为ID_CHANGETEXT;为菜单项添加事件处理程序(右键)。消息类型为command,选择类SingleDocumentDoc

自动添加的消息映射:

BEGIN_MESSAGE_MAP(CSingleDocumentDoc, CDocument)
	ON_COMMAND(ID_CHANGETEXT, &CSingleDocumentDoc::OnChangetext)
END_MESSAGE_MAP()

编辑该函数,进入SingleDocumentDoc.cpp,首先加入头文件"DlgInput.h",编辑处理函数OnChangeText():显示对话框,获取编辑框内容,更新视图。

void CSingleDocumentDoc::OnChangeText()
{
	// TODO: 在此添加命令处理程序代码
	DlgInput inputDlg;				//创建一个CInputDlg类的对象inputDlg
	if (inputDlg.DoModal() == IDOK)	//显示对话框
	{
		m_str = inputDlg.m_input;		//获取输入的字符串
		UpdateAllViews(NULL);		//更新视图
	}
}

UpdateAllViews(NULL);    会调用SingleDocumentView类的OnDraw()函数,所以编辑SingleDocumentView.cpp中OnDraw()函数,主要是调用TextOut()函数,将获取到的对话框文本显示在视图区。

void CSingleDocumentView::OnDraw(CDC* pDC)
{
	CSingleDocumentDoc* pDoc = GetDocument();//获得文本类对象
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO: 在此处为本机数据添加绘制代码
	CRect rectClient;
	GetClientRect(rectClient);		// 获取当前客户区的指针
	CSize sizeClient = rectClient.Size();	// 获取当前客户区的大小
	CString str = pDoc->m_str;		// 从文件中读取数据
	CSize sizeTextExtent = pDC->GetTextExtent(str);	// 用新选定的字体绘制字符串
	pDC->TextOut((sizeClient.cx - sizeTextExtent.cx) / 2, (sizeClient.cy - sizeTextExtent.cy) / 2, str);
}

多文档:

实现文档1显示文本,文档2绘图。

  1. 新建MFC工程。命名为MyMdi.文件扩展名改为mmd,为CMyMdiView类添加基类为CEditView
  2. 创建第二种文档和视图类。添加mfc类,命名为CMyMdi2,基类为CDocument。同样的方法添加View的派生类CMyMDiView2.
  3. 创建资源。(1)在Resource.h中添加
  #define IDR_MYMDITYPE2  135

(2)手工加入第二个资源模板字符串

打开MyMdi.rc找到:

IDR_MYMDITYPE "\nMyMdi\nMyMdi\nMyMdi 文件(*.mmd)\n.mmd\nMyMdi.Document\nMyMdi.Document"

在它后面添加:

IDR_MYMDITYPE2 "\nMyMdi2\nMyMdi2\nMyMdi2 文件(*.mm2)\n.mm2\nMyMdi2.Document\nMyMdi2.Document"

(3)为第二个资源文档添加菜单

打开菜单资源,将IDR_MYMDITYPE复制一份为IDR_MYMDITYPE2

4、编辑代码

(1)要在应用程序的InitInstance()函数中定义新的文档模板对象,打开MyMdi.cpp,在InitInstance()函数中添加:

CMultiDocTemplate* pDocTemplate;
    pDocTemplate = new CMultiDocTemplate(IDR_My112TYPE,
        RUNTIME_CLASS(CMy112Doc),
        RUNTIME_CLASS(CChildFrame), // 自定义 MDI 子框架
        RUNTIME_CLASS(CMy112View));
    if (!pDocTemplate)
        return FALSE;
    AddDocTemplate(pDocTemplate);

(2)在文件中添加MyMdiDoc2.h与MyMdiView2.h头文件

(3)为CMyMdiDoc2类添加CPtrArray类型成员变量m_data,这里用于保存图形信息。为其在应用程序中添加一个类DrawData:

class DrawData{
    Point begin,end;
    int type;
};

并在CMyMdiView2中添加头文件DrawData.h

CMyMdiDoc2中添加整型变量OnChangeDrawType(UNIT nID)

在CMyMdiView2中加入OnChangeDrawType映射消息,并补上代码

MyMdiDoc2.cpp

BEGIN_MESSAGE_MAP(CMyMdiDoc2, CDocument)
	ON_COMMAND_RANGE(ID_LINE,ID_RECTANGLE, &CMyMdiDoc2::OnChangeDrawType)
END_MESSAGE_MAP()


void CMyMdiDoc2::OnChangeDrawType(UINT nID)
{
	m_drawType=nID-ID_LINE;
}

(4)画图:

在MyMdiView2.h中添加成员变量

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
DrawData* m_drawData;
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);

在MyMdiView2窗口属性中添加WM_LBUTTONDOWN与WM_LBUTTONUP两个消息,编辑事件处理代码:

// CMyMdiView2 消息处理程序


void CMyMdiView2::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CMyMdiDoc2* pDoc = (CMyMdiDoc2 *)GetDocument();
	m_drawData=new DrawData;
	m_drawData->begin=point;

	CView::OnLButtonDown(nFlags, point);
}


void CMyMdiView2::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	CMyMdiDoc2* pDoc =(CMyMdiDoc2 *) GetDocument();
	m_drawData->end=point;
	CClientDC dc(this);
	CBrush *brush=CBrush::FromHandle((HBRUSH)
	GetStockObject(HOLLOW_BRUSH));
	dc.SelectObject(brush);
	CRect rect(m_drawData->begin,m_drawData->end);
	switch(pDoc->m_drawType)
	{	
	case 0:
		dc.MoveTo(m_drawData->begin);
		dc.LineTo(m_drawData->end);		
		break;
	case 1:		
		dc.Ellipse(rect);		
		break;
	case 2:		
		dc.Rectangle(rect);		
		break;	
	}
	m_drawData->type=pDoc->m_drawType;
	pDoc->m_data.Add(m_drawData);
	brush->DeleteObject();
	Invalidate(true);
	CView::OnLButtonUp(nFlags, point);
}

(5)最后,编辑视图类的OnDraw()函数,该函数将文档类的成员m_data在客户区绘制一遍。

void CMyMdiView2::OnDraw(CDC* pDC)
{
	//CDocument* pDoc = GetDocument();
	// TODO: 在此添加绘制代码
	CMyMdiDoc2 *pDoc =(CMyMdiDoc2 *)GetDocument();
	CBrush *brush=CBrush::FromHandle((HBRUSH)
	GetStockObject(HOLLOW_BRUSH));
	pDC->SelectObject(brush);
	for(int i=0;i<pDoc->m_data.GetCount();i++)
	{	
		m_drawData=(DrawData *)(pDoc->m_data.GetAt(i));
		CRect rect(m_drawData->begin,m_drawData->end);
		switch(m_drawData->type)	
		{	
		case 0:
			pDC->MoveTo(m_drawData->begin);
			pDC->LineTo(m_drawData->end);		
			break;
		case 1:
			pDC->Ellipse(rect);		
			break;
		case 2:
			pDC->Rectangle(rect);		
			break;	
		}
	}
	brush->DeleteObject();
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值