Programming Microsoft Visual C++

The first of this chapter's two examples shows a very simple document-view interaction. The CEx16aDoc document class, derived from CDocument, allows for a single embedded CStudent object. The CStudent class represents a student record composed of a CString name and an integer grade. The CEx16aView view class is derived from CFormView. It is a visual representation of a student record that has edit controls for the name and grade. The default Enter pushbutton updates the document with data from the edit controls. Figure 16-1 shows the EX16A program window.

Figure 16-1. The EX16A program in action.

Figure 16-2 shows the code for the CStudent class. Most of the class's features serve EX16A, but a few items carry forward to EX16B and the programs discussed in Chapter 17. For now, take note of the two data members, the default constructor, the operators, and the Dump function declaration. The DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC macros ensure that the class name is available for the diagnostic dump.

 

STUDENT.H

// student.h #ifndef _INSIDE_VISUAL_CPP_STUDENT #define _INSIDE_VISUAL_CPP_STUDENT class CStudent : public CObject { DECLARE_DYNAMIC(CStudent) public: CString m_strName; int m_nGrade; CStudent() { m_nGrade = 0; } CStudent(const char* szName, int nGrade) : m_strName(szName) { m_nGrade = nGrade; } CStudent(const CStudent& s) : m_strName(s.m_strName) { // copy constructor m_nGrade = s.m_nGrade; } const CStudent& operator =(const CStudent& s) { m_strName = s.m_strName; m_nGrade = s.m_nGrade; return *this; } BOOL operator ==(const CStudent& s) const { if ((m_strName == s.m_strName) && (m_nGrade == s.m_nGrade)) { return TRUE; } else { return FALSE; } } BOOL operator !=(const CStudent& s) const { // Let's make use of the operator we just defined! return !(*this == s); } #ifdef _DEBUG void Dump(CDumpContext& dc) const; #endif // _DEBUG }; #endif // _INSIDE_VISUAL_CPP_STUDENT

Figure 16-2. The CPersistentView class listing.

 

STUDENT.CPP

#include "stdafx.h" #include "student.h" IMPLEMENT_DYNAMIC(CStudent, CObject) #ifdef _DEBUG void CStudent::Dump(CDumpContext& dc) const { CObject::Dump(dc); dc << "m_strName = " << m_strName << "\nm_nGrade = " <<m_nGrade; } #endif // _DEBUG

Follow these steps to build the EX16A example:

  1. Run AppWizard to generate \vcpp32\ex16a\ex16a. In the Step 6 page, change the view's base class to CFormView, as shown here.

    The options and the default class names are shown here.

  2. Use the menu editor to replace the Edit menu options. Delete the current Edit menu items and replace them with a Clear All option, as shown here.

    Use the default constant ID_EDIT_CLEAR_ALL, which is assigned by the application framework. A menu prompt automatically appears.

  3. Use the dialog editor to modify the IDD_EX16A_FORM dialog. Open the AppWizard-generated dialog IDD_EX16A_FORM, and add controls as shown below.

    Be sure that the Styles properties are set exactly as shown in the Dialog Properties dialog (Style = Child; Border = None) and that Visible is unchecked.

    Use the following IDs for the controls.

    Control ID
    Name edit control IDC_NAME
    Grade edit control IDC_GRADE
    Enter pushbutton IDC_ENTER

  4. Use ClassWizard to add message handlers for CEx16aView. Select the CEx16aView class, and then add handlers for the following messages. Accept the default function names.
    Object ID MessageMember Function
    IDC_ENTER BN_CLICKED OnEnter
    ID_EDIT_CLEAR_ALL COMMAND OnEditClearAll
    ID_EDIT_CLEAR_ALL UPDATE_COMMAND_UI OnUpdateEditClearAll

  5. Use ClassWizard to add variables for CEx16aView. Click on the Member Variables tab in the MFC ClassWizard dialog, and then add the following variables.
    Control IDMember VariableCategoryVariable Type
    IDC_GRADE m_nGrade Value int
    IDC_NAME m_strName Value CString

    For m_nGrade, enter a minimum value of 0 and a maximum value of 100. Notice that ClassWizard generates the code necessary to validate data entered by the user.

  6. Add a prototype for the helper function UpdateControlsFromDoc.In the ClassView window, right-click on CEx16aView and choose Add Member Function. Fill out the dialog box to add the following function:

    private: void UpdateControlsFromDoc();

  7. Edit the file Ex16aView.cpp. AppWizard generated the skeleton OnInitialUpdate function, and ClassView generated the skeleton UpdateControlsFromDoc function. UpdateControlsFromDoc is a private helper member function that transfers data from the document to the CEx16aView data members and then to the dialog edit controls. Edit the code as shown here:

    void CEx16aView::OnInitialUpdate() { // called on startup UpdateControlsFromDoc(); } void CEx16aView::UpdateControlsFromDoc() { // called from OnInitialUpdate and OnEditClearAll CEx16aDoc* pDoc = GetDocument(); m_nGrade = pDoc->m_student.m_nGrade; m_strName = pDoc->m_student.m_strName; UpdateData(FALSE); // calls DDX }

    The OnEnter function replaces the OnOK function you'd expect to see in a dialog class. The function transfers data from the edit controls to the view's data members and then to the document. Add the boldface code shown here:

    void CEx16aView::OnEnter() { CEx16aDoc* pDoc = GetDocument(); UpdateData(TRUE); pDoc->m_student.m_nGrade = m_nGrade; pDoc->m_student.m_strName = m_strName; }

    In a complex multiview application, the Edit Clear All command would be routed directly to the document. In this simple example, it's routed to the view. The update command UI handler disables the menu item if the document's student object is already blank. Add the following boldface code:

    void CEx16aView::OnEditClearAll() { GetDocument()->m_student = CStudent(); // "blank" student object UpdateControlsFromDoc(); } void CEx16aView::OnUpdateEditClearAll(CCmdUI* pCmdUI) { pCmdUI->Enable(GetDocument()->m_student != CStudent()); // blank? }

  8. Edit the EX16A project to add the files for CStudent. Choose Add To Project from the Project menu, choose Files from the submenu, and select the Student.h header and the Student.cpp source code files. Visual C++ will add the files' names to the project's DSP file so that they will be compiled when you build the project.

  9. Add a CStudent data member to the CEx16aDoc class. Use ClassView to add the following data member, and the #include will be added automatically.

    public: CStudent m_student;

    The CStudent constructor is called when the document object is constructed, and the CStudent destructor is called when the document object is destroyed.

  10. Edit the Ex16aDoc.cpp file. Use the CEx16aDoc constructor to initialize the student object, as shown here:

    CEx16aDoc::CEx16aDoc() : m_student("default value", 0) { TRACE("Document object constructed\n"); }

    We can't tell whether the EX16A program works properly unless we dump the document when the program exits. We'll use the destructor to call the document's Dump function, which calls the CStudent::Dump function shown here:

    CEx16aDoc::~CEx16aDoc() { #ifdef _DEBUG Dump(afxDump); #endif // _DEBUG } void CEx16aDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); dc << "\n" << m_student << "\n"; }

  11. Build and test the EX16A application. Type a name and a grade, and then click Enter. Now exit the application. Does the Debug window show messages similar to those shown here?

    a CEx16aDoc at $411580 m_strTitle = Untitled m_strPathName = m_bModified = 0 m_pDocTemplate = $4113A0 a CStudent at $4115D4 m_strName = Sullivan, Walter m_nGrade = 78

To see these messages, you must compile the application with the Win32 Debug target selected and you must run the program from the debugger.

Категории