Training
Certifications
Books
Special Offers
Community




 
Microsoft® Mastering: MFC Development Using Microsoft Visual C++® 6.0
Author Microsoft Corporation
Pages 624
Disk 1 Companion CD(s)
Level Intermediate
Published 02/23/2000
ISBN 9780735609259
ISBN-10 0-7356-0925-X
Price(USD) $49.99
To see this book's discounted price, select a reseller below.
 

More Information

About the Book
Table of Contents
Sample Chapter
Index
Related Series
Related Books
About the Author

Support: Book & CD

Rate this book
Barnes Noble Amazon Quantum Books

 


Chapter 4: Implementing View Classes



This chapter examines the different types of view classes available in the Microsoft Foundation Class (MFC) Library. The chapter begins with a general discussion of how views fit into the document/view architecture, and continues with sections on some of the views.

The CHTMLView class, which provides Internet browsing functionality, is not covered in this chapter. For information about CHTMLView, see "Implementing HTML Views" on page 469 in Chapter 9, "Building Internet Applications."

Objectives

After completing this chapter, you will be able to:

  • Describe the purpose of documents, views, templates, and frames within the document/view architecture, and explain how they interact.
  • Describe the various types of view classes in MFC.
  • Implement applications that use the following view classes:
    • CView
    • CScrollView
    • CListView
    • CSplitter
    • CTreeView
    • CEditView
    • CRichEditView

  • Create single-document interface (SDI) and multiple-document interface (MDI) applications with multiple views.
  • Use two interrelated views in an application.

Introduction to Views

The view class, CView, physically represents the client area of the application. Logically, CView represents a viewport of the information contained in the document class. It also allows user input through the mouse or keyboard.

MFC supports a wide variety of views. The following illustration shows the hierarchy of MFC view classes.

Figure 4-1.

Figure 4-1.

By deriving your application’s view from one of these classes, the view inherits support for interaction with the application framework. This section provides information on the CView class and how it fits into document/view architecture. It also introduces the relationship between the view and the document.

The CView class simplifies the implementation of printing and print preview for your documents. For more information about implementing printing features, see Chapter 10, "Printing and Print Preview."

The CView Class

The CView class provides the basic functionality for user-defined view classes.

A view is attached to a document and acts as an intermediary between the document and the user. The view renders an image of the document on the screen or printer and interprets user input as operations on the document.

A view is a child of a frame window. More than one view can share a frame window, as in the case of a splitter window. When the user opens a new window or splits an existing one, the framework constructs a new view and attaches it to the document.

Relationship Between a View and a Document

A view can be attached to only one document, but a document can have multiple views attached to it at once, as when the contents of the document are displayed in a splitter window or in multiple child windows in an MDI application.

A view displays a document’s data. The document provides the view with the necessary details about its data. You can have the view access the document’s data members directly, or you can provide member functions in the document class for the view class to call.

Coordinating the Views of a Document

To manage the complex process of creating documents with their associated views and frame windows, the framework uses two document template classes:

  • CSingleDocTemplate
  • You use CSingleDocTemplate with single-document interface (SDI) applications to create and store one document of one type.

  • CMultiDocTemplate
  • You use CMultipleDocTemplate with multiple-document interface (MDI) applications to create and store multiple documents of one type.

When a document’s data changes, the view responsible for the changes typically calls the CDocument::UpdateAllViews function for the document, which notifies all the other views by calling the OnUpdate member function for each view. The default implementation of OnUpdate invalidates the view’s entire client area. You can override this function to invalidate only those parts of the client area that you want to redraw.

Managing Document/View Interaction

To manage the interaction between a document and its view, you must complete the following steps.

  1. Establish communication between the document and view.
  2. Display data in the view.
  3. Update the view when data in the document changes.

Establishing Communication

To establish communication between the current document and a view, create a pointer to the appropriate type of document and call the view’s GetDocument member function, as shown in the following example code:

// Samples\CH04\Mdiapp
// Mdiview.cpp
void CMDIAppView::OnDraw(CDC* pDC)
{
// Get pointer to current document
CMDIAppDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// Use document pointer as required
// to access document data and functions

// ... remainder of drawing code goes here
}

Displaying Data

To display data in a view, override the OnDraw function. The sample code on the following page overrides the OnDraw function. To copy this code for use in your own projects, see "Overriding OnDraw" on the accompanying CD-ROM.

// Overriding the OnDraw function to display data in a view
// Samples\CH04\Mdiapp
// Mdiview.cpp

void CMDIAppView::OnDraw(CDC* pDC)
{
// Get pointer to current document
CMDIAppDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);

// Calculate position to display text
CRect r;
GetClientRect(&r);
int x = r.right / 2, y = r.bottom / 2;

// Set text characteristics
pDC->SetTextColor(pDoc->GetColor());
pDC->SetTextAlign (TA_CENTER | TA_BASELINE);

// Display text to the view
pDC->TextOut (x, y, pDoc->GetPhrase());
}

Updating the View

To update the view(s) when data in the document changes, use either one of these procedures:

  • CWnd::Invalidate (or CDocument::UpdateAllViews)
  • Use in applications that use a single view.

  • CDocument::UpdateAllViews
  • Use in applications that use multiple views.

In applications that use views of different types, calling the UpdateAllViews function may not be the easiest solution for updating data. For information about a method that bypasses the UpdateAllViews function, see "Coordinating Multiple Interrelated Views" on page 183 in this chapter.


TIP:
You can use the pHint and lHint parameters of UpdateAllViews to pass information to the views about the modifications made to the document. You can encode information by using lHint, and you can define a CObject-derived class to store information about the modifications and pass an object of that class by using pHint. Override the CView::OnUpdate member function in your CView-derived class to optimize the updating of the view’s display, based on the information passed.

For more information about the UpdateAllViews function, search for "UpdateAllViews" in MSDN Library Visual Studio 6.0.


The following sample code shows how an MDI application uses the UpdateAllViews function to ensure that all views associated with the current document are correctly repainted when the user changes the color of the text displayed in the view. To copy this code for use in your own projects, see "Updating the Views in an MDI Application" on the accompanying CD-ROM.

// Repainting all views of a document when the user changes the text 
// color in one of the views
// Samples\CH04\Mdiapp
// Mdiview.cpp

void CMDIAppView::OnColors(UINT nID)
{
CMDIAppDoc* pDoc = GetDocument();
pDoc->SetColor(IDtoColorRef(nID));

// If this were an SDI app then you could call
// Invalidate();
// Since it's an MDI app, you have to call
pDoc->UpdateAllViews(NULL);
}
For more information about functions used to update views, search for "Updating Views" in MSDN Library Visual Studio 6.0.

Adding Multiple Views

It is possible to support more than one view of a single document. To help you implement multiple views, a document object keeps a list of its views, provides member functions for adding and removing views, and supplies the UpdateAllViews member function, which sends a message to the views when the user changes the data in a document.

This section explains how to create multiple views of the same document for SDI and MDI applications. In the sample applications for this section, multiple views share a single frame window. The views are constructed from different classes, each view providing a different way to display the same document. For example, one view might show the text in a document in a normal mode, while the other view shows the text in italic.

Adding Multiple Views to an SDI Application

In an SDI application, you can have multiple views of the same document. The views are constructed from different classes, each view providing a different way to display the same document. Several steps are required to add a second view to an SDI application.

To create an SDI application with two views of the same document

  1. Build an SDI application the way you normally would. For an application with more than one view class, like the one discussed in these steps, place the command handlers in the CMainFrame class. Placing the command handlers in CMainFrame ensures that they will be available regardless of which view is active. If you place the command handlers in the view class, the handlers will not be available unless that view object is active.

  2. TIP:
    In an application with only one view class, place command handlers in the view class. In an application with more than one view class, place command handlers in the CMainFrame (SDI) or CChildFrame (MDI) class. The functions CFrameWnd::GetActiveView and CFrameWnd::GetActiveDocument facilitate accessing the view of the document from your main frame or child frame.

  3. Add a new view class derived from CView.
  4. Add debug and nondebug versions of the GetDocument function.
  5. Use the GetDocument functions from your existing view class as a model.

  6. Add a public constructor.
  7. ClassWizard provides the new view class with a protected constructor. Make sure the constructor differs from the existing constructor in a way other than scope.

  8. Make the destructor provided by Class Wizard public.
  9. The protected destructor is not necessary, and the new constructor you have added is already public.

  10. Include the document class header file in the source file of the new view class.
  11. Add a handler for the OnDraw event of the new view class.
  12. Include the header file of the new view class in Mainfrm.cpp.
  13. Add two protected variables in the CMainFrame class.
  14. These variables will be pointers to the two view objects your application uses. Initialize these pointers to NULL (0) in the constructor of CMainFrame, as shown in the following example code:

    class CMainFrame : public CFrameWnd
    {
    ...
    protected:
    CItalicsView * m_pItalicsView;
    CDefaultView * m_pDefaultView;
    ...
    }
    CMainFrame::CMainFrame()
    {
    // To give this SDI app 2 views, the main frame stores
    // pointers to them both.
    m_pItalicsView = 0;
    m_pDefaultView = 0;
    }

  15. Add two menu selections to permit the application to switch between the two views.
  16. The View menu is a good place to insert the menu selections, but you can choose any of the drop-down menus.

  17. Add command handlers to CMainFrame for the two new menu items.
  18. The following sample code shows how to add the command handler to switch to the new view. To copy this code for use in your own projects, see "Command Handler to Switch to New View" on the accompanying CD-ROM.

    // To switch to the new view and hide the default view
    // Samples\CH04\SDI2VIEWS
    void CMainFrame::OnViewItalics()
    {
    CDocument* pDoc = GetActiveDocument();

    // Only need to do this one time.
    if (0 == m_pItalicsView)
    {
    m_pDefaultView = (CDefaultView *)GetActiveView();
    // This object is destroyed in main frame's d'tor.
    m_pItalicsView = new CItalicsView(NULL);

    m_pItalicsView->Create(NULL, NULL, AFX_WS_DEFAULT_VIEW,
    rectDefault, this, AFX_IDW_PANE_FIRST + 1);
    }

    pDoc->AddView(m_pItalicsView);

    // Set the child i.d. of the italics view to AFX_IDW_PANE_FIRST,
    // so that CFrameWnd::RecalcLayout will allocate to this
    // "first pane" that portion of the frame window's client area
    // not allocated to control bars. Set the child i.d. of the
    // default view to AFX_IDW_PANE_FIRST + 1
    m_pItalicsView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
    m_pDefaultView->SetDlgCtrlID(AFX_IDW_PANE_FIRST+1);

    // Show the italics view and hide the default view.
    m_pItalicsView->ShowWindow(SW_SHOW);
    m_pDefaultView->ShowWindow(SW_HIDE);

    SetActiveView(m_pItalicsView);

    // See comment in OnViewDefault.
    pDoc->RemoveView(m_pDefaultView);
    RecalcLayout();
    }

    The following sample code shows how to add the command handler that restores the default view. To copy this code for use in your own projects, see "Command Handler to Restore Default View" on the accompanying CD-ROM.

    // To switch to the default view and hide the second view (the italics
    // view)
    // Samples\CH04\SDI2VIEWS
    void CMainFrame::OnViewDefault()
    {
    CDocument* pDoc = GetActiveDocument();

    // The UI handler will prevent this function executing before
    // OnViewItalics, but just in case...
    ASSERT (m_pItalicsView != 0);
    ASSERT (m_pDefaultView != 0);

    pDoc->AddView(m_pDefaultView);

    m_pDefaultView->ShowWindow(SW_SHOW);
    m_pItalicsView->ShowWindow(SW_HIDE);

    m_pDefaultView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
    m_pItalicsView->SetDlgCtrlID(AFX_IDW_PANE_FIRST + 1);

    SetActiveView(m_pDefaultView);
    pDoc->RemoveView(m_pItalicsView);
    RecalcLayout();
    }

    You can choose to leave the inactive view in the application, or you can remove the inactive view from your application. The previous sample code uses CDocument::RemoveView to remove the inactive view. Removing it means that when the document object is changed and CDocument::UpdateAllViews is called, the inactive view object’s OnDraw function will not be called.

    Removing the inactive view is not required, but it makes the application more efficient. If the inactive view is not removed from the document object’s list of attached views, nothing detrimental will happen when the inactive view’s OnDraw function executes. In an application with only two views, each with simple OnDraw functions, you will not be able to tell much difference.

  19. Enable and disable the two menu items, as shown in the following example code:
  20. void CMainFrame::OnUpdateViewDefault(CCmdUI* pCmdUI) 
    {
    // Only enable the default view menu if the current view
    // is the italics view. The isKindOf function checks if the
    // active view is derived from CItalicsView
    RUNTIME_CLASS macro
    pCmdUI->Enable(
    GetActiveView()->IsKindOf(RUNTIME_CLASS(CItalicsView)));
    }

    void CMainFrame::OnUpdateViewItalics(CCmdUI* pCmdUI)
    {
    // Only enable the italics view menu if the current view
    // is the default view.
    pCmdUI->Enable(
    GetActiveView()->IsKindOf(RUNTIME_CLASS(CDefaultView)));
    }

The code samples discussed in this topic appear in the sample application SDI2VIEWS, which is located in the folder <install folder>\Samples\Ch04.


Next


Visit Microsoft Press for more information on
Microsoft® Mastering: MFC Development Using Microsoft Visual C++® 6.0


Top of Page


Last Updated: Friday, July 6, 2001