Bob is a systems engineer and MFC/ C++ instructor for STEP Technology, in Portland, Oregon.
Many applications require, or would benefit from, multiple types of views of the application data. Coincidentally, one strength of the Microsoft Foundation Classes (MFC) is its support of the document/view architecture. In this article, I'll examine how MFC supports the multiple-view facility, presenting code for implementing three types of views in an application. I'll also address the topic of customizing the titles that appear in MDI (Multiple Document Interface) frame windows, one of the first obstacles you'll encounter when building multiple-view applications.
The document template is the unifying construct for the MFC multiple-view architecture--specifically, the class CMultiDocTemplate represents the blueprint used to create a new frame-view-document-menu-icon combination called an "MDI Child."
When a user running a Windows program invokes File/New or File/ Open, a new window pops up on the screen. In an MDI MFC application, this new window is a "child frame." Inside the frame is a view. Associated with the view is a document, which manages the data being presented in the view. Additionally, the main menu may change to a menu specifically associated with the active view. When the frame is minimized, the associated icon is used for displaying the minimized window. These associations (the MFC "plumbing") and the dynamic creation of the frame and view objects are handled through the document template. The CMultiDocTemplate::CreateNewFrame function is the high-level call you use from your application. The document template keeps a list of all documents created according to its blueprint. Each document in turn keeps a list of its views. Each view, by virtue of its participation in the Windows system hierarchy of parent and child windows, can find its way back to its encompassing frame. Up at the top, the application object keeps a list of document templates and a pointer to its main frame window.
When a user selects Window/New from the menu, a new MDI Child also pops up, but this time, it's an additional view associated with an existing document. Which document? The active document. What's an active document? The document associated with the active view. What's an active view? The view inside of the active frame, with the highlighted title bar. Again, CMultiDocTemplate::CreateNewFrame is the function to call. This time, however, its first parameter, a document pointer, should point to the document associated with the active view. Then you'll get another view on the same document.
To get a different type of view (graphical view, data-entry-form view, text-editor view, data-cell view, or the like) of the same data or document, just use a unique document template. How? Since the CreateNewFrame function is a member function of the CMultiDocTemplate class, you call it through a template pointer. When created, the template object stores the information necessary to create a specific type of MDI child frame and a specific type of view (that is, a C++ class) associated with a specific type of document. When creating a new-document template instance, you pass the necessary information about these classes to the CMultiDocTemplate constructor, along with a resource ID that identifies a menu, an icon, and a string resource. The string resource, in turn, is a string composed of seven substrings, delimited by \n, which supply additional information for the framework.
The accompanying listings present the source code for the C++ classes in a sample application called "Seminar." As Figure 1 illustrates, Seminar is a program that displays a view similar to a seating chart for a classroom of ten students. One auxiliary view displays a data-entry form that contains information about a single student. Another auxiliary view provides a simple text editor for keeping notes on that student.
Seminar is a typical Visual-C++ MFC application initially generated with App-Wizard. AppWizard generates other large portions of the code. In the listings, comments starting with //*** identify code that the human programmer would write. Table 1(a) lists the C++ classes generated by AppWizard, while Table 1(b) lists the classes generated by ClassWizard or coded by hand. The complete Seminar sources (available electronically; see "Availability," page 3) include additional files, such as resources. For this program, I have used the default resources created by App-Wizard, changing only the menus and string-table entries for the new templates.
While Seminar's source code demonstrates a number of techniques for communicating between document and views, my discussion here focuses only on those programming techniques that directly apply to adding an auxiliary MDI Child to an application.
To start with, you need a new CView-derived class. In Seminar, there are two auxiliary-view classes, CStudentView and CNotesView. CStudentView is derived from CFormView using the AppStudio and ClassWizard tools. The results are studview.h and studview.cpp (see Listings Eleven and Twelve, pages 37 and 38, respectively). For CNotesView, derive the class from CEditView by generating a CView-derived class with ClassWizard and changing the base class from CView to CEditView. Add a GetDocument override to return a pointer to the document cast to a CSeminarDoc pointer. Add code to support the transfer of data between document and view and for updating the view; see Listings Thirteen and Fourteen (pages 38 and 39, respectively).
To create a new document template, you need a frame class, document class, view class, and resources. You can use the standard CMDIChildWnd class for the frame, CSeminarDoc for the document, and the new view classes described in Step 1. As for the resources, you need a menu, icon, and string resource, each identified by the same resource ID. These can be created using AppStudio by cutting and pasting the corresponding resources generated by AppWizard. For example, use copy and paste to duplicate the menu resource identified as IDR_CLASSTYPE, and rename the ID to IDR_STUDENTTYPE. Do the same for the IDR_CLASSTYPE icon, and the IDR_CLASSTYPE string resource. In the string resource, remove the substring between the second and third \n delimiters; see Example 1. This will prevent the framework from treating this template as the source of a possible primary view. Otherwise, for File/New or File/Open, the user will be presented with a dialog listing the possible primary views. This third substring in the document template string is the text that will be displayed to the user to identify this MDI Child.
You now have all the pieces for a document template. Since you'll want access to a particular template while the application is running, keep a data member to hold the document-template pointer when you've created it. The application class is an appropriate place for this data member (see Listings One and Two). Create the document template in the InitInstance function and provide a public-access function to retrieve the pointer from another class; see Example 2.
Template instances that are added to the application's template list with a call to AddDocTemplate are deleted in the application's destructor, so an explicit call to delete m_student_view_template should not be added to the ExitInstance function. If you created a template object and did not call AddDocTemplate, then you should delete the template object in ExitInstance.
In Seminar, CRoomView is derived from the FormViewclass and functions as the primary view. To make this work, just find the creation of the document template that AppWizard put into the InitInstance function and change CSeminarView to CRoomView.
Now go to the document class, where you add a function to create the auxiliary view (see Listings Five and Six). In this example, you create the CSeminarDoc::ViewStudent function. The idea is to retrieve the appropriate template pointer and then call the necessary functions in the template class. Since the application object is globally accessible through the global C function ::AfxGetApp, you can retrieve the document template for the student view. Use that template pointer to call CreateNewFrame(this, NULL). The first parameter is a pointer to a document. Since the ViewStudent function is in the document class, you use the this pointer. If not NULL, the second parameter is a pointer to an existing frame on which the new frame is based. This is used by the MFC framework in implementing the Window/New command. That parameter doesn't matter here, so just use NULL. The other required mumbo jumbo is to invoke InitialUpdateFrame through the template object, passing the new frame and the document as parameters: doc_template->InitialUpdateFrame( m_student_frame, this );.
To support the user interface, you need something that calls ViewStudent. Typically, this would be in a handler for a user event, like a menu-item selection in the View menu, or a mouse click on an item about which more detail is desired. In the case of the Seminar application, ViewStudent is invoked automatically whenever a new CRoomView is created. It does this by overriding CRoomView::OnInitialUpdate. However, if the user had closed an auxiliary view (or minimized it) it will reappear when the user clicks a student button in the room view. These details are repeated for CNotesView to provide the Seminar application with two auxiliary views.
In addition to the previously described incantations for creating a new MDI Child, there are a few other practical details to consider. First, in the case of auxiliary views, some user action represents a request to bring up that view. In the Seminar example, the user clicks on a student button in the room view. The auxiliary views are created, restored, or brought to the top, as appropriate. The Seminar code handles these situations in a single function for each view. The functions CSeminarDoc::ViewStudent and CSeminarDoc::ViewNotes demonstrate this. A data member in the document stores the pointer to the MDI Child frame. Zero implies that the frame does not exist and needs to be created. Nonzero implies the frame already exists; however, it may be minimized. A call to IsIconic() checks this. If it is minimized, then a call to ShowWindow( SW_RESTORE ) will bring the window back up and activate it. If the frame is not minimized, it may be "behind" other windows. In this case, a call to MDIActivate() will bring the window to the front and activate it. If you want to bring the window to the front without activating it, use the SetWindowPos function (see Example 3).
Now you have your bases covered. Users get what they probably expect, and you have a single function to call that can be invoked from handlers for various user events. Often, you will want to supply the user with more than one way to bring up auxiliary views, such as mouse clicks, mouse double clicks, or menu-item selections. You may want to add an item to the View menu to let the user control the appearance and disappearance of an auxiliary view.
A typical document template uses the standard CMDIChildWnd class as the type of frame. The CMDIChildWnd class supports automatic titling for the frames. You may have noticed titles such as "Class1.sem:1", "Class1.sem:2" in the title bars for MDI Children. To customize titling of your child frames, override the OnUpdateFrameTitle function, derive your own class from CMDIChildWnd, and supply the OnUpdateFrameTitle override. Now use your own frame class in place of CMDIChildWnd in the constructor of the appropriate document template. The Seminar application uses the class CNotesFrame to display the student name as the frame title. In the CSeminarApp::InitInstance function, CNotesFrame is used as the frame-class parameter when constructing the document template; see Example 4.
Figure 1 The Seminar application depicts three views of a single document. The primary view is similar to a seating chart, the first auxiliary view shows information on a selected student, and the second auxiliary view is a free-form notepad for additional comments about the same student.
Table 1: (a) C++ classes generated by AppWizard; (b) classes either generated by ClassWizard or coded by hand.
Example 1: (a) Removing the substring between the second and third \n delimiters; (b) the result.
Example 2: Creating the document template in the InitInstance function and providing a public-access function to retrieve the pointer from another class.
Example 3: Using the SetWindowPos function.
Example 4: CNotesFrame is used as the frame-class parameter when constructing the document template.
Copyright © 1995, Dr. Dobb's Journal(a)
SEMINAR.H (listing 1) The application-framework class.
SEMINAR.CPP (listing 2)
MAINFRM.H (listing 3) The main MDI frame window with menu.
MAINFRM.CPP (listing 4)
SEMDOC.H (listing 5) The Document class.
SEMDOC.CPP (listing 6)
ROOMVIEW.H (listing 7) The primary View class.
ROOMVIEW.CPP (listing 8)
(b)
STUDENT.H (listing 9) The simple CStudent data object.
STUDENT.CPP (listing 10)
STUDVIEW.H (listing 11) The first aux View class (form view).
STUDVIEW.CPP (listing 12)
NOTEVIEW.H (listing 13) The second aux View class (notes view).
NOTEVIEW.CPP (listing 14)
NOTESFRM.H (listing 15) Customized Frame class (notes view).
NOTESFRM.CPP (listing 16)
(a) \nClass\nCLASS Document\nCLASS Files(*.sem)\n.sem\nClassFileType
\nCLASSFile Type
(b) \nClass\n\nCLASS Files(*.sem)\n.sem\nClassFileType\nCLASS File Typeclass CSeminarApp : public CWinApp
{
...
protected:
CMultiDocTemplate *m_student_view_template;
public:
CMultiDocTemplate *GetTemplateForStudentView()
{ return m_student_view_template; }
};
BOOL CSeminarApp::InitInstance()
{
...
m_student_view_template = new CMultiDocTemplate(IDR_STUDENTTYPE,
RUNTIME_CLASS(CSeminarDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CStudentView));
AddDocTemplate( m_student_view_template );
...
} SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
m_notes_template = new CMultiDocTemplate(IDR_NOTESTYPE,
RUNTIME_CLASS(CSeminarDoc),
RUNTIME_CLASS(CNotesFrame),
RUNTIME_CLASS(CNotesView));Listing One
//////////////////////////////////////////////////////////////////////
// seminar.h : main header file for the Seminar application
// and interface for the CSeminarApp class
#ifndef __AFXWIN_H__
#error include 'stdafx.h' before including this file for PCH
#endif
#include "resource.h" // main symbols
class CSeminarApp : public CWinApp
{
public:
CSeminarApp();
// Attributes
protected:
//*** Document templates for the auxiliary views
CMultiDocTemplate *m_student_view_template;
CMultiDocTemplate *m_notes_template;
public:
//*** Access functions for the auxiliary document templates.
CMultiDocTemplate *GetTemplateForStudentView();
CMultiDocTemplate *GetTemplateForNotesView();
// Overrides
virtual BOOL InitInstance();
// Implementation
//{{AFX_MSG(CSeminarApp)
afx_msg void OnAppAbout();
// NOTE - the ClassWizard will add and remove functions here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//*** Inline implementations for access functions.
inline CMultiDocTemplate *CSeminarApp::GetTemplateForStudentView()
{ return m_student_view_template; }
inline CMultiDocTemplate *CSeminarApp::GetTemplateForNotesView()
{ return m_notes_template; }
Listing Two
//////////////////////////////////////////////////////////////////////
// seminar.cpp : implementation of the CSeminarApp class and of the
// CAboutDlg class.
#include "stdafx.h"
#include "seminar.h"
#include "mainfrm.h"
#include "semdoc.h"
#include "roomview.h"
#include "studview.h"
#include "notesfrm.h"
#include "noteview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
BEGIN_MESSAGE_MAP(CSeminarApp, CWinApp)
//{{AFX_MSG_MAP(CSeminarApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
// NOTE - ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CSeminarApp construction
CSeminarApp::CSeminarApp()
{
}
//////////////////////////////////////////////////////////////////////
// The one and only CSeminarApp object
CSeminarApp NEAR theApp;
//////////////////////////////////////////////////////////////////////
// CSeminarApp initialization
BOOL CSeminarApp::InitInstance()
{
// Standard initialization
SetDialogBkColor(); // set dialog background color to gray
LoadStdProfileSettings(); // Load standard INI file options
// Register the application's document templates. Document
// templates serve as the connection between documents,
// frame windows and views.
//*** Modify creation of primary document template to use
//*** the CRoomView class (as a primary form view).
AddDocTemplate(new CMultiDocTemplate(IDR_CLASSTYPE,
RUNTIME_CLASS(CSeminarDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CRoomView)));
//*** Create document templates for auxiliary views
m_student_view_template = new CMultiDocTemplate(IDR_STUDENTTYPE,
RUNTIME_CLASS(CSeminarDoc),
RUNTIME_CLASS(CMDIChildWnd),
RUNTIME_CLASS(CStudentView));
AddDocTemplate( m_student_view_template );
m_notes_template = new CMultiDocTemplate(IDR_NOTESTYPE,
RUNTIME_CLASS(CSeminarDoc),
RUNTIME_CLASS(CNotesFrame),
RUNTIME_CLASS(CNotesView));
AddDocTemplate( m_notes_template );
// create main MDI Frame window
CMainFrame* pMainFrame = new CMainFrame;
if (!pMainFrame->LoadFrame(IDR_MAINFRAME))
return FALSE;
pMainFrame->ShowWindow(m_nCmdShow);
pMainFrame->UpdateWindow();
m_pMainWnd = pMainFrame;
// enable file manager drag/drop and DDE Execute open
m_pMainWnd->DragAcceptFiles();
EnableShellOpen();
RegisterShellFileTypes();
// simple command line parsing
if (m_lpCmdLine[0] == '\0')
{
// create a new (empty) document
OnFileNew();
}
else if ((m_lpCmdLine[0] == '-' || m_lpCmdLine[0] == '/') &&
(m_lpCmdLine[1] == 'e' || m_lpCmdLine[1] == 'E'))
{
// program launched embedded - wait for DDE or OLE open
}
else
{
// open an existing document
OpenDocumentFile(m_lpCmdLine);
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// Implementation
protected:
virtual void DoDataExchange(CDataExchange* pDX);
//{{AFX_MSG(CAboutDlg)
// No message handlers
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// App command to run the dialog
void CSeminarApp::OnAppAbout()
{
CAboutDlg aboutDlg;
aboutDlg.DoModal();
}
Listing Three
//////////////////////////////////////////////////////////////////////
// mainfrm.h : interface for the CMainFrame class
class CMainFrame : public CMDIFrameWnd
{
DECLARE_DYNAMIC(CMainFrame)
public:
CMainFrame();
// Attributes
public:
// Operations
public:
// Implementation
public:
virtual ~CMainFrame();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
// Generated message map functions
protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Listing Four
//////////////////////////////////////////////////////////////////////
// mainfrm.cpp : implementation of the CMainFrame class
#include "stdafx.h"
#include "seminar.h"
#include "mainfrm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
//*** Constants for saving/restoring window size in .ini file
static LPCSTR frame_size = "Frame Size";
static LPCSTR top = "Top";
static LPCSTR left = "Left";
static LPCSTR bottom = "Bottom";
static LPCSTR right = "Right";
#define FRAME_LEFT 0
#define FRAME_TOP 0
#define FRAME_RIGHT 625
#define FRAME_BOTTOM 375
//////////////////////////////////////////////////////////////////////
// CMainFrame
IMPLEMENT_DYNAMIC(CMainFrame, CMDIFrameWnd)
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CMainFrame construction/destruction
CMainFrame::CMainFrame()
{
}
CMainFrame::~CMainFrame()
{
}
//////////////////////////////////////////////////////////////////////
// CMainFrame diagnostics
#ifdef _DEBUG
void CMainFrame::AssertValid() const
{
CMDIFrameWnd::AssertValid();
}
void CMainFrame::Dump(CDumpContext& dc) const
{
CMDIFrameWnd::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CMainFrame message handlers
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
//*** Retrieve size and position of main window from .ini file
CRect r;
GetWindowRect( r );
CWinApp *app = ::AfxGetApp();
if ( app != 0 )
{
r.left = app->GetProfileInt( frame_size, left, FRAME_LEFT );
r.top = app->GetProfileInt( frame_size, top, FRAME_TOP );
r.right = app->GetProfileInt( frame_size, right, FRAME_RIGHT );
r.bottom = app->GetProfileInt( frame_size, bottom,
FRAME_BOTTOM );
MoveWindow( r );
}
return 0;
}
void CMainFrame::OnDestroy()
{
CMDIFrameWnd::OnDestroy();
//*** Save size and position of main frame window in .ini file
CRect r;
GetWindowRect( r );
CWinApp *app = ::AfxGetApp();
if ( app != 0 )
{
app->WriteProfileInt( frame_size, left, r.left );
app->WriteProfileInt( frame_size, top, r.top );
app->WriteProfileInt( frame_size, right, r.right );
app->WriteProfileInt( frame_size, bottom, r.bottom );
}
}
Listing Five
//////////////////////////////////////////////////////////////////////
// semdoc.h : interface for the CSeminarDoc class
//*** constants used by document and its associated views
#define MAX_STUDENTS 10
#define ROOM_X 5
#define ROOM_Y 5
#define ROOM_WIDTH 505
#define ROOM_HEIGHT 155
#define STUDENT_X (ROOM_X)
#define STUDENT_Y (ROOM_Y+ROOM_HEIGHT+5)
#define STUDENT_WIDTH 300
#define STUDENT_HEIGHT 160
#define NOTES_X (STUDENT_X+STUDENT_WIDTH+5)
#define NOTES_Y (STUDENT_Y)
#define NOTES_WIDTH 300
#define NOTES_HEIGHT 160
enum Action { ACTION_ACTIVATE = 1, ACTION_CLEAR, ACTION_CHANGENAME };
//*** forward references
class CStudent;
class CNotesFrame;
// class declaration
class CSeminarDoc : public CDocument
{
protected: // create from serialization only
CSeminarDoc();
DECLARE_DYNCREATE(CSeminarDoc)
// Attributes
protected:
//*** data members for keeping track of open views.
CMDIChildWnd *m_student_frame;
CNotesFrame *m_notes_frame;
CMDIChildWnd *m_room_frame;
//*** data member for holding pointers to student objects
CObArray m_students;
// Operations
public:
//*** services provided by the document class
void ViewStudent( int nIndex, BOOL bActivate );
void ViewNotes( int nIndex, BOOL bActivate );
CMultiDocTemplate *GetTemplateForStudentView();
CMultiDocTemplate *GetTemplateForNotesView();
void StudentViewClosed();
void NotesViewClosed();
void SetRoomFrame( CMDIChildWnd *frame );
void CloseStudentView();
void CloseNotesView();
void RetrieveDataFromViews();
CStudent *GetStudent( int nIndex );
// Implementation
public:
virtual ~CSeminarDoc();
virtual void Serialize(CArchive& ar); // override for document i/o
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
virtual BOOL OnNewDocument();
// Generated message map functions
protected:
//{{AFX_MSG(CSeminarDoc)
// NOTE - the ClassWizard will add and remove functions here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//*** Inline implementations for access functions.
inline void CSeminarDoc::SetRoomFrame( CMDIChildWnd *frame )
{ m_room_frame = frame; }
inline CStudent *CSeminarDoc::GetStudent( int nIndex )
{ return (CStudent *)m_students.GetAt( nIndex ); }
Listing Six
//////////////////////////////////////////////////////////////////////
// semdoc.cpp : implementation of the CSeminarDoc class
#include "stdafx.h"
#include "seminar.h"
#include "student.h"
#include "semdoc.h"
#include "studview.h"
#include "notesfrm.h"
#include "noteview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CSeminarDoc, CDocument)
BEGIN_MESSAGE_MAP(CSeminarDoc, CDocument)
//{{AFX_MSG_MAP(CSeminarDoc)
// NOTE - ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CSeminarDoc construction/destruction
CSeminarDoc::CSeminarDoc()
{
//*** Initialize data members.
m_student_frame = 0;
m_notes_frame = 0;
m_room_frame = 0;
//** Create collection of 'blank' student objects.
for ( int i = 0; i < MAX_STUDENTS; i++ )
{
m_students.Add( new CStudent() );
}
}
CSeminarDoc::~CSeminarDoc()
{
//*** Destroy collection of student objects.
CStudent *student;
for ( int i = 0; i < MAX_STUDENTS; i++ )
{
student = (CStudent *)m_students.GetAt( i );
if ( student != 0 )
{
delete student;
}
}
m_students.RemoveAll();
}
BOOL CSeminarDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CSeminarDoc serialization
void CSeminarDoc::Serialize(CArchive& ar)
{
//*** If storing, retrieve data for currently selected student
if ( ar.IsStoring )
{
RetrieveDataFromViews();
}
//*** Serialize the collection of students
m_students.Serialize( ar );
}
//////////////////////////////////////////////////////////////////////
// CSeminarDoc diagnostics
#ifdef _DEBUG
void CSeminarDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CSeminarDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
//*** Provide access to document template pointer stored in
//*** application class.
CMultiDocTemplate *CSeminarDoc::GetTemplateForStudentView()
{
CSeminarApp *app = (CSeminarApp *)::AfxGetApp();
ASSERT( app != 0 );
return app->GetTemplateForStudentView();
}
//*** Provide access to document template pointer stored in
//*** applicatino class.
CMultiDocTemplate *CSeminarDoc::GetTemplateForNotesView()
{
CSeminarApp *app = (CSeminarApp *)::AfxGetApp();
ASSERT( app != 0 );
return app->GetTemplateForNotesView();
}
//*** Bring up the student view, creating it if necessary
void CSeminarDoc::ViewStudent( int nIndex, BOOL bActivate )
{
if ( m_student_frame != 0 )
{
//*** If the frame already exists, then check to see if the
//*** frame window is minimized. If so, restoring it will
//*** open it back up and activate it.
if ( m_student_frame->IsIconic() )
{
m_student_frame->ShowWindow( SW_RESTORE );
}
else if ( bActivate )
{
//*** If the frame already exists, but is not miminimized,
//*** then just call MDIActivate(), which will bring it
//*** front and activate it.
m_student_frame->MDIActivate();
}
else
{
//*** Bring frame to the front, but don't activate it.
m_student_frame->SetWindowPos( &CWnd::wndTop, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
}
}
else
{
//*** If the frame has not yet been created, create it here by
//*** using the appropriate document template pointer.
CMultiDocTemplate *doc_template = GetTemplateForStudentView();
if ( doc_template != 0 )
{
m_student_frame =
(CMDIChildWnd *)doc_template->CreateNewFrame(this, NULL);
if( m_student_frame != 0 )
{
if ( m_room_frame != 0 )
{
//*** Initialize size and position of the frame.
CRect roomRect;
m_room_frame->GetWindowRect( roomRect );
m_student_frame->SetWindowPos( 0, STUDENT_X,
STUDENT_Y, STUDENT_WIDTH, STUDENT_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE );
}
m_student_frame->ShowWindow( SW_SHOW );
m_student_frame->UpdateWindow();
doc_template->InitialUpdateFrame(m_student_frame, this );
}
}
}
if ( m_student_frame != 0 )
{
//*** Initialize view with appropriate student data.
CStudentView *view =
(CStudentView *)m_student_frame->GetActiveView();
if(view != 0)
{
view->SetStudent( (CStudent *)m_students.GetAt( nIndex ) );
}
}
}
//*** Bring up the notes view, creating it if necessary.
//*** This code is similar to the preceding ViewStudent function.
//*** and the comments in ViewStudent apply as appropriate here.
void CSeminarDoc::ViewNotes( int nIndex, BOOL bActivate )
{
if ( m_notes_frame != 0 )
{
if ( m_notes_frame->IsIconic() )
{
m_notes_frame->ShowWindow( SW_RESTORE );
}
else if ( bActivate )
{
m_notes_frame->MDIActivate();
}
else
{
m_notes_frame->SetWindowPos( &CWnd::wndTop, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE );
}
}
else
{
CMultiDocTemplate *doc_template = GetTemplateForNotesView();
if ( doc_template != 0 )
{
m_notes_frame =
(CNotesFrame *)doc_template->CreateNewFrame(this, NULL);
if(m_notes_frame != 0)
{
m_notes_frame->SetWindowPos( 0, NOTES_X, NOTES_Y,
NOTES_WIDTH, NOTES_HEIGHT,
SWP_NOZORDER | SWP_NOACTIVATE );
doc_template->InitialUpdateFrame(m_notes_frame, this);
}
}
}
if ( m_notes_frame != 0 )
{
CNotesView *view =
(CNotesView *)m_notes_frame->GetActiveView();
if(view != 0)
{
view->SetStudent( (CStudent *)m_students.GetAt( nIndex ) );
}
m_notes_frame->OnUpdateFrameTitle( FALSE );
}
}
//*** Remember that the student view is gone, so that the ViewStudent
//*** function will know whether it needs to create it.
void CSeminarDoc::StudentViewClosed()
{
m_student_frame = 0;
}
//*** Remember that the notes view is gone, so that the ViewNotes
//*** function will know whether it needs to create it.
void CSeminarDoc::NotesViewClosed()
{
m_notes_frame = 0;
}
//*** Force closing and destruction of the student view and frame
void CSeminarDoc::CloseStudentView()
{
if ( m_student_frame != 0 )
{
m_student_frame->PostMessage( WM_CLOSE );
}
}
//*** Force closing and destruction of the notes view and frame
void CSeminarDoc::CloseNotesView()
{
if ( m_notes_frame != 0 )
{
m_notes_frame->PostMessage( WM_CLOSE );
}
}
//*** Transfer data from the views to the document
void CSeminarDoc::RetrieveDataFromViews()
{
CStudentView *student_view;
CNotesView *notes_view;
if ( m_student_frame != 0 )
{
student_view = (CStudentView *)m_student_frame->GetActiveView();
if ( student_view != 0 )
{
student_view->UpdateDocument();
}
}
if ( m_notes_frame != 0 )
{
notes_view = (CNotesView *)m_notes_frame->GetActiveView();
if ( notes_view != 0 )
{
notes_view->UpdateDocument();
}
}
}
Listing Seven
//////////////////////////////////////////////////////////////////////
// roomview.h : interface for the CRoomView class
#ifndef __AFXEXT_H__
#include <afxext.h>
#endif
//*** forward references
class CSeminarDoc;
// class declaration
class CRoomView : public CFormView
{
DECLARE_DYNCREATE(CRoomView)
protected:
CRoomView(); // protected constructor used by dynamic creation
// Form Data
public:
//{{AFX_DATA(CRoomView)
enum { IDD = IDD_CLASSROOM };
// NOTE: the ClassWizard will add data members here
//}}AFX_DATA
// Attributes
public:
CSeminarDoc* GetDocument();
protected:
//*** Data members for keeping track of active student.
int m_button_id[MAX_STUDENTS];
int m_active_index;
// Operations
public:
//*** Make the given student the active student, updating
//*** other views.
void ActivateStudent( int nIndex );
// Implementation
protected:
virtual ~CRoomView();
virtual void DoDataExchange(CDataExchange* pDX);
//*** Provide one-time initialization for the view.
virtual void OnInitialUpdate();
//*** Override to update view with changes in data
virtual void OnUpdate(CView* pSender, LPARAM lHint,
CObject* pHint);
// Generated message map functions
//{{AFX_MSG(CRoomView)
afx_msg void OnClickedButton1();
afx_msg void OnClickedButton2();
afx_msg void OnClickedButton3();
afx_msg void OnClickedButton4();
afx_msg void OnClickedButton5();
afx_msg void OnClickedButton6();
afx_msg void OnClickedButton7();
afx_msg void OnClickedButton8();
afx_msg void OnClickedButton9();
afx_msg void OnClickedButton10();
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//*** Inline implementations for access functions.
inline CSeminarDoc* CRoomView::GetDocument()
{ return (CSeminarDoc*) m_pDocument; }
Listing Eight
//////////////////////////////////////////////////////////////////////
// roomview.cpp : implementation of the CRoomView class
#include "stdafx.h"
#include "seminar.h"
#include "student.h"
#include "semdoc.h"
#include "roomview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CRoomView, CFormView)
CRoomView::CRoomView()
: CFormView(CRoomView::IDD)
{
//{{AFX_DATA_INIT(CRoomView)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_button_id[0] = IDC_BUTTON1;
m_button_id[1] = IDC_BUTTON2;
m_button_id[2] = IDC_BUTTON3;
m_button_id[3] = IDC_BUTTON4;
m_button_id[4] = IDC_BUTTON5;
m_button_id[5] = IDC_BUTTON6;
m_button_id[6] = IDC_BUTTON7;
m_button_id[7] = IDC_BUTTON8;
m_button_id[8] = IDC_BUTTON9;
m_button_id[9] = IDC_BUTTON10;
m_active_index = 0;
}
CRoomView::~CRoomView()
{
}
void CRoomView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CRoomView)
// NOTE: the ClassWizard will add DDX and DDV calls here
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CRoomView, CFormView)
//{{AFX_MSG_MAP(CRoomView)
ON_BN_CLICKED(IDC_BUTTON1, OnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, OnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, OnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, OnClickedButton5)
ON_BN_CLICKED(IDC_BUTTON6, OnClickedButton6)
ON_BN_CLICKED(IDC_BUTTON7, OnClickedButton7)
ON_BN_CLICKED(IDC_BUTTON8, OnClickedButton8)
ON_BN_CLICKED(IDC_BUTTON9, OnClickedButton9)
ON_BN_CLICKED(IDC_BUTTON10, OnClickedButton10)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//*** Override to initialize size and position of the window,
//*** to initialize the association with the document, and to
//*** activate the default student.
void CRoomView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
CMDIChildWnd *frame = (CMDIChildWnd *)GetParentFrame();
if ( frame != 0 )
{
frame->SetWindowPos( 0, ROOM_X, ROOM_Y, ROOM_WIDTH,
ROOM_HEIGHT, SWP_NOZORDER | SWP_NOACTIVATE );
}
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
pDoc->SetRoomFrame( frame );
}
ActivateStudent( 0 );
}
//*** Override to update view with changes in data
void CRoomView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
CButton *button;
CStudent *student;
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
switch ( lHint )
{
case ACTION_CHANGENAME:
//*** Update the button text for the active student.
button =
(CButton *)GetDlgItem( m_button_id[m_active_index] );
student = pDoc->GetStudent( m_active_index );
if ( button != 0 && student != 0 )
{
button->SetWindowText( student->GetName() );
}
break;
default:
//*** If any of the student names have changed, update
//*** the text for the corresponding button.
for ( int i = 0; i < MAX_STUDENTS; i++ )
{
CButton *button = (CButton *)GetDlgItem( m_button_id[i] );
if ( button != 0 )
{
CString button_name;
button->GetWindowText( button_name );
CStudent *student = pDoc->GetStudent(i);
if ( student != 0
&& button_name != student->GetName() )
{
button->SetWindowText( student->GetName() );
}
}
}
}
}
}
//*** Make the given student the active student,
//*** updating other views.
void CRoomView::ActivateStudent( int nIndex )
{
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
pDoc->RetrieveDataFromViews();
m_active_index = nIndex;
pDoc->ViewStudent( nIndex, FALSE );
pDoc->ViewNotes( nIndex, FALSE );
pDoc->UpdateAllViews( NULL, ACTION_ACTIVATE,
pDoc->GetStudent( nIndex ) );
}
}
//////////////////////////////////////////////////////////////////////
// CRoomView message handlers
void CRoomView::OnClickedButton1()
{
//*** Activate the indicated student
ActivateStudent( 0 );
}
void CRoomView::OnClickedButton2()
{
//*** Activate the indicated student
ActivateStudent( 1 );
}
void CRoomView::OnClickedButton3()
{
//*** Activate the indicated student
ActivateStudent( 2 );
}
void CRoomView::OnClickedButton4()
{
//*** Activate the indicated student
ActivateStudent( 3 );
}
void CRoomView::OnClickedButton5()
{
//*** Activate the indicated student
ActivateStudent( 4 );
}
void CRoomView::OnClickedButton6()
{
//*** Activate the indicated student
ActivateStudent( 5 );
}
void CRoomView::OnClickedButton7()
{
//*** Activate the indicated student
ActivateStudent( 6 );
}
void CRoomView::OnClickedButton8()
{
//*** Activate the indicated student
ActivateStudent( 7 );
}
void CRoomView::OnClickedButton9()
{
//*** Activate the indicated student
ActivateStudent( 8 );
}
void CRoomView::OnClickedButton10()
{
//*** Activate the indicated student
ActivateStudent( 9 );
}
//*** Notify the document that this primary view is being closed,
//*** and force closing of any auxiliary views that are open.
void CRoomView::OnDestroy()
{
CFormView::OnDestroy();
// TODO: Add your message handler code here
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
pDoc->SetRoomFrame( 0 );
pDoc->CloseStudentView();
pDoc->CloseNotesView();
}
}
Listing Nine
//////////////////////////////////////////////////////////////////////
//*** student.h - interface for the CStudent class
class CStudent : public CObject
{
public:
CStudent();
//*** Support serialization of the student object
DECLARE_SERIAL( CStudent )
void Serialize( CArchive& ar );
//*** Access functions for data members.
void SetName( const CString& name ) {m_name = name;}
const CString& GetName() {return m_name;}
void SetFullname( const CString& fullname ){m_fullname = fullname;}
const CString& GetFullname() {return m_fullname;}
void SetTitle( const CString& title ) {m_title = title;}
const CString& GetTitle() {return m_title;}
void SetCompany( const CString& company ) {m_company = company;}
const CString& GetCompany() {return m_company;}
void SetPhone( const CString& phone ) {m_phone = phone;}
const CString& GetPhone() {return m_phone;}
void SetInfo( const CString& info ) {m_info = info;}
const CString& GetInfo() {return m_info;}
protected:
//*** Data members representing information describing a student.
CString m_name;
CString m_fullname;
CString m_title;
CString m_company;
CString m_phone;
CString m_info;
};
Listing Ten
//////////////////////////////////////////////////////////////////////
// student.cpp - implementation of the CStudent class
#include "stdafx.h"
#include "student.h"
//*** Support serialization of the student object.
IMPLEMENT_SERIAL( CStudent, CObject, 1 )
CStudent::CStudent()
{
//*** Initialize data members.
m_name = "";
m_fullname = "";
m_title = "";
m_company = "";
m_phone = "";
m_info = "";
}
//*** Serialize the data members representating information about
//*** a student.
void
CStudent::Serialize( CArchive& ar )
{
CObject::Serialize(ar);
if(ar.IsStoring())
{
ar << m_name << m_fullname << m_title
<< m_company << m_phone << m_info;
}
else
{
ar >> m_name >> m_fullname >> m_title
>> m_company >> m_phone >> m_info;
}
}
Listing Eleven
//////////////////////////////////////////////////////////////////////
// studview.h : interface for the CStudentView class
#ifndef __AFXEXT_H__
#include <afxext.h>
#endif
// forward references
class CSeminarDoc;
class CStudent;
// class declaration
class CStudentView : public CFormView
{
DECLARE_DYNCREATE(CStudentView)
protected:
CStudentView(); // protected constructor used by dynamic creation
// Form Data
public:
//{{AFX_DATA(CStudentView)
enum { IDD = IDD_STUDENT };
CString m_company;
CString m_fullname;
CString m_name;
CString m_phone;
CString m_title;
//}}AFX_DATA
// Attributes
public:
//*** Access functions for data members.
CSeminarDoc* GetDocument();
void SetStudent( CStudent *student );
protected:
//*** Data member to keep track of active student.
CStudent *m_student;
// Operations
public:
//*** Provide service for transferring data from view to document
void UpdateDocument();
// Implementation
protected:
virtual ~CStudentView();
virtual void DoDataExchange(CDataExchange* pDX);
//*** Override to update view with changes in data
virtual void OnUpdate(CView* pSender, LPARAM lHint,
CObject* pHint);
//*** Reinitialize all data members holding student data.
void ClearData();
// Generated message map functions
//{{AFX_MSG(CStudentView)
afx_msg void OnDestroy();
afx_msg void OnChangeName();
afx_msg void OnChangeFullname();
afx_msg void OnChangeTitle();
afx_msg void OnChangeCompany();
afx_msg void OnChangePhone();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//*** Inline implementations for access functions.
inline CSeminarDoc* CStudentView::GetDocument()
{ return (CSeminarDoc*) m_pDocument; }
inline void CStudentView::SetStudent( CStudent *student )
{ m_student = student; }
Listing Twelve
//////////////////////////////////////////////////////////////////////
// studview.cpp : implementation of the CStudentView class
#include "stdafx.h"
#include "seminar.h"
#include "student.h"
#include "semdoc.h"
#include "studview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CStudentView, CFormView)
CStudentView::CStudentView()
: CFormView(CStudentView::IDD)
{
//{{AFX_DATA_INIT(CStudentView)
m_company = "";
m_fullname = "";
m_name = "";
m_phone = "";
m_title = "";
//}}AFX_DATA_INIT
m_student = 0;
}
CStudentView::~CStudentView()
{
}
void CStudentView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CStudentView)
DDX_Text(pDX, IDC_COMPANY, m_company);
DDX_Text(pDX, IDC_FULLNAME, m_fullname);
DDX_Text(pDX, IDC_NAME, m_name);
DDX_Text(pDX, IDC_PHONE, m_phone);
DDX_Text(pDX, IDC_TITLE, m_title);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CStudentView, CFormView)
//{{AFX_MSG_MAP(CStudentView)
ON_WM_DESTROY()
ON_EN_CHANGE(IDC_NAME, OnChangeName)
ON_EN_CHANGE(IDC_FULLNAME, OnChangeFullname)
ON_EN_CHANGE(IDC_TITLE, OnChangeTitle)
ON_EN_CHANGE(IDC_COMPANY, OnChangeCompany)
ON_EN_CHANGE(IDC_PHONE, OnChangePhone)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CStudentView::ClearData()
{
//*** Clear all data members holding student data.
m_company = "";
m_fullname = "";
m_name = "";
m_phone = "";
m_title = "";
}
//*** Override to update view with changes in data
void CStudentView::OnUpdate(CView* pSender, LPARAM lHint,
CObject* pHint)
{
if ( m_student == 0 )
{
ClearData();
}
else
{
m_name = m_student->GetName();
m_fullname = m_student->GetFullname();
m_title = m_student->GetTitle();
m_company = m_student->GetCompany();
m_phone = m_student->GetPhone();
}
UpdateData( FALSE );
}
//*** Transfer data from view to document
void CStudentView::UpdateDocument()
{
UpdateData( TRUE );
if ( m_student != 0 )
{
m_student->SetName( m_name );
m_student->SetFullname( m_fullname );
m_student->SetTitle( m_title );
m_student->SetCompany( m_company );
m_student->SetPhone( m_phone );
}
}
//////////////////////////////////////////////////////////////////////
// CStudentView message handlers
void CStudentView::OnDestroy()
{
//*** Transfer student data to document and notify document of
//*** view closing.
UpdateDocument();
CFormView::OnDestroy();
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
pDoc->StudentViewClosed();
}
}
void CStudentView::OnChangeName()
{
//*** Retrieve student name after every keystroke and notify
//*** other views of the changes.
CSeminarDoc *pDoc = GetDocument();
if ( pDoc != 0 )
{
CString name;
CWnd *control = GetDlgItem( IDC_NAME );
if ( control != 0 && m_student != 0 )
{
control->GetWindowText( name );
m_student->SetName( name );
pDoc->UpdateAllViews( this, ACTION_CHANGENAME, m_student );
}
pDoc->SetModifiedFlag();
}
}
void CStudentView::OnChangeFullname()
{
//*** Mark the document as 'dirty' to force prompt for saving
//*** document if user exits program,r closes document, or
//*** causes destruction of document object by closing primary
//*** view (which in this application forces closing of all
//*** auxiliary views).
GetDocument()->SetModifiedFlag();
}
void CStudentView::OnChangeTitle()
{
//*** Mark document as 'dirty'
GetDocument()->SetModifiedFlag();
}
void CStudentView::OnChangeCompany()
{
//*** Mark document as 'dirty'
GetDocument()->SetModifiedFlag();
}
void CStudentView::OnChangePhone()
{
//*** Mark document as 'dirty'
GetDocument()->SetModifiedFlag();
}
Listing Thirteen
//////////////////////////////////////////////////////////////////////
// noteview.h : interface for the CNotesView class
//*** forward references
class CSeminarDoc;
// class declaration
class CNotesView : public CEditView
{
DECLARE_DYNCREATE(CNotesView)
protected:
CNotesView(); // protected constructor used by dynamic creation
// Attributes
public:
CSeminarDoc* GetDocument();
//*** Maintain pointer to current student and provide
//*** access functions.
CStudent *GetStudent();
void SetStudent( CStudent *student );
protected:
CStudent *m_student;
// Operations
public:
//*** Provide service for transferring data from view to document
void UpdateDocument();
// Implementation
protected:
virtual ~CNotesView();
virtual void OnDraw(CDC* pDC); // overridden to draw this view
//*** Override to update view with changes in data
virtual void OnUpdate(CView* pSender, LPARAM lHint,
CObject* pHint);
// Generated message map functions
protected:
//{{AFX_MSG(CNotesView)
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//*** Inline implementations for access functions.
inline CSeminarDoc* CNotesView::GetDocument()
{ return (CSeminarDoc*) m_pDocument; }
inline void CNotesView::SetStudent( CStudent *student )
{ m_student = student; }
inline CStudent *CNotesView::GetStudent()
{ return m_student; }
Listing Fourteen
//////////////////////////////////////////////////////////////////////
// noteview.cpp : implementation of the CNotesView class
#include "stdafx.h"
#include "seminar.h"
#include "student.h"
#include "semdoc.h"
#include "noteview.h"
#include "notesfrm.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CNotesView, CEditView)
CNotesView::CNotesView()
{
m_student = 0;
}
CNotesView::~CNotesView()
{
}
BEGIN_MESSAGE_MAP(CNotesView, CEditView)
//{{AFX_MSG_MAP(CNotesView)
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//////////////////////////////////////////////////////////////////////
// CNotesView drawing
void CNotesView::OnDraw(CDC* pDC)
{
}
//*** Override to update view with changes in data
void CNotesView::OnUpdate(CView* pSender, LPARAM lHint,
CObject* pHint)
{
CNotesFrame *frame = (CNotesFrame *)GetParentFrame();
switch ( lHint )
{
case ACTION_CHANGENAME:
if ( frame != 0 &&
frame->IsKindOf( RUNTIME_CLASS(CNotesFrame) ) )
{
frame->OnUpdateFrameTitle( FALSE );
}
break;
default:
CEdit& notes_control = GetEditCtrl();
if ( m_student != 0 )
{
const CString& info = m_student->GetInfo();
notes_control.SetWindowText( info );
notes_control.SetModify( FALSE );
}
}
}
//*** Transfer data from view to document
void CNotesView::UpdateDocument()
{
CEdit& notes_control = GetEditCtrl();
if ( notes_control.GetModify() && m_student != 0 )
{
// Transfer info from the edit control to the student data
CString notes;
notes_control.GetWindowText( notes );
m_student->SetInfo( notes );
notes_control.SetModify( FALSE );
}
}
//////////////////////////////////////////////////////////////////////
// CNotesView message handlers
void CNotesView::OnDestroy()
{
//*** Transfer notes to document and notify document of
//*** view closing.
UpdateDocument();
CEditView::OnDestroy();
GetDocument()->NotesViewClosed();
}
Listing Fifteen
//////////////////////////////////////////////////////////////////////
// notesfrm.h : interface for the CNotesFrame class
class CNotesFrame : public CMDIChildWnd
{
DECLARE_DYNCREATE(CNotesFrame)
protected:
CNotesFrame(); // protected constructor used by dynamic creation
// Attributes
public:
// Operations
public:
//*** Override to customize frame title
virtual void OnUpdateFrameTitle( BOOL bAddToTitle );
// Implementation
protected:
virtual ~CNotesFrame();
// Generated message map functions
//{{AFX_MSG(CNotesFrame)
// NOTE - the ClassWizard will add and remove functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
Listing Sixteen
//////////////////////////////////////////////////////////////////////
// notesfrm.cpp : implementation of the CNotesFrame class
#include "stdafx.h"
#include "seminar.h"
#include "student.h"
#include "notesfrm.h"
#include "noteview.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNCREATE(CNotesFrame, CMDIChildWnd)
CNotesFrame::CNotesFrame()
{
}
CNotesFrame::~CNotesFrame()
{
}
BEGIN_MESSAGE_MAP(CNotesFrame, CMDIChildWnd)
//{{AFX_MSG_MAP(CNotesFrame)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
//*** Override to customize frame title
void CNotesFrame::OnUpdateFrameTitle( BOOL bAddToTitle )
{
CStudent *student =
((CNotesView *)GetActiveView())->GetStudent();
CString student_name = "< nameless student >";
if ( student != 0 && student->GetName() != "" )
{
student_name = student->GetName();
}
CString title = "Notes on " + student_name;
SetWindowText( title );
}