当前位置:文档之家› 第10讲 单文档与多文档

第10讲 单文档与多文档

第11章单文档与多文档本章主要介绍Visual C++中的文档/视图结构的工作机制

11.1 概述

11.1.1单文档界面与多文档界面

VC的MFC库支持三种不同的应用程序单文档界面(SDI)

多文档界面(MDI)

基于对话框的应用程序

SDI的应用程序

只有一个窗口

MDI的应用程序每次

可以读写多个文件或

文档,可同时对多个

文档进行操作,可以

有多个子窗口

在创建SDI界面的应用程序时,不生成

CChildFrame类,CMainFrame类的基类

为CFrameWnd

在创建MDI界面的应用程序时,

CMainFrame类的基类为

使用AppWizard创建SDI和MDI界面的应用程序的过程几乎完全一样

视图是文档的不同表现形式,一个*.html

语言的文件,在浏览器里和在记事本中打

开的表现形式是不同的但它们操作的是同

一个文件这就是一个文档对应两视图

由于每一个文档可以有多个视图,但

每个视图只能对应于一个确定的文档

多文档程序需要解决的问题仅仅是多

个文档的数据管理方法的问题

多文档程序,最初的文档模板只支持主窗口,但每次打开一个新文档时都调用CDocument的函数OnNewDocument,建立一个由CMDIChildWnd派生的新的MDI子窗口,这些窗口

11.1.2 文档/视图结构在文档/视图结构中

对数据进行管理和维

护,数据保存在文档

类的成员变量中文档类通过串行化

的过程将数据保存

到磁盘文件或数据库中

文档类还可处理来自如菜单、工具栏按钮和加

速键的WM_COMMAND 消息

除WM_COMMAND 外,文档不能处理其它的Windows 消息

由此我们可以看出,命令消息可以被多种对象处理,这些对象除了窗口和视图外,还可以是文档、文档模板或应用程序本身这一点与Windows 消息和控件通知消息不同,因为Windows 消息和控通过调用文档和视图的接口将修

在文档和用户之

间起中介作用视图可以直接或间接

的访问文档类中的成

员变量,它从文档类

中(而不是从存储介质

中)将文档中的数据取

出来,然后在屏幕上

它可以接收用户的输入,并接受用户的修改

文档/视图结构的工作机制

视图通过GetDocument

成员函数获得指向相关

联的文档对象的指针

通过该指针调用文

档类的成员函数来

从文档中读取数据视图把数据显示

于计算机屏幕上

用户通过与视图的交互来查看数据并对数据进行修改视图通过相关联的文档类

的成员函数将经过修改的

数据传递给文档对象

文档对象获得修改过的数据之后,对

其进行必要的修改,最后保存到永久

SDI文档/视图应用程序示意图

11.1.3 SDI程序中文档、视图对象的创建过程SDI程序中框架窗口、文档和视图的创建是在应用程序对象的InitInstance()成员函数中通过文档模板类完成的:CSingleDocTemplate * pDocTemplate;//创建单文档模板类对象pDocTemplate = new CSingleDocTemplate

(IDR_MAINFRAME,

RUNTIME_CLASS (CMyDoc),//CMyDoc是应用程序中的文档类RUNTIME_CLASS (CMainFrame),//CMainFrame是应用程序中的框架窗口RUNTIME_CLASS (CMyView) );//CMyView是应用程序中的视图类AddDocTemplate(pDocTemplate); //加载文档模板类对象到文档模板列表…

CCommandLineInfo cmdInfo;

ParseCommandLine(cmdInfo); //初始化CCommandLineInfo对象

if(! ProcessShellCommand(cmdInfo)) //据对象中的信息启动程序

return FALSE;

m_pMainWnd -> ShowWindow(SW_SHOW);

m_pMainWnd -> UpdateWindow();//显示和更新窗口

11.1.4 SDI程序的消息传递过程

当用户选择了菜单项,

单击了快捷键或工具条

按钮,系统就会发送

WM_COMMAND消息。框

架窗口实际上是大多数

WM_COMMAND消息的接

受者,但WM_COMMAND

消息还可以在视图、文

档,甚至应用程序类中

被处理。

11.2 Doc/View框架的主要成员Doc/View框架虽然可以调用成百上千个不

同的类,但是核心类只有五个: CWinApp

CDocument

CView

CDocTemplate

CFrameWnd

11.2.1 CWinApp 类

CWinApp类代表主程序,CWinApp本身是不可见的,它负责维护进程的启动、终止、消息循环、命令行参数、资源管理

成员描述

m_pszAppName应用程序名

m_lpCmdLine命令行参数

m_pMainWnd应用程序主窗口指针m_pszExeName可执行文件名

m_pszProfileName配置INI文件名

m_pszRegistrKey配置注册表主键值LoadCursor加载光标资源LoadIcon加载图标资源部分主要成员

11.2.2 CDocument类

CDocument的一般方法

方法说明

GetTitle() 获得文档标题

SetTitle() 设置文档标题

GetPathName() 获得文档数据文件的路径字符串

SetPathName() 设置文档数据文件的路径字符串

GetDocTemplate() 获得指向描述文档类型的文档模板的指针AddView() 对与文档相关联的视图列表添加指定的视图RemoveView() 从文档视图列表中删除视图

UpdateAllViews() 通知所有视图,文档己被修改,应重画DisconnectViews() 使文档与视图相分离

CDocument的虚拟方法

方法说明

OnNewDocument()由MFC调用来建立文档

OnOpenDocument()由MFC调用来打开文档

OnSaveDocument()由MFC调用来保存文档

OnCloseDocument()由MFC调用来关闭文档

CanCloseFrame()确定观察文档的框架窗口是否被允许关闭DeleteContents()在未撤消文档对象时删除文档数据

ReleaseFile()释放文件以允许其它应用程序使用

SaveModified()查询文档的修改状态并存储修改的文档

IsModified()确定文档从它最后一次存储后是否被修订过SetModifiedFlag()设置文档从它最后一次存储后是否被修订过的布尔值GetFirstViewPosition()获得视图列表头的位置

GetNextView()获得视图列表的下一个视图

最常用的是SetModifiedFlag()和UpdateAllViews()。文档内容被修改后,一般要调用SetModifiedFlag()来设定一个标志。UpdateAllView()刷新所有和文档关联的视图。实际上该函数调用各个视图类的OnUpdate()函数。这样做可以保证各个视图之间的同步。

用户可通过函数GetFirstViewPosition()和GetNextView()得到和文档关联的视图的指针,代码如下:

POSITION pos = GetFirstViewPosition(); //得到视图列表头的位置While(pos != NULL)

{ CView *pView = GetNextView(pos);//获得视图列表中的视图指针…

}

CDocument类在现在流行的MVC(Modal、View、Control)设计模式中相当于其中的Modal,表示抽象数据模型。

文档最主要的功能如下:

l打开保存文档

l维护文档相关的视图列表

l维护文档修改标志

l通过电子邮件发送文档

用户修改文档数据时,调用SetModifiedFlag方法来标志数据被更改过。当程序关闭该文档关联的最后一个视图的时候,文档会自

从CDocument类派生新的文档类的一般过程如下:

?为每一个文档类型从CDocument类派生一个相应的文档类。?为文档类添加成员变量,这些变量主要用来保存文档的数据,并使其它的对象(如视图对象)可以访问这些成员变量,从而实

现文档和视图的相互搭配使用。

?重载Serialize成员函数,实现文档数据的串行化。

无论是保存文档或是打开文档,应用程序都是通过调用文档类的Serialize串行化成员函数来完成操作的。因此,在大多数情况下,我们都需要重载Serialize成员函数。Serialize成员函数带有一个CArchive类型的参数,这是一个与所打开的文件相关联的对象。一般情况下,总是使用CArchive对象来保存和打开文档。

CArchive对象是单向的,只用于保存或读取两者之一,不能通过同一个CArchive 对象既保存又读取文档。

在框架创建CArchive对象时,已根据用户选择的是“保存”( “另存为”)还是“打开”来设置了CArchive对象的类型,我们可以使用CArchive类的成员函数IsStoring来检索当前CArchive对象的类型,从而得知用户所期望的操作是保存还是

读取,执行不同的操作。

11.2.3 CView类

视图类(CView)是从CWnd类下派生的

视图类具有CWnd的所有功

能如:创建、移动、显示和

隐藏窗口等。CView类可以

接收任何Windows消息,而

CDocument类则不行

IsSelected():确定文档是否被选中

OnScroll():当用户滚动时,CView的响应OnInitialUpdate():在类第一次构造后由MFC调用OnDraw():由MFC调用发出文档到设备描述表OnUpdate():由MFC调用对文档的修改进行响应CView主要虚拟方法

CView类中最常用的是OnDraw函数,该函数在屏幕发生变化或因为焦点的变化需要重绘时调用,没有该函数,就不可能在程序的切换后保证屏幕的正确显示。

注意: 尽量不要在OnDraw之外的函数调用绘图方法,那些方法不会在视图需要重新绘制的时候被自动调用。

若想在数据更新的时强制视图更新,可调用Invalidate方法和UpdateWindow方法来实现。

CEditView:简单的文本编辑器,类似Notepad

CListView:基于列表的视图,类似文件夹浏览

CTreeView:基于树状控件的视图,类似文件浏览左侧的树状结构CRichEditView:支持多种字体、OLE和RTF格式的高级编辑器CScrollView:支持滚动条的视图

CFormView:窗体视图,支持在上边使用对话框控件CRecordView:连接到ODBC数据库的视图CDaoRecordView:连接到DAO数据库的视图

CView的子类

11.2.4 CDocTemplate类

文档模板类在应用程序中有着非常重要的作用,是它将原本独立的文档、视图和框架窗口对象联系在一起

文档模板类负

责具体的关联

文档、视图、

框架的创建

关于单文档多视与MFC的初始化过程

单文档多视的实现 多视图是VC开发中经常要用到的技术之一,一般地实现单文档多视图有两种方式1)通过视图分割的技术(使用CSplitterWnd实现),将窗口分割为多个部分,每个部分显示各自显示不同的视图,这种技术实现起来比较简单,并且相关的资料也很多。2)通过一个文档关联多个视图,窗口显示整个视图。第二种实现较第一种复杂,这里给出详细的实现方法。 Step 1:使用VC 6.0新建一个Project,命名为:MultiView。除选择单文档属性外,一切使用“默认”方式。于是你可以获得五个类:CMainFrame,CMultiViewApp,CMultiViewDoc,CMultiViewView,和CAboutDlg; Step 2:新建一个新的视图View,添加一个新的MFC Class(Insert->New Class),基类为CView(或者CView的派生子类,如CEditView等)。类的名字为CAnotherView,这就是新的视图;并为CAnotherView添加GetDocument 个子菜单“视图一”和“视图二”,添加相应函数: (void CMultiViewApp::OnShowFirstview()和 void CMultiViewApp::OnShowSecondview()); 注意这里将菜单消息的响应都放在app对象里面,而不是放到MainFrame对象中进行。 Step 4:创建新的视图:在BOOL CMultiViewApp::InitInstance()中添加

Step 5:现在已经创建了视图,并且都和文档关联起来了。现在要作的就是视图间的转换。在void CMultiViewApp::OnShowFirstview()中添加实现代

vc 6.0打造单文档界面与多文档界面的编程

vc++6.0打造单文档界面与多文档界面的编程 VC++6中,可以利用MFC向导分别创建单文档和多文档界面的应用程序。有了这两种类型的应用程序,您就可以实现简单的记事本,写字本和WORD的功能了。 以下介绍一个在文档中输出一段文字,点击菜单项,输入文字内容按OK按钮后可以更改输出的文字。 1.首先,点击MFC向导,选择多文档视图类型,新建一个名为MdiDemo的工程。 2.新建一个对话框。上面放置一个Static控件和一个Edit控件,按CTRL+W,将Edit控件改成m_Caption. 3.新建一个类与对话框对应,如CDlgDemo类。 4.在菜单中,增加一项Demo,并增加菜单项Test.按 CTRL+W,并双击后,在消息的上面选择Doc,下面选择Command,双击就产生了对应的事件处理函数。 5.在MdiDemoDoc.cpp类中输入以下: // DlgDemo.cpp : implementation file // #include "stdafx.h" #include "MdiDemo.h" #include "DlgDemo.h" #ifdef _DEBUG

#define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CDlgDemo dialog CDlgDemo::CDlgDemo(CWnd* pParent /*=NULL*/) : CDialog(CDlgDemo::IDD, pParent) { //{{AFX_DATA_INIT(CDlgDemo) m_Caption = _T(""); //}}AFX_DATA_INIT } void CDlgDemo::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CDlgDemo) DDX_Text(pDX, IDC_EDIT1, m_Caption); //}}AFX_DATA_MAP }

(已读)第十四章 单文档界面的程序

第十四章单文档界面的程序 用VC++的AppWizard生成的程序有三种样式的界面,它们是单文档、多文档和对话框界面。前面各章我们都生成对话框样式的界面,这可以方便我们学习各种常用控件的设计,本章要学习如何生成一个单文档界面的应用程序,以及文档类和视图类的概念和相互关系。 本章要点 1 用AppWizard生成单文档界面的操作方法 2 文档类和视图类的概念 3 如何保持文档和视图的同步关联。 14.1 生成单文档界面的文本编辑器 用AppWizard生成单文档界面的操作方法和生成对话框界面的操作方法稍有不同,我们通过建立一个“文本编辑器”应用程序MyNote.exe来演示,具体过程如下: 1 打开应用程序向导,在d:\myVC\CH14创建应用程序MyNote。 2 在Step1中选择“单文档”和“文档/视图支持”,如图chap14-01. 图chap14-01 3 在step2和step3对话框中都用默认的。在step4中如图chap14-02选择前五项,当然也可以按你的需要选择。 图chap14-02

4 在Step5中选择MFC标准、加备注和静态连接库。图chap14-03 图chap14-03 5 在step6中选择视图的基类(base class),因为我们需要的是文本编辑器,所以要选类CEditView作为基类。点击[完成]按纽,应用程序的框架就创建好了。 14.2 文档类和视图类的概念 向导工作完成以后马上编译和连接,运行后就可以看到一个已经能够使用的文本编辑器,它不仅可以输入文字,还可以保存或打开文件,与Windows的记事本差不多了,只是没有设置字体的功能。图chap14-04是它运行时的窗口。 chap14-04 菜单和工具栏的响应函数都已经生成了相应的代码,我们没有做任何编写工作就得到了一个“完整”的应用程序,甚至还创建了一个帮助文件呢。这就是VC++开发环境的巨大威力!我们从上图中可以看到,编辑菜单中的复制和剪切都已经有效了。 图中的窗口是主框架,对应于类CMainFrame,而其中的“编辑区域”叫用户区,对应于视图类CMyNoteView,而被编辑的文本对应于一个文档类CMyNoteDoc。另外,每个程序还有一个对应于应用程序本身的类,本例中是CMyNoteApp。这四个类就是向导自动生成的应用程序框架类,打开工作区的类classView页区,就可以看到,如图chap14-05。 展开视图类,可以找到一个函数GetDocument(),它是使视图(的内容)和文档保持同步关联的纽带。它返回一个CMyNoteDoc类型的对象指针m_pDocument。使用它在视图中访问文档的内容。

第三章 单文档应用程序

第三章单文档应用程序 在本学习情境中主要学习: (1)单文档应用框架 (2)文档与视图 3.1 MFC消息处理 3.1.1事件驱动程序设计 事件驱动程序设计是一种全新的程序设计方法,它不是由事件的顺序来控制,而是由事件的发生来控制,而这种事件的发生是随机的、不确定的,并没有预定的顺序,这样就允许程序的的用户用各种合理的顺序来安排程序的流程。对于需要用户交互的应用程序来说,事件驱动的程序设计有着过程驱动方法无法替代的优点。它是一种面向用户的程序设计方法,它在程序设计过程中除了完成所需功能之外,更多的考虑了用户可能的各种输入,并针对性的设计相应的处理程序。它是一种“被动”式程序设计方法,程序开始运行时,处于等待用户输入事件状态,然后取得事件并作出相应反应,处理完毕又返回并处于等待事件状态。它的框图如图1所示: 图1事件驱动程序模型 3.1.2 MFC的消息处理 在DOS应用程序下,可以通过getchar()、getch()等函数直接等待键盘输入,并直接向屏幕输出。而在Windows下,由于允许多个任务同时运行,应用程序的输入输出是由Windows 来统一管理的。 Windows操作系统包括三个内核基本元件:GDI, KERNEL ,USER。其中GDI(图形设备接口)负责在屏幕上绘制像素、打印硬拷贝输出,绘制用户界面包括窗口、菜单、对话框等。系统内核KERNEL支持与操作系统密切相关的功能:如进程加载,文本切换、文件I/O,以及内存管理、线程管理等。USER为所有的用户界面对象提供支持,它用于接收和管理所有输入消息、系统消息并把它们发给相应的窗口的消息队列。消息队列是一个系统定义的内存块,用于临时存储消息;或是把消息直接发给窗口过程。每个窗口维护自己的消息队列,并从中取出消息,利用窗口函数进行处理。框图2如下:

单文档和多文档窗口使用方法解析

单文档和多文档窗口使用方法解析 一.实验目的 掌握利用开发平台创建单文档和多文档窗口方法 掌握在窗口中输出文字、图形的方法及 MFC 中相关类的使用 二.实验要求 1 创建一个单文档窗口,在文档类定义一个整型变量,其取值范围从 0 ~ 1000 循环,在视图的中间显示该数字,当用户点击窗口的不同区域时,变量值按不同的增量增加并显示。 提示:在修改数据后,使用 Invalidate() 函数引起 MFC 对 OnDraw() 的调用,这样就可以用修改后的数据进行画图了。关于对文档类的访问,见本实验的技术支持。 2 创建一个单文档窗口,鼠标在窗口上单击后在鼠标的位置显示一正方形,点击 20 次后清窗口,新的点击将不再增加新的正方形,而是将已输入的正方形在原位置显示,当然,在每20 单击后要重新清窗口。(要求用 MFC 的通用类保存单击的信息,如 CList 类) 知识点:画线 当单击鼠标左键时,就可以获得一个点,即线条的起点。接着按住鼠标左键并拖动一段距离后松开鼠标,此时也可以获得一个点,即线条的终点。也就是说,我们需要捕获两个消息,一个是鼠标左键按下消息(WM_LBUTTONDOWN),在该消息响应函数中可以获得将要绘制的线条的起点;另一个是鼠标左键弹起来的消息(WM_LBUTTONUP),在该消息响应函数中可以获得将要绘制的线条的终点。有了这两个点就可以绘制出一条线。 利用SDK全局函数实现画线功能 为了进行绘图操作,必须获得一个设备描述表(DC),因此,首先定义一个HDC类型的变量:hdc,接着调用全局函数GetDC获得当前窗口的设备描述表。因为CWnd类有一个成员变量(m_hWnd),而CView类派生于CWnd类,因此该类也有这样的一个成员变用于保存窗口句柄,而GetDC函数可以直接把这个成员变量作为参数来使用。 利用MFC的CDC类实现画线功能 该类提供一个数据成员m_hDC类用来保存与CDC相关的DC句柄。其道理与CWnd 类提供成员变量m_hWnd保存与窗口相关的窗口句柄是一样的。 CDC* pDC = GetDC(); pDC->MoveTo(m_ptOriginal); pDC->LineTo(point); ReleaseDC(pDC);

MFC多文档多视图编程

深入了解MFC中的文挡/视结构 李泽宇金刚熊联欢姜军 (华中理工大学图象识别与人工智能研究所) Visual C++ 5.0 以其功能强大、用户界面友好而倍受程序员们的青睐。但是,在当前的Microsoft 基本类库4.2 版本中,大约有将近200 个类,数千个函数,加之Microsoft 公司隐藏了一些技术细节,使得人们深入学习MFC变得十分困难。 MFC的AppWizard可以生成三种类型的应用程序:基于对话框的应用、单文档应用(SDI)和多文档应用(MDI)。前两者的结构较简单,本文不再赘叙。笔者拟从MFC中的文档/视结构入手,分析一些函数的流程,并解决编制MDI 应用程序过程中的一些常见问题。 (一)、了解文档/视结构 MFC应用程序模型历经多年以有了相当大的发展。有一个时期,它只是个使用应用程序对象和主窗口对象的简单模型。在这个模型中,应用程序的数据作为成员变量保持在框架窗口类中,在框架窗口的客户区中,该数据被提交显示器。随着MFC2。0的问世,一种应用程序结构的新方式----MFC文档/视结构出现了。在这种结构中,CFrameWnd繁重的任务被委派给几个不同类,实现了数据存储和显示的分离。一般情况下,采用文档/视结构的应用程序至少应由以下对象组成: 。应用程序是一个CwinApp派生对象,它充当全部应用程序的容器。应用程序沿消息映射网络分配消息给它的所有子程序。 。框架窗口是一CfrmeWnd派生对象。 。文档是一个CDocument派生对象,它存储应用程序的数据,并把这些信息提供给应用程序的其余部分。 。视窗是Cview派生对象,它与其父框架窗口用户区对齐。视窗接受用户对应用程序的输入并显示相关联的文档数据。 通常,应用程序数据存在于简单模型中的框架窗口中。在文档/视方式中,该数据移入称为document 的独立数据对象。当然,文档不一定是文字,文档是可以表现应用程序使用的数据集的抽象术语。而用户输入处理及图形输出功能从框架窗口转向视图。单独的视窗完全遮蔽框架窗口的客户区,这意味着即使程序员直接绘画至框架窗口的客户区,视图仍遮蔽绘画,在屏幕上不出现任何信息。所以输出必须通过视图。框架窗口仅仅是个视图容器。 CDocument类对文档的建立及归档提供支持并提供应用程序用于控制其数据的接口。MDI应用程序可以处理多个类型的文档,每个类型的文档拥有一个相关联的文档模板对象。文档对象驻留在场景后面,提供由视图对象显示的信息。文档至少有一个相关联的视图。视图只能与一个文档相关联。 在文档/视方式中,对象的建立是由文档模板来管理的,它是CDocTemplate派生对象,建立并维护框架窗口,文档及视。 MFC调用命令处理程序以响应发生在应用程序中的事件。命令发送的优先级是: 活动的视图->框架窗口->文档->应用程序->默认窗口过程(DefWindowsProc) 总之,在文档/视方式中,文档和视是分离的,即:文档用于保存数据,而视是用来显示这些数据。文档模板维护它们之间的关西。这种文档/视结构在开发大型软件项目时特别有用。

MFC单文档多视图分割

MFC视图分割有两种方法,一种动态分割,一种静态分割。但是动态分割中,对于单文档只能对应于同一个类窗口,这里不适用所以不做过多研究,重点看静态分割的方法。 MFC中封装了CSplitterWnd类可用于视图的分割。 首先在CMainFrame类中添加CSplitterWnd的对象,然后重写CMainFrame 类的OnCreateClient函数,在该函数中进行视图的分割。 在OnCreateCinent函数中,先定义CRect rect,调用函数Getclient(&rect)用来获取主视图窗格的大小,然后调用CSplitterWnd的成员函数CreateStatic 函数来对视图进行分割,函数原型如下, BOOL CreateStatic( CWnd* pParentWnd, //父框架视图对象 int nRows, //行数 int nCols, //列数 DWORD dwStyle = WS_CHILD | WS_VISIBLE, //风格,可直接用默认 UINT nID = AFX_IDW_PANE_FIRST //此窗口的子窗口ID。如果这个分隔器窗口不是嵌套在另一个分隔器窗口中的,则这个ID可以是AFX_IDW_PANE_FIRSH。); 父框架视图对象为this表示第一次分割,这时只需定义要分割的行数和列数即可。如果已经产生了第一次分割,需要对子窗口进行再分割,则这时候pParentWnd为第一次用于分割的CSplitterWnd的对象指针,再新定义CSplitterWnd对象用于第二次分割,这时nID是要被分割的窗口ID, m_wndSplitter1.IdFromRowCol(1, 0)。 在分割完窗口后,对分割完成的视图创建窗格,此时调用CSplitterWnd的CreateView函数,函数原型如下, virtual BOOL CreateView( int row, //要被创建的视图行 int col, //要被创建的视图列 CRuntimeClass* pViewClass, // RUNTIME_CLASS(窗格的类名) SIZE sizeInit, //指定窗格的大小CSize(rect.Width()/3, rect.Height()/2) CCreateContext* pContext //pContext );

SDI(单文档界面)

英文全称Single Document Interface 如果使用过基于 Windows 的应用程序,也许已经注意到不是所有用户界面看上去或操作起来都一样。用户界面样式主要有两种:单文档界面(SDI) 和多文档界面(MDI)。SDI 界面的一个示例就是Microsoft Windows 中的WordPad(记事本)应用程序(图 6.1)。在WordPad 中,只能打开一个文档,想要打开另一个文档时,必须先关上已打开的文档。 图记事本,一个单文档界面(SDI) 应用程序 象Microsoft Excel 和 Microsoft Word for Windows 这样的应用程序就是MDI 界面;它们允许同时显示多个文档,每一个文档都显示在自己的窗口中(图 6.2)。按照是否包含有能在窗口或文档之间进行切换的子菜单的Windows 菜单项,就能识别出 MDI 应用程序。 图Microsoft Excel,一个多文档界面 (MDI) 应用程序 要决定哪种界面样式最好,需要看应用程序的目的。一个处理保险索赔的应用程序可能要用多文档界面MDI 样式,一个职员很可能会同时处理一个以上索赔,或者需要对两个索赔进行比较。另一方面,日历程序最好设成SDI(单文档界面)样式,因为不大需要同时打开一个以上日历;在极少的情况下,可以再打开一个单文档界面应用程序的实例。 SDI 样式更常用,《程序员指南》中的大多数实例都采用SDI 应用程序。关于创建 MDI 应用程序有一些需要单独考虑的问题和技巧,放在本章后面“多文档界面 (MDI) 应用程序”一节。

除了以上两个最常用的界面样式SDI 与MDI 外,第三种界面样式变得越来越流行,这就是资源管理器样式的界面(图 6.3)。资源管理器样式界面是包括有两个窗格或者区域的一个单独的窗口,通常是由左半部分的一个树型的或者层次型的视图和右半部分的一个显示区所组成,如在Microsoft Windows 的资源管理器中所见到的那样。这种样式的界面可用于定位或浏览大量的文档、图片或文件。 图Windows 的资源管理器,资源管理器样式的界面 除了本章所附的 MDI 与SDI 应用程序示例,实用程序向导还提供了一种比较界面样式差别的方法。可以用向导来为每一种样式生成一个框架,然后观察它生成的窗体与代码。 此外,在AUTO CAD绘图程序中,有SDI 口令,通过该口令可以设置CAD程序是当文档显示或多文档显示。SDI有0、1两个值。当设置为0时,为单文档显示;设置为1时为多文档显示,即每次打开一个图形文件,都会启动一次CAD程序。

金融经济学十讲——史树中

1、一般经济均衡: 假定市场上一共有k 种商品,每一种商品的供给和需求都是这k 种商品的价格的函数。 这k 种商品的供需均衡就得到k 个方程。 但是价格需要有一个计量单位,这k 种商品的价格之间只有k-1 种商品的价格是独立的。 瓦尔拉斯又加入了一个财务均衡的关系,即所有商品供给的总价值应该等于所有商品需求的总价值。这一关系目前就称为“瓦尔拉斯法则”,它被用来消去一个方程。 2、从“华尔街革命”追溯到1900年 ?3、对每一固定收益都求出其最小风险,那么在风险-收益平面上,就可画出一条曲线,它称为组合前沿。马科维茨理论的基本结论是:在证券允许卖空的条件下,组合前沿是一条双曲线的一支;在证券不允许卖空的条件下,组合前沿是若干段双曲线段的拼接。 组合前沿的上半部称为有效前沿。对于有效前沿上的证券组合来说,不存在收益和风险两方面都优于它的证券组合。 ?4、夏普:假定所有投资者都以马科维茨的准则来决策,而导出全市场的证券组合的收益率是有效的以及所谓资本资产定价模型(Capital Asset Pricing Model, CAPM)。这一模型认为,每种证券的收益率都只与市场收益率有关。 5、米勒与莫迪利阿尼:探讨“公司的财务政策(分红、债权/股权比等)是否会影响公司的价值”这一主题。他们的结论是:在理想的市场条件下,公司的价值与财务政策无关。后来他们的这些结论就被称为莫迪利阿尼-米勒定理(Modigliani-Miller Theorem,MMT ?无套利假设是指在一个完善的金融市场中,不存在套利机会(即确定的低买高卖之类的机会)。因此,如果两个公司将来的(不确定的) 价值是一样的,那么它们今天的价值也应该一样,而与它们财务政策无关;否则人们就可通过买卖两个公司的股票来获得套利。‘ ?布莱克和肖尔斯先把模型连续动态化。他们假定模型中有两种证券,一种是债券,它是无风险证券,其收益率是常数;另一种是股票,它是风险证券,沿用马科维茨的传统,它也可用证券收益率的期望和方差来刻划,但是动态化以后,其价格的变化满足一个随机微分方程,其含义是随时间变化的随机收益率,其期望值和方差都与时间间隔成正比。这种随机微分方程称为几何布朗运动。 ?然后,利用每一时刻都可通过股票和期权的适当组合对冲风险,使得该组合变成无风险证券,从而就可得到期权价格与股票价格之间的一个偏微分方程,其中的参数是时间、期权的执行价格、债券的利率和股票价格的“波动率”。出人意料的是这一方程居然还有显式解。于是布莱克-肖尔斯期权定价公式就这样问世了。 6、布莱克-肖尔斯公式的成功也是用无套利假设来为金融资产定价的成功。这 一成功促使1976 年罗斯(S. A. Ross, 1944~) 的套利定价理论(APT, Arbitrage Pricing Theory) 的出现。 如果证券组合的风险越来越小,那么它的收益率就会越来越接近无风险收益率。 7、金融经济学就在很大程度上离开了一般经济均衡框架,而只需要从等价于无

多视图开发实例讲解

VC项目开发之单文档多视图实现 多视图是VC开发中经常要用到的技术之一,一般地实现单文档多视图有两种方式1)通过视图分割的技术(使用CSplitterWnd实现),将窗口分割为多个部分,每个部分显示各自显示不同的视图,这种技术实现起来比较简单,并且相关的资料也很多。2)通过一个文档关联多个视图,窗口显示整个视图。第二种实现较第一种复杂,这里给出详细的实现方法。 Step 1:使用VC 6.0新建一个Project,命名为:MultiView。除选择单文档属性外,一切使用“默认”方式。于是你可以获得五个类:CMainFrame ,CMultiViewApp,CMultiViewDoc,CMultiViewView,和CAboutDlg; Step 2:新建一个新的视图View,添加一个新的MFC Class(Insert->New Class),基类为CView(或者CView的派生子类,如CEditView等)。类的名字为CAnotherView,这就是新的视图;并为CAnotherView添加GetDocument的实现: CMultiViewDoc* CAnotherView::GetDocument() { return (CMultiViewDoc*)m_pDocument; } Step 3:在CMultiViewApp添加成员变量记录这两个视图: private: CView* m_pFirstView; CView* m_pAnotherView; 给程序菜单IDR_MAINFRAME添加一个菜单项目“视图”,该菜单项有两个子菜单“视图一”和“视图二”,添加相应函数(void CMultiViewApp:: OnShowFirstview()和void CMultiViewApp:: OnShowSecondview()); Step 4:创建新的视图:在BOOL CMultiViewApp::InitInstance()中添加代码:

金融经济学导论第1章讲义

为什么我们需要金融市场和金融机构呢? 一个金融体系是由一系列的机构和市场所组成,它们允许交换合约和提供服务,其目的是使得经济代理人(economic agents)的收入流和消费流不同步,即让它们缺少相似性。 这一功能有两个维度:时间维度(time dimension)和风险维度(risk dimension)。 金融:时间维度(time dimension) 为什么将消费和收入夸时分离是有用的呢? 理由1:收入在离散的时间情况下获得(比如一个月),而与此同时按照人们的习惯,消费是连续的(即每天)。 理由2:消费支出决定了生活水平,绝大多数人都发现要逐月逐年的改变他们的生活水平是困难的。这样就有了对平稳消费流的要求。 平稳消费流的要求具有普遍性,深深的影响着每个人的,因此这一要求最重要的表现就是在于为退休而储蓄的需要,即消费小于收入,这样才能使退休后消费流超过收入,即动用储蓄。 对于较短时期的情况,平稳消费流的要求同样需要。例如,消费和收入的季节性模式:特定的个体(汽车销售员、百货公司销售员)可能会经历由于季节性事件(如绝大多数的新车都是在春季和夏季销售的)所导致的收入波动,而他们不希望这一波动影响到他们的消费。同样由于营业周期性波动而导致的暂时性失业也会产生这一问题,工人不想因为暂时的失业而失去了可持续的收入时,工人们不希望他们家庭的消费大大下降。 因此,金融中第一个关键的要素就是时间 (勤俭创业的企业家) 在一个不受时间影响的世界中,将没有资产,没有金融交易(虽然人们使用货币,但货币仅具有交易的功能),也没有金融机构。 持有资产则使得消费流和收入流不同步。例如农民留着种子、守财奴将金子埋起来或老奶奶将钞票放在床底下,都会使他们的消费和收入不同步,这样做,是为了让他们自己有一个更高水平的福利。 一个完全发达的金融体系应当具备有效完成这一同样功能的性质。因此金融体系应当提供多功能的、各种各样的金融工具,在贷款规模、贷款时间的选择和贷款到期日以及金融工具的流动性等方面,满足存款人和借款人普遍不同的需求。

VC++多文档编程

教案 2007 ~2008 学年第一学期 主讲教师 课程名称面向对象程序设计(VC++)课程类别专业基础课 学时及学分80、4 授课班级 使用教材 VC++的使用及面向对象软件工程实例分析 系(院、部) 教研室(实验室) 计算机应用教研室

课时授课计划 课次序号: 一、课题:ch6 多文档编程 二、课型:讲授 三、目的要求: 1、理解多文档程序的结构,熟悉多文档窗口的特点。 2、掌握多文档程序的设计方法。 3、熟悉视图分割的方法和应用。 四、重点、难点: 重点:多文档程序的结构和设计方法。 难点:多文档程序中视图与文档的交互作用较难理解。 五、教学方法及手段: 案例式教学:设计目标、关键技术、结合实例讲解语法、总结。 六、参考资料: 《面向对象程序设计与VC++实践》揣锦华编著,西安电子科技大学出版社,第11章 《C++面向对象程序设计》李涛编著,高等教育出版社,第9章 七、作业: 习题6.2 6.3 6.4 6.6 八、授课记录: 九、授课效果分析:

十、教学进程(教学内容、教学环节及时间分配等) 1、复习 多文档程序的框架结构:5个主要的类比如, 创建多文档程序ex_mdi,包含的主要类有:CmainFrame Cex_mdiView Cex_mdiDoc Cex_mdiApp CchildFrame 与单文档程序相比,多了一个子窗口类类CchildFrame 2、导入课题 多文档程序可以运行用户同时打开和使用多个文档,比单文档程序更方便,比如Word、Excel等。 3、教学内容 ch6.1 多文档程序的结构和多文档窗口特点 [通过实例分析] 例6-1:建立一个多文档应用程序,用户能打开多个文档,并能在多个文档中输入信息,并可以利用“保存/另存为”保存每个文档中输入的信息,也可以利用“打开”新建的子窗口显示文件的内容。 关键技术: 利用视图类的ONCHAR消息映射函数OnChar实现键盘输入; 利用文档的串行化实现数据的保存、文件的打开。 实现过程: (1)建立单文档应用程序ex_mdi (2)为文档类Cex_mdiDoc添加一个字符串变量,用于保存输入的字符串。 CString m_strText; (3)在文档类Cex_mdiDoc的构造函数中初始化字符串变量。 m_strText.Empty(); //初始化字符串为空 (4)处理键盘输入:为视图类添加WM_CHAR消息映射函数OnChar(),在函数 中添加“取得输入字符”代码: pDoc->m_strText+=nChar; Invalidate(); //强迫调用OnDraw()函数,更新视图 [运行:从键盘输入,但看不见输入的信息] (5)在视图中显示输入的内容:在视图类的OnDraw()中添加输出代码。 pDC->TextOut(0,10,pDoc->m_strText);

单文档视图结构ActiveX控件

单文档/视图模式是MFC编程里比较强大的一种编程模式,如果ActiveX控件能够用这种模式的话,将可以做出非常强大的Web在线应用。 下面我们就介绍一种把单文档/视图模式的程序改造成ActiveX控件的方法。 做起来很难,但是完成了会很有成就感,本方法来源于15Seconds。在VC6.0和https://www.doczj.com/doc/f614651798.html,下都已证明可行。我用这个方法做了一个Web上的在线服装设计软件,Client 端支持NT4.0,客户公司有上千台NT4.0。据美国同事说在投标中击败了Altium公司(电路设计软件Protel的开发商)的方案,哈。 需要要两个文件: // ActivDoc.cpp : implementation file // #include "stdafx.h" #include "ActivDoc.h" CActiveXDocTemplate::CActiveXDocTemplate(CRuntimeClass* pDocClass, CRuntimeClass* pFrameClass, CRuntimeClass* pViewClass) : CSingleDocTemplate(IDR_NOTUSED, pDocClass, pFrameClass, pViewClass) { ASSERT(pFrameClass); } CFrameWnd* CActiveXDocTemplate::CreateDocViewFrame(CWnd* pParen tWnd) { CWaitCursor cursor; TRY { ASSERT(pParentWnd && IsWindow(*pParentWnd)); ASSERT_KINDOF(CActiveXDocControl, pParentWnd); m_pParentWnd = pParentWnd; m_pFrameWnd = NULL; // OpenDocumentFile is a virtual method (implemented in

单文档多视图

相信这就是vc的弊病吧!项目作了很久发现应该用多视图,可是刚开始建立工程的时 候考虑不周阿,没办法,只能从网上搜了,竟搜到了一个不错的函数可以解决这个问题:void CMainFrame::SwitchToView(int nForm) { //CDocument* pDoc = GetActiveDocument(); CView *pOldActiveView=GetActiveView(); //保存旧视图 CView *pNewActiveView=(CView*)GetDlgItem(nForm); //取得新视图 if(pNewActiveView==NULL) { switch(nForm) //这些ID是对话框的标志符,但也可以用其他的标志 { case IDD_PLANT_VIEW : pNewActiveView=(CView*)new CPlantView; break; case IDD_HSUB_VIEW : pNewActiveView=(CView*)new CHSubView; break; } CCreateContext context; //将文挡和视图相连 context.m_pCurrentDoc=pOldActiveView->GetDocument(); pNewActiveView->Create(NULL,NULL,WS_BORDER|WS_CHILD,CFrameWnd::rectDefault,this,nForm, &context); pNewActiveView->OnInitialUpdate(); } SetActiveView(pNewActiveView); //改变活动的视图 pNewActiveView->ShowWindow(SW_SHOWMAXIMIZED); //显示新的视图 pOldActiveView->ShowWindow(SW_HIDE); //隐藏旧的视图 pNewActiveView->GetDocument()-SetTitle(\"。。。。\"); if(pOldActiveView->GetRuntimeClass() ==RUNTIME_CLASS(CHSubView)) pOldActiveView->SetDlgCtrlID(IDD_HSUB_VIEW); else if(pOldActiveView-GetRuntimeClass() ==RUNTIME_CLASS(CPlantView)) pOldActiveView-SetDlgCtrlID(IDD_PLANT_VIEW); pNewActiveView-SetDlgCtrlID(AFX_IDW_PANE_FIRST); delete pOldActiveView; //删除旧视图 RecalcLayout(); //调整框架窗口 }; 这个函数很好用大家可以参考一下。其中IDD_HSUB_VIEW 等都是新建立的FormView,也就是继承了CFormView类的新类。注意将各个新类中的构造函数改成public,才能用此函数不出错。 由于最近做的一个程序用到了单文档多视图切换,所以把它总结一下。内容如下:

基于单文档的(MFC)窗口分割

基于单文档的窗口分割 简介部分是对于MFC应用程序的介绍,在博客上看到的,觉得受益匪浅,所以写到这里。不需要的朋友可以从第二部分程序设计开始看起。

目录 基于单文档的窗口分割 (1) 简介 (3) MFC应用程序类型简介 (3) 单文档与多视图 (5) 单文档多视图程序设计 (6) Step1:创建单文档的MFC程序 (6) Step2:声明相关的变量。 (6) Step3:重载OnCreateClient()函数,进行窗口的分割 (7) Step4:设置行列初始值 (9) 附:代码 (10)

简介 MFC应用程序类型简介 在Microsoft VC++ 6.0中,基于MFC的应用程序一般分为以下几种: 多文档界面(MDI) 单文档界面(SDI) 基于对话框的应用程序。 图1-1 应用程序类型 其中单文档又可分为单视图的和多视图的。

图1-2 单文档单视图 图1-3 单文档多视图 一般情况下,单文档仅需要单视图就够了,如Windows自带的记事本、画图程序等等,但

在一些情况下,单文档需要多视图支持,比如同时观察文档的不同部分,同时从不同的角度观察同一文档等。 在MFC的框架下,文档对象(CDocument)有一个保存其所有视图的列表,并提供了增加视图(AddView)与删除视图(RemoveView)函数,以及当文档内容改变时通知其所有视图的方法(UpdateAllViews)。 1-4 类视图 通过多文档框架的窗口复制机制和单文档框架的分割窗口机制是实现单文档多视图的主要方法。单文档与多视图 一般地,单文档与多视图有三种情况: 1)在多文档界面MDI中,每个视图位于MDI的一个独立子文档框架中,视图对象基于同一个视图类。用户可以通过“窗口|新窗口”菜单,为同一文档的视图再创建一个窗口,通过新创建的窗口,可以编辑和观察文档的另一部分,同一文档各个视图之间自动实现同步,用户修改一个视图的内容,在另外的视图中也自动更新。 MFC框架通过复制原来的子框架窗口和其中的视图来实现上面的功能,并且是完全自动的。 2)视图对象基于同一视图类,所有视图位于同一文档框架中。 分割窗口将单文档窗口的视图区分割成几个独立的视图,框架从同一视图类创建多个视图对象。Word的子窗口即属于这种类型。 3)视图对象基于不同的视图类,所有的视图位于同一文档框架中。 多个视图共享同一文档框架,但从不同的视图类创建,每个视图可以为文档提供不同的观察和编辑方法。比如在一个窗口里观察文档的不同部分,或者是在一个窗口里用不用类型的视图观察同一个文档。这种类型的实现方法是通过重载框架类CMainFrame的成员函数OnCreateClient实现,用户可以根据不同需要将窗口分为垂直或水平的多个分割窗口。

MFC多文档和单文档视结构

MFC多文档和单文档视结构 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ //这一页的代码最重要了,呵呵……什么都在这里面呢; 单文档新建: CWinApp_________docManager->docSingleTemplate 的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 多文档新建: CWinApp_________docManager->docMultTemplate的OpenDocumentFile函数参数为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 单文档打开:CWinApp_________docManager中经过一个

打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调 用父类的此函数___________docSingleTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 多文档打开:CWinApp_________docManager中经过一个 打开对话框传递参数,中途还调用了APP的OpenDocumentFile,当然如果我们的APP重载了这个函数也要调用我们的但是我们的函数一定别忘记最后返回是调 用父类的此函数___________docMultTemplate的OpenDocumentFile函数参数不为空,此函数完成了大部分东西,包括新建文档类框架类等______________然后是调用CDocument就没什么意思了,当然我们要是重载了CDocument的新建函数就是调用子类虚函数。 他们两个只有在docMultTemplate和docSingleTemplate的OpenDocumentFile函数中的动作不同,单文档负责新建框架类和视类但是如果存在了我们就不重建了,只是给其赋值。而多文档无论如何都会新建一个视类和框架类文档类,这也就是为什么他是多文档结构的原因。

使用VC++实现单文档多视图的一种方法

使用VC++实现单文档多视的程序框架 91550部队指控中心池晓春赵鹤群 摘要:本文分析了在对同一数据源使用多种形式显示的情况下,采用单文档多视的程序框架开发显示软件的原因,介绍了单文档多视框架(SDMV)的实现方法,并在Windows 2000环境下,使用Visual C++ 6.0创建开发单文档多视框架的示例程序。 关键词:单文档多视(SDMV)视图切换 1选择SDMV程序框架的原因 程序员使用Visual C++ 6.0开发软件时,为了缩短开发时间和工作量,通常借助AppWizard生成基于MFC的SDI或MDI应用程序框架。但是要实现对同一数据源使用多种形式显示的功能,使用SDI或MDI的框架进行软件开发都有各自的缺陷,不能较好的满足软件需求,这是因为: 使用SDI框架的应用程序具有单一文档和单一视图,即程序运行时只能够生成一个文档类对象和一个视图类对象,虽然满足使用同一数据的要求,但是由于只有一个视图窗口,无法实现以多种形式显示试验数据。 使用MDI框架的应用程序具有多窗口的特点,可以使用多个子窗口来实现对不同数据源的浏览,但它的视图和文档一一对应,即视图+文档构成一个子窗口。由于各个子窗口之间数据相互独立,如果要保持数据同步更新就需要采用特殊的技术,所以对于用户在程序各个窗口之间对同一数据源进行不同形式的浏览,用这种方式实现起来既费时又费力。 由于SDI和MDI这两种Windows标准应用程序框架不能满足软件开发的需要,就特别需要一种被称为“单文档多视”的应用程序框架。顾名思义,该框架用单一的文档类来统一管理应用程序的所有数据,同时用多个视图以多种显示形式(如:表格、曲线、趋势图)等来显示这些数据。程序在任何时刻都可以用同一个窗口,通过切换视图的方法以不同的形式显示同一数据。可以看出,使用SDMV程序框架开发数据显示软件,就能够更好的满足用户的需求。 2SDMV程序框架的实现方法 SDMV程序框架的本质是文档-视图结构,它针对同一数据源使用不同的形式在多个视图中显示。如果数据发生改变,所有和数据相关的视图中的显示内容也会随之改变来反映数据的变化。针对这种特点,可以考虑通过改造SDI框架来实现SDMV框架,借助VC ++提供的AppWizard生成SDI应用程序框架,可以在很大程度上减少工作量,

单文档

MFC是一个编程框架 MFC中的各种类结合起来构成了一个应用程序框架,它的目的就是让程序员在此基础上来建立Windows下的应用程序。MFC框架定义了应用程序的轮廓,并提供了用户接口的标准实现方法。AppWizard可以用来生成初步的框架文件。资源编辑器用于帮助直观的设计用户接口。ClassWizard用来协助添加代码到框架文件,最后,通过类库实现了应用程序特定的逻辑。 MFC提供了一个Windows应用程序开发模式,对程序的控制主要是由MFC框架完成的。而且MFC也完成了大部分的功能,预定义或实现了许多事件和消息处理。框架或者由其本身处理事件,不依赖程序员的代码,或者调用程序员的代码来处理应用程序特定的事件。 1.S DI生成 1.步骤dxq2009 首先,打开VC++6.0开发环境,然后,选择”File”菜单中的“New”子菜单,在弹出的对话框中选择“MFC AppWizard(exe)”项并在“Progect name”编辑框中输入合适的工程名字Simple1,如图,它的意思是创建一个基于MFC的应用,接着进入正式的创建过程,MFC 应用程序的创建过程有6步(基于对话框)或者6步(SDI或者MDI),下面首先介绍SDI 应用的创建过程。 (1)第一步用于选择应用的结构以及语言等。如图1,首先确定应用是否需要Doc/View Architecture Support支持,因为不使用该结构的应用不支持从磁盘文件打开文档,也没有派生于类CWnd的窗口客户区。上面3个单选按钮用于确定创建的应用类型,

包括单文档,多文档,对话框,这里选择第一个。然后从资源列表框选择应用所使用的语言种类,单击“Next”。 图1 (2)第二步为用用程序选择4项数据库支持选项之一:如图2.如果选择了数据库支持,那么单击“Data Source”按钮,选择外部的数据库表项,一般按默认即可,单击“Next”。 图2 (3)第三步选择希望包含在应用中的复合文档支持项,同时判定是否启用标准的ActiveX 资源,以及是否为应用的菜单条添加额外的自动化命令等,如图4,一般安默认,单击“Next”

相关主题
文本预览
相关文档 最新文档