| Tenouk C & C++ | MFC Home | Separating the Document from Its View 4 | SDI Serialization 1 | Download | Site Index |


 

 

 

 

 

 

Module 10d:

Separating the Document from Its View 5

 

 

 

 

 

 

 

This is a continuation from the previous module... Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:

 

 

  1. Data Members

  2. OnInitialUpdate()

  3. OnUpdate()

  4. Protected Virtual Functions

  5. CMymfc16View Class

  6. Testing the MYMFC16 Application

  7. Two Exercises for the Reader

 

 

 Data Members

 

The m_position data member is a kind of cursor for the document's collection. It contains the position of the CStudent object that is currently displayed. The m_pList variable provides a quick way to get at the student list in the document.

 

 

Listing 19.

 

OnInitialUpdate()

 

The virtual OnInitialUpdate() function is called when you start the application. It sets the view's m_pList data member for subsequent access to the document's list object.

 

 

Listing 20.

 

OnUpdate()

 

The virtual OnUpdate() function is called both by the OnInitialUpdate() function and by the CDocument::UpdateAllViews function. It resets the list position to the head of the list, and it displays the head entry. In this example, the UpdateAllViews() function is called only in response to the Edit Clear All command. In a multiview application, you might need a different strategy for setting the CMymfc16View m_position variable in response to document updates from another view.

 

 

Listing 21.

 

Protected Virtual Functions

 

The following three functions are protected virtual functions that deal specifically with CStudent objects:

 

  1. GetEntry().

  2. InsertEntry().

  3. ClearEntry().

 

Adding a protected virtual function using ClassView.

 

Figure 32: Adding a protected virtual function using ClassView.

 

 

Listing 22.

 

You can transfer these functions to a derived class if you want to isolate the general-purpose list-handling features in a base class.

 

CMymfc16View Class

 

Listing 23 shows the code for the CMymfc16View class. This code will be carried over into the next two Modules.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC16VIEW.H

// Mymfc16View.h : interface of the CMymfc16View class

//

//////////////////////////////////////////////////////////////////////

 

#if !defined(AFX_MYMFC16VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_)

#define AFX_MYMFC16VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

class CMymfc16View : public CFormView

{

protected:

    POSITION      m_position; // current position in document list

    CStudentList* m_pList;    // copied from document

 

protected: // create from serialization only

    CMymfc16View();

    DECLARE_DYNCREATE(CMymfc16View)

 

public:

    //{{AFX_DATA(CMymfc16View)

    enum { IDD = IDD_MYMFC16_FORM };

    int     m_nGrade;

    CString m_strName;

    //}}AFX_DATA

 

// Attributes

public:

    CMymfc16Doc* GetDocument();

 

// Operations

public:

 

// Overrides

    // ClassWizard generated virtual function overrides

    //{{AFX_VIRTUAL(CMymfc16View)

    public:

    virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

    protected:

    virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support

    virtual void OnInitialUpdate(); // called first time after construct

    virtual void OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint);

    //}}AFX_VIRTUAL

 

// Implementation

public:

    virtual ~CMymfc16View();

#ifdef _DEBUG

    virtual void AssertValid() const;

    virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

    virtual void ClearEntry();

    virtual void InsertEntry(POSITION position);

    virtual void GetEntry(POSITION position);

 

// Generated message map functions

protected:

    //{{AFX_MSG(CMymfc16View)

    afx_msg void OnClear();

    afx_msg void OnStudentHome();

    afx_msg void OnStudentEnd();

    afx_msg void OnStudentPrev();

    afx_msg void OnStudentNext();

    afx_msg void OnStudentIns();

    afx_msg void OnStudentDel();

    afx_msg void OnUpdateStudentHome(CCmdUI* pCmdUI);

    afx_msg void OnUpdateStudentEnd(CCmdUI* pCmdUI);

    afx_msg void OnUpdateStudentDel(CCmdUI* pCmdUI);

    //}}AFX_MSG

    DECLARE_MESSAGE_MAP()

};

 

#ifndef _DEBUG  // debug version in Mymfc16View.cpp

inline CMymfc16Doc* CMymfc16View::GetDocument()

   { return (CMymfc16Doc*)m_pDocument; }

#endif

 

//////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations

// immediately before the previous line.

 

#endif // !defined(AFX_MYMFC16VIEW_H__4D011049_7E1C_11D0_8FE0_00C04FC2A0C2__INCLUDED_)

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC16VIEW.CPP

// Mymfc16View.cpp : implementation of the CMymfc16View class

//

 

#include "stdafx.h"

#include "mymfc16.h"

 

#include "Mymfc16Doc.h"

#include "Mymfc16View.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__ ;

#endif

 

//////////////////////////////////////////////////////////////////////

// CMymfc16View

 

IMPLEMENT_DYNCREATE(CMymfc16View, CFormView)

BEGIN_MESSAGE_MAP(CMymfc16View, CFormView)

    //{{AFX_MSG_MAP(CMymfc16View)

    ON_BN_CLICKED(IDC_CLEAR, OnClear)

    ON_COMMAND(ID_STUDENT_HOME, OnStudentHome)

    ON_COMMAND(ID_STUDENT_END, OnStudentEnd)

    ON_COMMAND(ID_STUDENT_PREV, OnStudentPrev)

    ON_COMMAND(ID_STUDENT_NEXT, OnStudentNext)

    ON_COMMAND(ID_STUDENT_INS, OnStudentIns)

    ON_COMMAND(ID_STUDENT_DEL, OnStudentDel)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_HOME, OnUpdateStudentHome)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_END, OnUpdateStudentEnd)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_PREV, OnUpdateStudentHome)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_NEXT, OnUpdateStudentEnd)

    ON_UPDATE_COMMAND_UI(ID_STUDENT_DEL, OnUpdateStudentDel)

    //}}AFX_MSG_MAP

END_MESSAGE_MAP()

 

//////////////////////////////////////////////////////////////////////

// CMymfc16View construction/destruction

 

CMymfc16View::CMymfc16View() : CFormView(CMymfc16View::IDD)

{

    TRACE("Entering CMymfc16View constructor\n");

    //{{AFX_DATA_INIT(CMymfc16View)

    m_nGrade = 0;

    m_strName = _T("");

    //}}AFX_DATA_INIT

    m_position = NULL;

}

 

CMymfc16View::~CMymfc16View()

{     }

 

void CMymfc16View::DoDataExchange(CDataExchange* pDX)

{

    CFormView::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CMymfc16View)

    DDX_Text(pDX, IDC_GRADE, m_nGrade);

    DDV_MinMaxInt(pDX, m_nGrade, 0, 100);

    DDX_Text(pDX, IDC_NAME, m_strName);

    DDV_MaxChars(pDX, m_strName, 20);

    //}}AFX_DATA_MAP

}

BOOL CMymfc16View::PreCreateWindow(CREATESTRUCT& cs)

{

    // TODO: Modify the Window class or styles here by modifying

    //  the CREATESTRUCT cs

    return CFormView::PreCreateWindow(cs);

}

 

void CMymfc16View::OnInitialUpdate()

{

    TRACE("Entering CMymfc16View::OnInitialUpdate\n");

    m_pList = GetDocument()->GetList();

    CFormView::OnInitialUpdate();

}

 

//////////////////////////////////////////////////////////////////////

// CMymfc16View diagnostics

 

#ifdef _DEBUG

void CMymfc16View::AssertValid() const

{

    CFormView::AssertValid();

}

 

void CMymfc16View::Dump(CDumpContext& dc) const

{

    CFormView::Dump(dc);

}

 

CMymfc16Doc* CMymfc16View::GetDocument() // non-debug version is inline

{

    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMymfc16Doc)));

    return (CMymfc16Doc*)m_pDocument;

}

#endif //_DEBUG

 

//////////////////////////////////////////////////////////////////////

// CMymfc16View message handlers

 

void CMymfc16View::OnClear()

{

    TRACE("Entering CMymfc16View::OnClear\n");

    ClearEntry();

}

 

void CMymfc16View::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)

{

    // called by OnInitialUpdate and by UpdateAllViews

    TRACE("Entering CMymfc16View::OnUpdate\n");

    m_position = m_pList->GetHeadPosition();

    GetEntry(m_position); // initial data for view

}

 

void CMymfc16View::OnStudentHome()

{

    TRACE("Entering CMymfc16View::OnStudentHome\n");

    // need to deal with list empty condition

    if (!m_pList->IsEmpty()) {

        m_position = m_pList->GetHeadPosition();

        GetEntry(m_position);

    }

}

 

void CMymfc16View::OnStudentEnd()

{

    TRACE("Entering CMymfc16View::OnStudentEnd\n");

    if (!m_pList->IsEmpty()) {

        m_position = m_pList->GetTailPosition();

        GetEntry(m_position);

    }

}

 

void CMymfc16View::OnStudentPrev()

{

    POSITION pos;

    TRACE("Entering CMymfc16View::OnStudentPrev\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetPrev(pos);

        if (pos) {

            GetEntry(pos);

      m_position = pos;

        }

    }

}

 

void CMymfc16View::OnStudentNext()

{

    POSITION pos;

    TRACE("Entering CMymfc16View::OnStudentNext\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetNext(pos);

        if (pos) {

            GetEntry(pos);

            m_position = pos;

        }

    }

}

 

void CMymfc16View::OnStudentIns()

{

    TRACE("Entering CMymfc16View::OnStudentIns\n");

    InsertEntry(m_position);

    GetDocument()->SetModifiedFlag();

    GetDocument()->UpdateAllViews(this);

}

 

void CMymfc16View::OnStudentDel()

{

    // deletes current entry and positions to next one or head

    POSITION pos;

    TRACE("Entering CMymfc16View::OnStudentDel\n");

    if ((pos = m_position) != NULL) {

        m_pList->GetNext(pos);

        if (pos == NULL) {

            pos = m_pList->GetHeadPosition();

            TRACE("GetHeadPos = %ld\n", pos);

            if (pos == m_position) {

                pos = NULL;

            }

        }

        GetEntry(pos);

        CStudent* ps = m_pList->GetAt(m_position);

        m_pList->RemoveAt(m_position);

        delete ps;

        m_position = pos;

        GetDocument()->SetModifiedFlag();

        GetDocument()->UpdateAllViews(this);

    }

}

 

void CMymfc16View::OnUpdateStudentHome(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    POSITION pos;

 

    // enables button if list not empty and not at home already

    pos = m_pList->GetHeadPosition();

    pCmdUI->Enable((m_position != NULL) && (pos != m_position));

}

 

void CMymfc16View::OnUpdateStudentEnd(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    POSITION pos;

    // enables button if list not empty and not at end already

    pos = m_pList->GetTailPosition();

    pCmdUI->Enable((m_position != NULL) && (pos != m_position));

}

 

void CMymfc16View::OnUpdateStudentDel(CCmdUI* pCmdUI)

{

    // called during idle processing and when Student menu drops down

    pCmdUI->Enable(m_position != NULL);

}

 

void CMymfc16View::GetEntry(POSITION position)

{

    if (position) {

        CStudent* pStudent = m_pList->GetAt(position);

        m_strName = pStudent->m_strName;

        m_nGrade = pStudent->m_nGrade;

    }

    else {

        ClearEntry();

    }

    UpdateData(FALSE);

}

 

void CMymfc16View::InsertEntry(POSITION position)

{

    if (UpdateData(TRUE)) {

        // UpdateData returns FALSE if it detects a user error

        CStudent* pStudent = new CStudent;

        pStudent->m_strName = m_strName;

        pStudent->m_nGrade = m_nGrade;

        m_position = m_pList->InsertAfter(m_position, pStudent);

    }

}

 

void CMymfc16View::ClearEntry()

{

    m_strName = "";

    m_nGrade = 0;

    UpdateData(FALSE);

    ((CDialog*) this)->GotoDlgCtrl(GetDlgItem(IDC_NAME));

}

 

Listing 23: The CMymfc16View class listing.

 

Testing the MYMFC16 Application

 

Build the program and start it from the debugger.

 

Running MYMFC16 program from the debugger.

 

Figure 33: Running MYMFC16 program from the debugger.

 

 

MYMFC16 program output in action.

 

Figure 34: MYMFC16 program output in action.

 

Fill in the student name and grade fields, and then click the New button:

To insert the entry into the list. Repeat this action several times, using the Clear pushbutton to erase the data from the previous entry. Notice the toolbar buttons enable/disable change. When you exit the application, the debug output should look similar to this:

...

Entering CMymfc16View::OnStudentIns

Entering CMymfc16View::OnClear

Entering CMymfc16View::OnStudentIns

Entering CMymfc16View::OnClear

Entering CMymfc16View::OnStudentIns

Entering CMymfc16View::OnClear

Entering CMymfc16View::OnStudentIns

Entering CMymfc16View::OnClear

a CMymfc16Doc at $4216B0

m_strTitle = Untitled

m_strPathName =

m_bModified = 1

m_pDocTemplate = $4218C0

 

a CObList at $421704

with 4 elements

       a CStudent at $422DD0

m_strName = Mr. Pink Panther

m_nGrade = 95

       a CStudent at $422340

m_strName = Mr. Bush Blair

m_nGrade = 40

       a CStudent at $422460

m_strName = Mrs. Rice Plate

m_nGrade = 67

       a CStudent at $422200

m_strName = Mr. Mechanick

m_nGrade = 88

 

Warning: destroying an unsaved document.

The thread 0x5B8 has exited with code 0 (0x0).

The program 'F:\mfcproject\mymfc16\Debug\mymfc16.exe' has exited with code 0 (0x0).

You can clear all data by using the Edit, Clear All menu.

 

Deleting all the data using the Edit Clear All menu.

 

Figure 35: Deleting all the data using the Edit Clear All menu.

 

Two Exercises for the Learners

 

You might have noticed the absence of a Modify button on the toolbar. Without such a button, you can't modify an existing student record. Can you add the necessary toolbar button and message handlers? The most difficult task might be designing a graphic for the button's tile. Recall that the CMymfc16View class is just about ready to be a general-purpose base class. Try separating the CStudent-specific virtual functions into a derived class. After that, make another derived class that uses a new element class other than CStudent.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

  2. MSDN MFC 9.0 class library online documentation - latest version.

  3. Porting & Migrating your older programs.

  4. MSDN Library

  5. DCOM at MSDN.

  6. COM+ at MSDN.

  7. COM at MSDN.

  8. Windows data type.

  9. Win32 programming Tutorial.

  10. The best of C/C++, MFC, Windows and other related books.

  11. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | Separating the Document from Its View 4 | SDI Serialization 1 | Download | Site Index |