Document-View Interaction Functions
You already know that the document object holds the data and that the view object displays the data and allows editing. A Single Document Interface (SDI) application has a document class derived from CDocument, and it has one or more view classes, each ultimately derived from CView. A complex handshaking process takes place among the document, the view, and the rest of the application framework.
To understand this process, you need to know about five important member functions in the document and view classes. Two are nonvirtual base class functions that you call in your derived classes; three are virtual functions that you often override in your derived classes. Let's look at these functions one at a time.
The CView::GetDocument Function
A view object has one and only one associated document object. The GetDocument function allows an application to navigate from a view to its document. Suppose a view object gets a message that the user has entered new data into an edit control. The view must tell the document object to update its internal data accordingly. The GetDocument function provides the document pointer that can be used to access document class member functions or public data members.
Note | The CDocument::GetNextView function navigates from the document to the view, but because a document can have more than one view, you have to call this member function once for each view, inside a loop. You'll seldom call GetNextView because the application framework provides a better method of iterating through a document's views. |
When the MFC Application Wizard generates a derived CView class, it creates two special type-safe versions of the GetDocument function (a debug version and a non-debug version) that return a pointer to an object of your derived document class. The non-debug version (which appears in the view header file) looks like this:
inline CMyDoc* CMyView::GetDocument() const
{ return reinterpret_cast<CMyDoc*>(m_pDocument); }
The debug version (which appears in the view source code file and is compiled when debugging is defined) looks like this:
CMyDoc* CMyView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDoc)));
return (CMyDoc*)m_pDocument;
}
When the compiler sees a call to GetDocument in your view class code, it uses CMyView::GetDocument, which returns CMyDocument *, instead of using CView::GetDocument, which returns CDocument *. Because CMyDocument * is returned, you do not have to cast the returned pointer to your derived document class. Without a helper function like this, the compiler would call the base class's GetDocument function and thus return a pointer to a CDocument object.
Notice that a statement such as the following always calls the base class's GetDocument function—whether or not you have the previous helper function in your program—because the CView::GetDocument function is not a virtual function:
pView->GetDocument(); // pView is declared CView*
The CDocument::UpdateAllViews Function
If the document data changes for any reason, all views must be notified so they can update their representations of that data. If UpdateAllViews is called from a member function of a derived document class, its first parameter, pSender, is NULL. If UpdateAllViews is called from a member function of a derived view class, set the pSender parameter to the current view, like this:
GetDocument()->UpdateAllViews(this);
The non-null parameter prevents the application framework from notifying the current view. The assumption here is that the current view has already updated itself.The function has optional hint parameters that you can use to give view-specific and application-dependent information about which parts of the view to update. This is an advanced use of the function.How exactly is a view notified when UpdateAllViews gets called? Take a look at the next function, OnUpdate.
The CView::OnUpdate Function
This virtual function is called by the application framework in response to your application's call to the CDocument::UpdateAllViews function. You can, of course, call it directly within your derived CView class. Typically, your derived view class's OnUpdate function accesses the document, gets the document's data, and then updates the view's data members or controls to reflect the changes. Alternatively, OnUpdate can invalidate a portion of the view, causing the view's OnDraw function to use document data to draw in the window. The OnUpdate function might look something like this:
void CMyView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CMyDocument* pMyDoc = GetDocument();
CString lastName = pMyDoc->GetLastName();
m_pNameStatic->SetWindowText(lastName); // m_pNameStatic is
// a CMyView data member
}
The hint information is passed through directly from the call to UpdateAllViews. The default OnUpdate implementation invalidates the entire window rectangle. In your overridden version, you can choose to define a smaller invalid rectangle as specified by the hint information.If the CDocument function UpdateAllViews is called with the pSender parameter pointing to a specific view object, OnUpdate is called for all the document's views except the specified view.
The CView::OnInitialUpdate Function
This virtual CView function is called when the application starts, when the user chooses New from the File menu, or when the user chooses Open from the File menu. The CView base class version of OnInitialUpdate does nothing but call OnUpdate. If you override OnInitialUpdate in your derived view class, be sure that the view class calls the base class's OnInitialUpdate function or the derived class's OnUpdate function.You can use your derived class's OnInitialUpdate function to initialize your view object. When the application starts, the application framework calls OnInitialUpdate immediately after OnCreate (if you've mapped OnCreate in your view class). OnCreate is called once, but OnInitialUpdate can be called many times.
The CDocument::OnNewDocument Function
The framework calls this virtual function after a document object is first constructed or when the user chooses New from the File menu in an SDI application. This is a good place to set the initial values of your document's data members. The MFC Application Wizard generates an overridden OnNewDocument function in your derived document class. Be sure to retain the call to the base class function.