Programming with Microsoft Visual C++.NET 6ed [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Programming with Microsoft Visual C++.NET 6ed [Electronic resources] - نسخه متنی

George Shepherd, David Kruglinski

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
توضیحات
افزودن یادداشت جدید








The Ex15b Example: A Multi-View SDI Application


This second SDI example improves on Ex15a in the following ways:



    Instead of a single embedded CStudent object, the document contains a list of CStudent objects. (Now you see the reason for using the CStudent class instead of making m_strName and m_nGrade data members of the document.)



    Toolbar buttons allow the user to sequence through the list.



    The application is structured to allow the addition of extra views. The Edit Clear All command is now routed to the document object, so the document's UpdateAllViews function and the view's OnUpdate function are brought into play.



    The student-specific view code is isolated so that the CEx15bView class can later be transformed into a base class that contains only general-purpose code. Derived classes can override selected functions to accommodate lists of application-specific objects.



The Ex15b window, shown in Figure 15-1. The toolbar buttons are enabled only when appropriate. The Next (down arrow) button, for example, is disabled when we're positioned at the bottom of the list.


Figure 15-2: The Ex15b program in action.

The toolbar buttons function as follows.




























Button


Function




Retrieves the first student record




Retrieves the last student record




Retrieves the previous student record




Retrieves the next student record




Inserts a new student record




Deletes the current student record


The Clear button in the view window clears the contents of the Name and Grade edit controls. The Clear All command on the Edit menu deletes all the student records in the list and clears the view's edit controls.

This example deviates from the step-by-step format in the previous examples. There's now more code, so we'll simply show selected code and the resource requirements. Boldface code indicates additional code or other changes that you enter in the output from the MFC Application Wizard and the code wizards available from Class View's Properties window. The frequent use of TRACE statements lets you follow the program's execution in the debugging window.


Resource Requirements


The file

Ex15b.rc defines the application's resources as follows.

Toolbar


The toolbar (visible in Figure 15-2) was created by erasing the Edit Cut, Copy, and Paste tiles (fourth, fifth, and sixth from the left) and replacing them with six new patterns. The Flip Vertical command (on the Image menu) was used to duplicate some of the tiles. The

Ex15b.rc file defines the linkage between the command IDs and the toolbar buttons.


Student Menu


It isn't absolutely necessary to have menu commands that correspond to the new toolbar buttons. (Class View's Properties window allows you to map toolbar button commands just as easily as menu commands.) However, most applications for Windows have corresponding menu commands, so users generally expect them.


Edit Menu


On the Edit menu, the clipboard commands are replaced by the Clear All command. See step 2 of the Ex15a example for an illustration of the Edit menu.


The IDD_EX15B_FORM Dialog Template


The IDD_EX15B_FORM dialog template is similar to the Ex15a dialog box shown in Figure 15-1 except that the Enter pushbutton has been replaced by the Clear pushbutton.

The following IDs identify the controls:



















Control


ID


Name edit control


IDC_NAME


Grade edit control


IDC_GRADE


Clear pushbutton


IDC_CLEAR


The controls' styles are the same as for the Ex15a program.




Code Requirements


Here's a list of the files and classes in the Ex15b example.




























Header File


Source Code File


Classes


Description


Ex15b.h


Ex15b.cpp


CEx15bAppCAboutDlg


Application class (from the MFC Application Wizard) About dialog box


MainFrm.h


MainFrm.cpp


CMainFrame


SDI main frame


Ex15bDoc.h


Ex15bDoc.cpp


Ex15bDoc


Student document


Ex15b.h


Ex15b.cpp


Ex15bView


Student form view (derived from CFormView)


Student.h


Student.cpp


Cstudent


Student record (similar to Ex15a)


StdAfx.h


StdAfx.cpp


Includes the standard precompiled headers



CEx15bApp


The files

Ex15b.cpp and

Ex15b.h are the standard MFC Application Wizard output.



CMainFrame


The code for the CMainFrame class in

MainFrm.cpp is the standard MFC Application Wizard output.



CStudent


This is the code from Ex15a, except for the following line added at the end of

Student.h :

typedef CTypedPtrList<CObList, CStudent*> CStudentList;





Note

Use of the MFC template collection classes requires the following statement in

StdAfx.h :


#include <afxtempl.h>




CEx15bDoc


The MFC Application Wizard originally generated the CEx15bDoc class. The code used in the Ex15b example is shown here:

Ex15bDoc.h






// Ex15bDoc.h : interface of the CEx15bDoc class
//
#pragma once
#include "student.h"
class CEx15bDoc : public CDocument
{
protected: // create from serialization only
CEx15bDoc();
DECLARE_DYNCREATE(CEx15bDoc)
// Attributes
public:
CStudentList* GetList() {
return &m_studentList;
}
// Operations
public:
// Overrides
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
// Implementation
public:
virtual ~CEx15bDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
private:
CStudentList m_studentList;
};












Ex15bDoc.cpp






// Ex15bDoc.cpp : implementation of the CEx15bDoc class
//
#include "stdafx.h"
#include "Ex15b.h"
#include "Ex15bDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CEx15bDoc
IMPLEMENT_DYNCREATE(CEx15bDoc, CDocument)
BEGIN_MESSAGE_MAP(CEx15bDoc, CDocument)
ON_COMMAND(ID_EDIT_CLEARALL, OnEditClearall)
ON_UPDATE_COMMAND_UI(ID_EDIT_CLEARALL, OnUpdateEditClearall)
END_MESSAGE_MAP()
// CEx15bDoc construction/destruction
CEx15bDoc::CEx15bDoc()
{
TRACE("Entering CEx15bDoc constructor\n");
#ifdef _DEBUG
afxDump.SetDepth(1); // Ensure dump of list elements
#endif // _DEBUG
}
CEx15bDoc::~CEx15bDoc()
{
}
BOOL CEx15bDoc::OnNewDocument()
{
TRACE("Entering CEx15bDoc::OnNewDocument\n");
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
// CEx15bDoc serialization
void CEx15bDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
}
else
{
// TODO: add loading code here
}
}
// CEx15bDoc diagnostics
#ifdef _DEBUG
void CEx15bDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CEx15bDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
dc << "\n" << m_studentList << "\n";
}
#endif //_DEBUG
// CEx15bDoc commands
void CEx15bDoc::DeleteContents()
{
#ifdef _DEBUG
Dump(afxDump);
#endif
while (m_studentList.GetHeadPosition()) {
delete m_studentList.RemoveHead();
}
}
void CEx15bDoc::OnEditClearall()
{
DeleteContents();
UpdateAllViews(NULL);
}
void CEx15bDoc::OnUpdateEditClearall(CCmdUI *pCmdUI)
{
pCmdUI->Enable(!m_studentList.IsEmpty());
}












Message Handlers for CEx15bDoc


The Edit Clear All command is handled in the document class. The following message handlers were added through Class View's Properties window.
















Object ID


Message


Member Function


ID_EDIT_CLEARALL


COMMAND


OnEditClearall


ID_EDIT_CLEARALL


ON_UPDATE_COMMAND_UI


OnUpdateEditClearall



Data Members


The document class provides for an embedded CStudentList object, the m_stu-dentList data member, which holds pointers to CStudent objects. The list object is constructed when the CEx15bDoc object is constructed, and it is destroyed at program exit. CStudentList is a typedef for a CTypedPtrList for CStudent pointers.


Constructor


The document constructor sets the depth of the dump context so that a dump of the list causes dumps of the individual list elements.



GetList


The inline GetList function helps isolate the view from the document. The document class must be specific to the type of object in the list—in this case, objects of the class CStudent. A generic list view base class, however, can use a member function to get a pointer to the list without knowing the name of the list object.



DeleteContents


The DeleteContents function is a virtual override function that is called by other document functions and by the application framework. Its job is to remove all student object pointers from the document's list and to delete those student objects. An important point to remember here is that SDI document objects are reused after they're closed. DeleteContents also dumps the student list.



Dump


The MFC Application Wizard generates the Dump function skeleton between the lines #ifdef _DEBUG and #endif. Because the afxDump depth was set to 1 in the document constructor, all the CStudent objects contained in the list are dumped.



CEx15bView


The code for the CEx15bView class is shown in the following code listing.

Ex15bView.h






// Ex15bView.h : interface of the CEx15bView class
//
#pragma once
class CEx15bView : public CFormView
{
protected:
POSITION m_position; // current position in document list
CStudentList* m_pList; // copied from document
protected: // create from serialization only
CEx15bView();
DECLARE_DYNCREATE(CEx15bView)
public:
enum{ IDD = IDD_EX15B_FORM };
// Attributes
public:
CEx15bDoc* GetDocument() const;
// Operations
public:
// Overrides
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
virtual void OnInitialUpdate(); // called first time after construct
// Implementation
public:
virtual ~CEx15bView();
#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:
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnStudentHome();
afx_msg void OnStudentDelete();
afx_msg void OnStudentEnd();
afx_msg void OnStudentInsert();
afx_msg void OnStudentNext();
afx_msg void OnStudentPrevious();
afx_msg void OnUpdateStudentHome(CCmdUI *pCmdUI);
afx_msg void OnUpdateStudentDelete(CCmdUI *pCmdUI);
afx_msg void OnUpdateStudentEnd(CCmdUI *pCmdUI);
afx_msg void OnUpdateStudentNext(CCmdUI *pCmdUI);
afx_msg void OnUpdateStudentPrevious(CCmdUI *pCmdUI);
int m_nGrade;
CString m_strName;
protected:
virtual void OnUpdate(Cview* /*pSender/,
LPARAM /*lHint*/, CObject* /*pHint*/)
public:
afx_msg void OnBnClickedClear();
};
#ifndef _DEBUG // debug version in Ex15bView.cpp
inline CEx15bDoc* CEx15bView::GetDocument() const
{ return reinterpret_cast<CEx15bDoc*>(m_pDocument); }
#endif











Ex15bView.cpp






// Ex15bView.cpp : implementation of the CEx15bView class
//
#include "stdafx.h"
#include "Ex15b.h"
#include "Ex15bDoc.h"
#include "Ex15bView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CEx15bView
IMPLEMENT_DYNCREATE(CEx15bView, CFormView)
BEGIN_MESSAGE_MAP(CEx15bView, CFormView)
ON_COMMAND(ID_STUDENT_HOME, OnStudentHome)
ON_COMMAND(ID_STUDENT_DELETE, OnStudentDelete)
ON_COMMAND(ID_STUDENT_END, OnStudentEnd)
ON_COMMAND(ID_STUDENT_INSERT, OnStudentInsert)
ON_COMMAND(ID_STUDENT_NEXT, OnStudentNext)
ON_COMMAND(ID_STUDENT_PREVIOUS, OnStudentPrevious)
ON_UPDATE_COMMAND_UI(ID_STUDENT_HOME, OnUpdateStudentHome)
ON_UPDATE_COMMAND_UI(ID_STUDENT_DELETE, OnUpdateStudentDelete)
ON_UPDATE_COMMAND_UI(ID_STUDENT_END, OnUpdateStudentEnd)
ON_UPDATE_COMMAND_UI(ID_STUDENT_NEXT, OnUpdateStudentNext)
ON_UPDATE_COMMAND_UI(ID_STUDENT_PREVIOUS, OnUpdateStudentPrevious)
ON_BN_CLICKED(IDC_CLEAR, OnBnClickedClear)
END_MESSAGE_MAP()
// CEx15bView construction/destruction
CEx15bView::CEx15bView()
: CFormView(CEx15bView::IDD)
, m_nGrade(0)
, m_strName(_T("))
, m_position(NULL)
{
TRACE("Entering CEx15bView constructor\n");
}
CEx15bView::~CEx15bView()
{
}
void CEx15bView::DoDataExchange(CDataExchange* pDX)
{
CFormView::DoDataExchange(pDX);
DDX_Text(pDX, IDC_GRADE, m_nGrade);
DDX_Text(pDX, IDC_NAME, m_strName);
}
BOOL CEx15bView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CFormView::PreCreateWindow(cs);
}
void CEx15bView::OnInitialUpdate()
{
TRACE("Entering CEx15bView::OnInitialUpdate\n");
m_pList = GetDocument()->GetList();
CFormView::OnInitialUpdate();
}
// CEx15bView diagnostics
#ifdef _DEBUG
void CEx15bView::AssertValid() const
{
CFormView::AssertValid();
}
void CEx15bView::Dump(CDumpContext& dc) const
{
CFormView::Dump(dc);
}
CEx15bDoc* CEx15bView::GetDocument() const // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CEx15bDoc)));
return (CEx15bDoc*)m_pDocument;
}
#endif //_DEBUG
// CEx15bView message handlers
void CEx15bView::OnStudentHome()
{
TRACE("Entering CEx15bView::OnStudentHome\n");
// need to deal with list empty condition
if (!m_pList->IsEmpty()) {
m_position = m_pList->GetHeadPosition();
GetEntry(m_position);
}
}
void CEx15bView::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 CEx15bView::OnStudentDelete()
{
// deletes current entry and positions to next one or head
POSITION pos;
TRACE("Entering CEx15bView::OnStudentDelete\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 CEx15bView::OnUpdateStudentDelete(CCmdUI *pCmdUI)
{
// called during idle processing and when Student menu drops down
pCmdUI->Enable(m_position != NULL);
}
void CEx15bView::OnStudentEnd()
{
TRACE("Entering CEx15bView::OnStudentEnd\n");
if (!m_pList->IsEmpty()) {
m_position = m_pList->GetTailPosition();
GetEntry(m_position);
}
}
void CEx15bView::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 CEx15bView::OnStudentInsert()
{
TRACE("Entering CEx15bView::OnStudentInsert\n");
InsertEntry(m_position);
GetDocument()->SetModifiedFlag();
GetDocument()->UpdateAllViews(this);
}
void CEx15bView::OnStudentNext()
{
POSITION pos;
TRACE("Entering CEx15bView::OnStudentNext\n");
if ((pos = m_position) != NULL) {
m_pList->GetNext(pos);
if (pos) {
GetEntry(pos);
m_position = pos;
}
}
}
void CEx15bView::OnUpdateStudentNext(CCmdUI *pCmdUI)
{
OnUpdateStudentEnd(pCmdUI);
}
void CEx15bView::OnStudentPrevious()
{
POSITION pos;
TRACE("Entering CEx15bView::OnStudentPrevious\n");
if ((pos = m_position) != NULL) {
m_pList->GetPrev(pos);
if (pos) {
GetEntry(pos);
m_position = pos;
}
}
}
void CEx15bView::OnUpdateStudentPrevious(CCmdUI *pCmdUI)
{
OnUpdateStudentHome(pCmdUI);
}
void CEx15bView::OnUpdate(CView* /*pSender*/,
LPARAM /*lHint*/, CObject* /*pHint*/)
{
// called by OnInitialUpdate and by UpdateAllViews
TRACE("Entering CEx15bView::OnUpdate\n");
m_position = m_pList->GetHeadPosition();
GetEntry(m_position); // initial data for view
}
void CEx15bView::ClearEntry()
{
m_strName = ";
m_nGrade = 0;
UpdateData(FALSE);
((CDialog*) this)->GotoDlgCtrl(GetDlgItem(IDC_NAME));
}
void CEx15bView::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 CEx15bView::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 CEx15bView::OnBnClickedClear()
{
TRACE("Entering CEx15bView::OnBnClickedClear\n");
ClearEntry();
}












Message Handlers for CEx15bView


Class View's Properties window was used to map the CEx15bView Clear pushbutton notification message as follows:













Object ID


Message


Member Function


IDC_CLEAR


BN_CLICKED


OnBnClickedClear


Because CEx15bView is derived from CFormView, Class View supports the definition of dialog data members. The variables shown here were added using the Add Member Variable Wizard:
















Control ID


Member Variable


Category


Variable Type


IDC_GRADE


m_nGrade


Value


int


IDC_NAME


m_strName


Value


CString


You can use Class View's Properties window to map toolbar button commands to their handlers. Here are the commands and the handler functions to which they were mapped:




























Object ID


Message


Member Function


ID_STUDENT_HOME


COMMAND


OnStudentHome


ID_STUDENT_END


COMMAND


OnStudentEnd


ID_STUDENT_PREVIOUS


COMMAND


OnStudentPrevious


ID_STUDENT_NEXT


COMMAND


OnStudentNext


ID_STUDENT_INSERT


COMMAND


OnStudentInsert


ID_STUDENT_DELETE


COMMAND


OnStudentDelete


Each command handler has built-in error checking.

The following update command user interface message handlers are called during idle processing to update the state of the toolbar buttons and, when the Student menu is painted, to update the menu commands.

























Object ID


Message


Member Function


ID_STUDENT_HOME


UPDATE_COMMAND_UI


OnUpdateStudentHome


ID_STUDENT_END


UPDATE_COMMAND_UI


OnUpdateStudentEnd


ID_STUDENT_PREVIOUS


UPDATE_COMMAND_UI


OnUpdateStudentPrevious


ID_STUDENT_NEXT


UPDATE_COMMAND_UI


OnUpdateStudentNext


ID_STUDENT_DELETE


UPDATE_COMMAND_UI


OnUpdateCommandDelete



For example, the Following button, which retrieves the first student record, is disabled when the list is empty and when the m_position variable is already set to the head of the list.

The Previous button is disabled under the same circumstances, so it uses the same update command user interface handler. The End and the Next buttons share a handler for similar reasons. Because a delay sometimes occurs in calling the update command user interface functions, the command message handlers must look for error conditions.


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.



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.



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 multi-view application, you might need a different strategy for setting the CEx15bView m_position variable in response to document updates from another view.




Protected Virtual Functions


The following three functions are protected virtual functions that deal specifically with CStudent objects: GetEntry, InsertEntry, and ClearEntry. You can transfer these functions to a derived class if you want to isolate the general-purpose list-handling features in a base class.



Testing the Ex15b Application


Fill in the student name and grade fields, and then click this 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. When you exit the application, the debug output should look similar to this:

 a CEx15bDoc at $4116D0
m_strTitle = Untitled
m_strPathName =
m_bModified = 1
m_pDocTemplate = $4113F1
a CObList at $411624
with 4 elements
a CStudent at $412770
m_strName = Fisher, Lon
m_nGrade = 67
a CStudent at $412E80
m_strName = Meyers, Lisa
m_nGrade = 80
a CStudent at $412880
m_strName = Seghers, John
m_nGrade = 92
a CStudent at $4128F0
m_strName = Anderson, Bob
m_nGrade = 87



/ 319