The Ex12a Example
This example illustrates the routing of menu and keyboard accelerator commands to both documents and views. The application's view class is derived from CView and contains a rich edit control. View-directed menu commands, originating from a new submenu named Transfer, move data between the view object and the document object, and a Clear Document command erases the document's contents. On the Transfer menu, the Store Data In Document command is grayed out if the view hasn't been modified since the last time the data was transferred. The Clear Document command, located on the Edit menu, is grayed out when the document is empty. Figure 12-4 shows the first version of the Ex12a program in use.

Figure 12-4: The Ex12a program in use.
If we were to exploit the document-view architecture fully, we would tell the rich edit control to keep its text inside the document, but that's rather difficult to do. Instead, we'll define a document CString data member named m_strText, the contents of which the user can transfer to and from the control. The initial value of m_strText is a Hello message; choosing Clear Document from the Edit menu sets it to empty. By running this example, you'll start to understand the separation of the document and the view.The first part of the Ex12a example uses Visual C++ .NET's WYSIWYG menu editor and keyboard accelerator editor along with the code wizards available from Class View's Properties window. You'll need to do very little C++ coding. Simply follow these steps:
Run the MFC Application Wizard to generate the Ex12a project. Accept all the default settings but two: Select Single Document and deselect Printing And Print Preview.
Use the resource editor to edit the application's main menu. In Resource View, edit the IDR_MAINFRAME menu resource to add a separator and a Clear Document command to the Edit menu, as shown here:Tip
The resource editor's menu resource editor is intuitive, but you might need some help the first time you insert a command in the middle of a menu. Just right-click where you want to insert the command and choose Insert New from the shortcut menu. You'll automatically see where to add the command. To insert a separator, choose Insert Separator from the shortcut menu.
Now add a Transfer menu, and then define the underlying commands:
The MFC library has defined the following command IDs for your new menu commands in the Resource Symbols dialog box. (Note that \t is a tab character—but type \t; don't press the Tab key.)
Menu
Caption
Command ID
Edit
Clear &Document
ID_EDIT_CLEARDOCUMENT
Transfer
&Get Data From Document\tF2
ID_TRANSFER_GETDATAFROMDOCUMENT
Transfer
&Store Data In Document\tF3
ID_TRANSFER_STOREDATAINDOCUMENT
After you add the commands, right-click on each of them and choose Properties from the shortcut menu. Type an appropriate prompt string in each command's Properties window. These prompts will appear in the application's status bar window when the command is highlighted.
Use the resource editor to add keyboard accelerators. Open the IDR_MAINFRAME accelerator table by double-clicking on its icon in Resource View, and then click on the empty row entry at the bottom of the table to add the following items.
Accelerator ID
Key
ID_TRANSFER_GETDATAFROMDOCUMENT
VK_F2
ID_TRANSFER_STOREDATAINDOCUMENT
VK_F3
Be sure to select None from the drop-down list in the Modifier box to turn off the Ctrl, Alt, and Shift modifiers.
Use Class View's Properties window for the CEx12aView class to add the view class command and update command user interface message handlers. Select the CEx12aView class, and then add the following member functions:
Object ID
Event
Member Function
ID_TRANSFER_GETDATAFROMDOCUMENT
COMMAND
OnTransferGetdatafromdocument
ID_TRANSFER_STOREDATAINDOCUMENT
COMMAND
OnTransferStoredataindocument
ID_TRANSFER_STOREDATAINDOCUMENT
UPDATE_COMMAND_UI
OnUpdateTransferStoredataindocument
Use Class View's Properties window for the CEx12aDoc class to add the document class command and update command user interface message handlers. Select the CEx12aDoc class, and then add the following member functions:
Object ID
Event
Member Function
ID_EDIT_CLEARDOCUMENT
COMMAND
OnEditCleardocument
ID_EDIT_CLEARDOCUMENT
UPDATE_
COMMAND_UI
OnUpdateEditCleardocument
Insert the following line in theEx12aDoc.cpp file:
#include "Ex12aView.h"
Add a CString data member to the CEx12aDoc class. Edit the fileEx12aDoc.h or use Class View.
public:
CString m_strText;
Edit the document class member functions inEx12aDoc.cpp . The OnNewDocument function was generated by Visual Studio .NET. The framework calls this function after it first constructs the document and when the user chooses New from the File menu. Your version sets some text in the string data member. Add the following boldface code:
BOOL CEx12aDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
m_strText = "Hello (from CEx12aDoc::OnNewDocument)";
return TRUE;
}
The Edit Clear Document message handler sets m_strText to empty, and the update command user interface handler grays out the command if the string is already empty. Remember that the framework calls OnUpdateEditCleardocument when the Edit menu is displayed. Add the following boldface code:void CEx12aDoc::OnEditCleardocument()
{
m_strText.Empty();
//reflect changes to the views
POSITION pos = GetFirstViewPosition();
while (pos != NULL)
{
CEx12aView* pView = (CEx12aView*) GetNextView(pos);
pView->m_rich.SetWindowText(m_strText);
}
}
void CEx12aDoc::OnUpdateEditCleardocument(CCmdUI *pCmdUI)
{
pCmdUI->Enable(!m_strText.IsEmpty());
}
Add a CRichEditCtrl data member to the CEx12aView class. Edit the fileEx12aView.h or use Class View.
public:
CRichEditCtrl m_rich;
Use Class View's Properties window to map the WM_CREATE and WM_SIZE messages in the CEx12aView class.The OnCreate function creates the rich edit control. The control's size is 0 here because the view window doesn't have a size yet. Add the following boldface code:int CEx12aView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CRect rect(0, 0, 0, 0);
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_rich.Create(ES_AUTOVSCROLL | ES_MULTILINE | ES_WANTRETURN |
WS_CHILD | WS_VISIBLE | WS_VSCROLL, rect, this, 1);
return 0;
}
Windows sends the WM_SIZE message to the view as soon as the view's initial size is determined and again each time the user changes the frame size. This handler simply adjusts the rich edit control's size to fill the view client area. Add the following boldface code:void CEx12aView::OnSize(UINT nType, int cx, int cy)
{
CRect rect;
CView::OnSize(nType, cx, cy);
GetClientRect(rect);
m_rich.SetWindowPos(&wndTop, 0, 0, rect.right - rect.left,
rect.bottom - rect.top, SWP_SHOWWINDOW);
}
Edit the menu command handler functions inEx12aView.cpp . Visual Studio .NET generated these skeleton functions when you mapped the menu commands in step 4. The OnTransferGetdatafromdocument function gets the text from the document data member and puts it in the rich edit control. The function then clears the control's modified flag. There is no update command user interface handler. Add the following boldface code:
void CEx12aView::OnTransferGetdatafromdocument()
{
CEx12aDoc* pDoc = GetDocument();
m_rich.SetWindowText(pDoc->m_strText);
m_rich.SetModify(FALSE);
}
The OnTransferStoredataindocument function copies the text from the view's rich edit control to the document string and resets the control's modified flag. The corresponding update command user interface handler grays out the command if the control has not been changed since it was last copied to or from the document. Add the following boldface code:void CEx12aView::OnTransferStoredataindocument()
{
CEx12aDoc* pDoc = GetDocument();
m_rich.GetWindowText(pDoc->m_strText);
m_rich.SetModify(FALSE);
}
void CEx12aView::OnUpdateTransferStoredataindocument(CCmdUI* pCmdUI)
{
pCmdUI->Enable(m_rich.GetModify());
}
Build and test the Ex12a application. When the application starts, the Clear Document command on the Edit menu should be enabled. Choose Get Data From Document from the Transfer menu. Some text should appear. Edit the text, and then choose Store Data In Document. That command should now appear gray. Try choosing the Clear Document command, and then choose Get Data From Document again.