_AUXILIARY VIEWS OF WINDOWS APPS_ by Robert Rosenberg 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 #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 #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 ); } Example 1: (a) \nClass\nCLASS Document\nCLASS Files(*.sem)\n.sem\nClassFileType\nCLASS File Type (b) \nClass\n\nCLASS Files(*.sem)\n.sem\nClassFileType\nCLASS File Type Example 2: class 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 ); ... } Example 3: m_notes_frame->SetWindowPos( &CWnd::wndTop, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE ); Example 4: m_notes_template = new CMultiDocTemplate(IDR_NOTESTYPE, RUNTIME_CLASS(CSeminarDoc), RUNTIME_CLASS(CNotesFrame), RUNTIME_CLASS(CNotesView));