VC++60 第十四章 单文档界面的程序

第十四章 单文档界面的程序

 

用VC++的AppWizard生成的程序有三种样式的界面,它们是单文档、多文档和对话框界面。前面各章我们都生成对话框样式的界面,这可以方便我们学习各种常用控件的设计,本章要学习如何生成一个单文档界面的应用程序,以及文档类和视图类的概念和相互关系。

 

本章要点

1 用AppWizard生成单文档界面的操作方法
2 文档类和视图类的概念
3 如何保持文档和视图的同步关联。

 

14.1 生成单文档界面的文本编辑器

 

用AppWizard生成单文档界面的操作方法和生成对话框界面的操作方法稍有不同,我们通过建立一个“文本编辑器”应用程序MyNote.exe来演示,具体过程如下:

1 打开应用程序向导,在d:\myVC\CH14创建应用程序MyNote。
2 在Step1中选择“单文档”和“文档/视图支持”,如图chap14-01.

VC++60 <wbr>第十四章 <wbr>单文档界面的程序
图chap14-01

 

3 在step2和step3对话框中都用默认的。在step4中如图chap14-02选择前五项,当然也可以按你的需要选择。
VC++60 <wbr>第十四章 <wbr>单文档界面的程序
图chap14-02

4 在Step5中选择MFC标准、加备注和静态连接库。图chap14-03
VC++60 <wbr>第十四章 <wbr>单文档界面的程序
图chap14-03

5 在step6中选择视图的基类(base class),因为我们需要的是文本编辑器,所以要选类CEditView作为基类。点击[完成]按纽,应用程序的框架就创建好了。

 

14.2 文档类和视图类的概念

 

向导工作完成以后马上编译和连接,运行后就可以看到一个已经能够使用的文本编辑器,它不仅可以输入文字,还可以保存或打开文件,与Windows的记事本差不多了,只是没有设置字体的功能。图chap14-04是它运行时的窗口。

VC++60 <wbr>第十四章 <wbr>单文档界面的程序
chap14-04

菜单和工具栏的响应函数都已经生成了相应的代码,我们没有做任何编写工作就得到了一个“完整”的应用程序,甚至还创建了一个帮助文件呢。这就是VC++开发环境的巨大威力!我们从上图中可以看到,编辑菜单中的复制和剪切都已经有效了。

图中的窗口是主框架,对应于类CMainFrame,而其中的“编辑区域”叫用户区,对应于视图类CMyNoteView,而被编辑的文本对应于一个文档类CMyNoteDoc。另外,每个程序还有一个对应于应用程序本身的类,本例中是CMyNoteApp。这四个类就是向导自动生成的应用程序框架类,打开工作区的类classView页区,就可以看到,如图chap14-05。

VC++60 <wbr>第十四章 <wbr>单文档界面的程序
chap14-05

展开视图类,可以找到一个函数GetDocument(),它是使视图(的内容)和文档保持同步关联的纽带。它返回一个CMyNoteDoc类型的对象指针m_pDocument。使用它在视图中访问文档的内容。
在文档类中有一个OnNewDocument()函数,在“新建文件”和程序第一次运行时被调用,它打开一个新文档供用户编辑。我们来看一下它的代码:

BOOL CMyNoteDoc::OnNewDocument()
{
    if (!CDocument::OnNewDocument())
        return FALSE;
    ((CEditView*)m_viewList.GetHead())->SetWindowText(NULL);
    return TRUE;
}

if语句调用其父类的同名函数,第二个语句设置编辑区的文本为空白。你试着用“这是一个新文档”来代替NULL,重新编译和运行,那每次打开时编辑区会出现这句话。
文档类中还有一个叫Serialize,把它系列化对象CArchive& ar设置为按行系列化,这是纯文本文件存取时所需要的。下面是它的代码。

void CMyNoteDoc::Serialize(CArchive& ar)
{
    // CEditView contains an edit control which handles all serialization
    ((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
}

在下一节中,我们将通过一个例程来演示,如何在文档对象和视图对象之间互相访问和交换数据。

 

14.3 Circle程序的界面和功能

 

Circle程序的功能是:用鼠标左键在用户区域任意的点一下,就以这一点为圆心画一个半径为50的圆。程序的界面和上例一样,都是单文档程序的基本形式么。但是其客户区年输入文字,是画图形式的。

 

VC++60 <wbr>第十四章 <wbr>单文档界面的程序
图chap14-06

 

下面我们就来制作这一程序。
1 创建工程
打开应用程序向导,在d:\myVC\CH14创建应用程序Circle。选择“单文档”,后面的应答与上例一样。不同的是最后一步视图基类的选择,不是选CEditView而是选CView。CEditView类是CView类的子类,适合于需要文字编辑的场合。

2 添加变量
画圆需要与圆心和半径,为了文档和视图的同步,我们需要给两者都引进三个变量m_PosX、 m_PosY和m_Reduse。定义要写在他们的构造函数中:

public:
    int m_PosX, m_PosY;
    int m_Reduse ;

3 编写代码
(1)函数OnDraw(CDC* pDC)的功能是在客户区画图,我们用它以试图中的变量值来画圆,代码如下:

void CCircleView::OnDraw(CDC* pDC)
{
    CCircleDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    //Draw a circle
    RECT rect;
    rect.left= m_PosX - m_Reduse ;
    rect.top = m_PosY - m_Reduse ;
    rect.right = m_PosX + m_Reduse ;
    rect.bottom= m_PosY + m_Reduse ;
    pDC->Ellipse(&rect);
}
其中pDC是由参数表传递过来的屏幕设备对象,可以画图。RECT是表示举行的数据结构。是画图圆需要的参数。

(2)变量m_PosX等的值在初始更新函数OnInitialUpdate()中给定,而值是从文档的同名函数中传递过来的。

    CCircleDoc* pDoc = GetDocument();
    m_PosX = pDoc->m_PosX ;
    m_PosY = pDoc->m_PosY ;
    m_Reduse = pDoc->m_Reduse ;

(3)要求当“按下鼠标时画圆”,就要添加OnLButtonDown函数,其中使用Invalidate(),它会调用函数OnDraw重新画客户区,其代码如下:

void CCircleView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: Add your message handler code here and/or call default
    m_PosX = point.x ;
    m_PosY = point.y ;
    Invalidate();
    CCircleDoc* pDoc = GetDocument();
    pDoc->m_PosX = m_PosX;
    pDoc->m_PosY = m_PosY;
    pDoc->SetModifiedFlag(TRUE);
    CView::OnLButtonDown(nFlags, point);
}

变量point对应的是鼠标当前点的位置,传递给视图的变量,然后画圆;再把它传递给文档,这就保证视图和文档数据的一致性。语句

        pDoc->SetModifiedFlag(TRUE);

设置文档已经被修改的标志,这使得程序在退出时会询问“是否要保存?”。

(4)在文档类中有一个函数OnNewDocument(),它是在按“文件/新建”时被调用的。我们用它给出圆的初始值:

   m_PosX = 100;
    m_PosY = 100;
    m_Reduse = 50 ;

需要的代码就这些了,现在可以编译和运行之。

 

思考和练习

1 文档类应用程序是如何保持视图和文档数据的一致性的?
2 在MyNote程序中添加菜单及其代码,扩展它的功能。例如,增加文字的大小和颜色等。
3 在Circle程序中添加菜单及其代码,扩展它的功能。例如,可变的半径,画不同的图形等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章