Lesson 4: DocumentView Architecture

The purpose of an application is to perform operations on a set of data. When you are working on the logical design of your application, you will need to specify how the application data is going to be structured, and how it is to be presented to users so that they can interact with it.

The MFC document/view architecture provides a single, consistent way of co-ordinating application data as well as views of that data. The document/view architecture is implemented by the classes created when you generate an application using the AppWizard. This lesson will describe the features of the document/view architecture and explain how the application framework implements it.

After this lesson, you will be able to:

  • Describe the features of the document/view architecture and the benefits they offer to the application developer.
  • Describe how the application framework objects act together to implement the document/view architecture.
  • Describe how the document/view architecture can be used to display a visual representation of the application data on an output device such as a screen or a printer.
Estimated lesson time: 40 minutes

Documents and Views

In the MFC framework, a document is simply an object that acts as a container for the application data. A view is a window object, usually associated with the client area of an onscreen window, through which the user interacts with the data contained in the document.

This logical separation of application data and its visual representation means that a document can be associated with a number of different views. For example, when editing a Microsoft Word document, you can switch between Normal View, Page Layout View, and Outline View. All of these views draw upon the same data—they simply display it differently. Any changes made in one view are reflected in the other views.

Benefits of the Document/View Architecture

The document/view architecture assists you by simplifying the process of rendering application data on the screen in a way that enables users to interact with the data. This functionality can be designed completely from scratch through the overloading of the view's drawing function, the handling of mouse and keyboard interaction with the view, and the handling of menu commands. Alternatively, you can elect to use a predefined view that is based on a control. These capabilities let you develop an application similar to Windows Explorer by using a Tree View and a List View side by side in a split window. An Edit View, based on a rich-text edit control, can be used as the basis of a text-editor.

The document/view architecture also simplifies printing and print previewing by using the same drawing logic (contained in the view's drawing function) to render the application's data on the view, on a print preview window, or on a printer.

The document/view architecture provides much of the logic for saving documents to disk and loading them back into memory. This process of saving and loading documents, known as serialization, allows you to save and retrieve data in the custom object format used by your application, as well as in any of the object formats derived from the MFC CObject class. Serialization of application data is covered in Chapter 6, Persistent Data.

Document/view architecture is important because applications that use documents and views derive the greatest benefit from the application framework. Although most of the discussion about Visual C++ and MFC functionality assumes the use of the document/view architecture, you can use MFC without implementing a document/view architecture. The benefits associated with document/view architecture also carry with them a potentially significant performance and size cost.

In some cases, document/view might not be the right choice for your application. For example, an application that compresses text files might require only a dialog box that requests file names and displays a progress bar. A main frame window and a view are not needed, so the document/view architecture would provide little, if any, benefit in this instance. In this case, you could use the dialog-based application framework that the AppWizard provides.

SDI and MDI Applications

As you learned in Chapter 2, in addition to generating a dialog-based application, the MFC AppWizard can generate frameworks for two types of document/view-based applications: single document interface (SDI) and multiple-document interface (MDI). SDI applications permit only one document frame window at a time. The Paint and WordPad applications that come with Windows are examples of SDI applications. MDI applications allow multiple document windows to be open within the same instance of an application. In an MDI application, the user can open multiple MDI child windows in the main window. These child windows are themselves frame windows, each containing a separate document. Microsoft Word and Microsoft Excel are examples of MDI applications. The SDI and MDI application types are shown in Figures 3.5 and 3.6.

click to view at full size.

Figure 3.5 An SDI application

click to view at full size.

Figure 3.6 An MDI application

Objects in the Document/View Architecture

The AppWizard generates the basic framework of an MFC document/view application for you. As always, you can modify and extend the generated code to obtain the degree of customization and control that you require.

This framework for documents and views implemented in classes is derived from the MFC base classes CDocument and CView. The CWinApp, CFrameWnd, and CDocTemplate classes work in conjunction with CDocument and CView to ensure that all the pieces of the application fit together.

Table 3.6 lists the application objects and related MFC base classes in a document/view-based application and describes the major tasks each object performs.

Table 3.6 Document/View-Based Application Objects and Related MFC Base Classes

Object Derivation and task
Document Derived from CDocument. Specifies your application's data.
View Derived from CView. As the user's window to the data, the view class specifies how the user sees your document's data and interacts with it.
Frame window Derived from CFrameWnd. Views are displayed inside document frame windows. In an SDI application, the document frame window is also the main frame window for the application.
Document template Derived from CDocTemplate. A document template orchestrates the creation of documents, views, and frame windows. A particular document-template class creates and manages all open documents of one type.
Application Derived from CWinApp. Controls all of the objects in this table and specifies the application's behavior, such as initialization and cleanup.

Document/view application objects cooperatively respond to user actions, bound together by commands and other messages.

Document Template Objects

Document templates are created and maintained by the application object. One of the key tasks performed during your application's InitInstance() function is to construct one or more document templates of the appropriate kind. The following code shows how this is achieved in an SDI application:

 // From CMyAppApp::InitInstance() CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate(      IDR_MAINFRAME,      RUNTIME_CLASS(CMyAppDoc),      RUNTIME_CLASS(CMainFrame),       // main SDI frame window      RUNTIME_CLASS(CMyAppView)); AddDocTemplate(pDocTemplate);

When a document template object is created, it associates a document class with a group of resources (such as menus and icons), a frame window, and a view. The template is added to the application by using the CWinApp::AddDocTemplate() function.

In an SDI application, the user views and manipulates a document through a view contained inside the main frame window, derived from CFrameWnd. Figure 3.7 shows the relationship between the document/view objects in a running SDI application.

Figure 3.7 Objects in an SDI application

MDI applications use a CMultiDocTemplate object, which keeps a list of many open documents of one type. MDI applications use a class derived from CMDIFrameWnd to implement the application main window. Views are contained within MDI child windows, implemented by the CMDIChildWnd class. An MDI child window looks much like a typical frame window, except that it appears inside an MDI frame window rather than on the desktop. An MDI child window does not have a menu bar of its own, but instead shares the menu of the MDI frame window. The framework automatically changes the MDI frame menu to represent the currently active MDI child window.

The construction of an application's CMultiDocTemplate object is illustrated in the following code snippet.

 // From CMyMDIAppApp::InitInstance()    CMultiDocTemplate* pDocTemplate;    pDocTemplate = new CMultiDocTemplate(        IDR_MYMDIATYPE,        RUNTIME_CLASS(CMyMDIAppDoc),        RUNTIME_CLASS(CChildFrame), // custom MDI child frame        RUNTIME_CLASS(CMyMDIAppView));    AddDocTemplate(pDocTemplate);

Document Objects

The document object in an MFC document/view application is implemented in a class derived from CDocument. This class loads, stores, and manages the application's data. It will also contain the functions that are used to access and work with that data. To support the close connection between documents and views, each document object maintains a list of all the associated views, accessed through the CDocument::GetFirstViewPosition() and CDocument::GetNextView() functions.

The CDocument class also provides the UpdateAllViews() member function, which iterates through all the views associated with a document and notifies each one that it should redraw itself (by calling the CView::OnUpdate() member function).

Your application's views should be updated whenever changes are made to the application data that affect how that data will appear on the screen.

View Objects

The view object physically represents the client area of an application. Logically it represents a view of the information contained in the document class and allows the user input through the mouse and keyboard. Whereas a document object can have any number of views associated with it, a view always belongs to just one document. Views in your application will be derived from the CView class unless you specify that the AppWizard should use one of its specialized subclasses. These include CScrollView, which will provide your view with scrolling functions; and CListView and CTreeView, which allow you to base the representation of your data on the list and tree common controls.

The CView class provides a GetDocument() member function, which supplies a pointer to the associated document object.

Drawing, Printing, and Print Preview Architecture

The final section of this lesson takes a closer look at the CView class and how it is used to display a visual representation of the application data on an output device, such as a screen or a printer.

Device Contexts and the GDI

Windows provides a layer of abstraction between applications and output devices, known as the Graphics Device Interface (GDI). The GDI presents a standard programming interface to applications, allowing you to write code that is guaranteed to produce consistent output on all GDI-compatible devices.

The GDI manages a data structure called a device context, which maintains information about the current drawing attributes of a device. This might include information such as the color palette, the text font, the width of the pen used to draw lines, and the brush style used to fill areas. The Windows API provides a number of GDI functions for drawing lines and shapes, filling areas, and printing text. These functions render their output to a device context—they take a handle to a device context as a parameter.

In MFC, the device context, as well as many general GDI operations, is encapsulated by the CDC class, which provides creation and initialization functions for a device context and drawing functions that you can use to render your application's output. A number of classes that provide for a variety of specific needs are derived from CDC, including those listed in Table 3.7.

Table 3.7 CDC Derived Classes

CDC Derived Class Description
CPaintDC Encapsulates a device context that is prepared for painting an invalid region of a client window, in response to a WM_PAINT message. The constructor calls CWnd::BeginPaint(), which creates the device context and prepares the client area for graphic output. The destructor calls CWnd::EndPaint() to perform clean up operations.
CClientDC Encapsulates a device context that represents only the client area of a window.
CWindowDC Encapsulates a device context that represents the whole window, including its frame.
CMetafileDC Encapsulates drawing into a Windows metafile—a collection of structures that stores a picture in a device-independent format.

Drawing in a View

The graphical output of your application's data is handled by the view object's OnDraw() member function. The CView-derived class that AppWizard generates for you provides a stub OnDraw() function, to which you must add code to display a representation of your application data. The stub OnDraw() function looks like this:

void CMyAppView::OnDraw(CDC* pDC) {      CMyAppDoc* pDoc = GetDocument();      ASSERT_VALID(pDoc);      // TODO: add draw code for native data here }

Note that a pointer to a CDC object is passed to the OnDraw() function. This pointer is used to call the device context drawing functions to render your application's output. Note, also, that the stub implementation sets up a pointer to your application's document object. You use this pointer to retrieve the application data.

The following exercise demonstrates a very simple implementation of the OnDraw() function.

  • To implement the OnDraw() function
    1. Return to the MyApp project you created in the previous lesson.
    2. In ClassView, right-click the CMyAppDoc class icon.
    3. On the shortcut menu that appears, click Add Member Variable.
    4. In the Add Member Variable dialog box, type CString in the Variable Type box and m_string in the Variable Name box.
    5. Leave the Access type set as Public and click OK to create the variable.
    6. Expand the CMyAppDoc class icon and confirm that the m_string member variable has been added.
    7. Locate the CMyAppDoc constructor icon, the member function displayed beneath the CMyAppDoc class icon with the name CMyAppDoc. Note the key icon, which indicates a protected class member. Double-click the CMyAppDoc constructor icon to edit the constructor code.
    8. Add the following line of code to the body of the constructor:
    9. m_string = "Hello World!";

    10. Expand the CMyAppView class icon. Double-click the OnDraw() function icon to edit the function code.
    11. Add the following code to the OnDraw() function in place of the //TODO comment:
    12. CSize TextSize = pDC->GetTextExtent(pDoc->m_string); CRect rect(10, 10, 10+TextSize.cx, 10+TextSize.cy); rect.InflateRect(4, 4); pDC->Rectangle(&rect); pDC->TextOut(10, 10, pDoc->m_string);

    13. Build and run the program. Check that "Hello World!" is displayed inside a rectangle in the upper left corner of your application's view.

    You will learn more about displaying application output in Chapter 5, Implementing Application Behaviors. For now, note the following points:

    • The device context pointer is used to call the GDI member's functions of the MFC CDC class to display the application output.
    • The document pointer is used to retrieve application data.
    • The drawing code is designed so that when the application data changes, it will always be displayed in a consistent fashion—the rectangle will always neatly frame the text. Try assigning a longer string to the CMyAppDoc:: m_string member in the CMyAppDoc constructor. Recompile and rerun the program to verify that it displays correctly.

    How OnDraw() is Called by the Framework

    When a document's data changes in a way that will affect the visual representation of the data, the view must be redrawn to reflect the changes. Typically, this happens when the user makes a change through a view on the document. Any code that updates the document data should call the document's member UpdateAllViews() function to notify all views on the same document to update themselves.

    UpdateAllViews() calls each view's OnUpdate() member function. The default implementation of OnUpdate() invalidates the view's entire client area. You can override OnUpdate() to invalidate only those regions of the client area that map to the modified portions of the document.

    When a view becomes invalid, Windows sends it a WM_PAINT message. The view's default OnPaint() handler function responds to the message by creating a device context object of class CPaintDC and passing it to the view's OnDraw() member function. You have already seen how the OnDraw() function uses this device context object to draw a representation of your data.

    Printing and Print Preview

    In Windows programming, sending output to the printer is very similar to sending output to the screen. This is because the GDI is hardware-independent. You can use the same GDI functions for screen display or for printing simply by using the appropriate device context. If the CDC object that OnDraw() receives represents the printer, the output from OnDraw() goes to the printer.

    This explains how MFC applications can perform simple printing without requiring extra effort on your part. The framework takes care of displaying the Print dialog box and creating a device context for the printer. When the user chooses the Print command from the File menu, the view passes this device context to OnDraw(), which draws the document to the printer.

    click to view at full size.

    Figure 3.8 How OnDraw() is called by the framework

    There are, however, some significant differences between printing and screen display. When you print, you have to divide the document into distinct pages and display them one at a time, rather than display whatever portion is visible in a window. As a corollary, you have to be aware of the size of the paper (whether it's letter size, legal size, or an envelope). You might want to print in different orientations, such as landscape or portrait. The CView class provides a set of print-related functions to enable you to implement the logic for the printing routines.

    Lesson Summary

    The MFC document/view architecture is implemented by the application framework to provide a single, consistent way of coordinating application data and views of that data. A document is an object that acts as a container for the application's data. A view is a window object, usually associated with the client area of an onscreen window, through which the user interacts with the data contained in the document.

    The document/view architecture provides many benefits to the application developer. The document/view architecture simplifies the display of the application data on the screen so that users can interact with the data. Printing and print previewing are also simplified because the same drawing logic is used to render the application's data on the view window, on a print preview window, or on a printer. The document/view architecture provides much of the logic for serialization—the saving of documents to disk and loading them back into memory.

    The framework classes generated by the MFC AppWizard work together to implement the document/view architecture. The application object contains at least one document template object that associates a document class (derived from the MFC class CDocument) with a group of resources, with a frame window class, and with a view class (derived from the CView class).

    Document/view applications can expose a single document interface (SDI) or a multiple document interface (MDI). SDI applications permit only one document, displayed within the application's main frame window, to be open at a time. MDI applications allow multiple documents, displayed in multiple MDI child windows, to be opened in a single instance of an application.

    Drawing on an output device such as a screen or a printer is handled by the Graphical Device Interface (GDI). The GDI presents a standard programming interface that allows you to write device-independent graphical output code. The GDI manages a data structure called a device context, which maintains information about the current drawing attributes of a device. GDI drawing functions render their output to a device context. MFC encapsulates device contexts, and the associated GDI drawing functions, in the CDC class.

    The application's drawing logic is implemented by the view's OnDraw() function. The OnDraw() function is called by the framework, and is passed a pointer to a CDC object that represents the current device context. You add code to the OnDraw() function to display a visual representation of your application data, which is contained within the application's document object. The same drawing code is used to render output to your application's view, to a print preview window, and to the printer.



    Microsoft Press - Desktop Applications with Microsoft Visual C++ 6. 0. MCSD Training Kit
    Desktop Applications with Microsoft Visual C++ 6.0 MCSD Training Kit
    ISBN: 0735607958
    EAN: 2147483647
    Year: 1999
    Pages: 95

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net