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 pop-up menu named Transfer, move data between the view object and the document object, and a Clear Document menu item erases the document's contents. On the Transfer menu, the Store Data In Document item is grayed when the view hasn't been modified since the last time the data was transferred. The Clear Document item, located on the Edit menu, is grayed when the document is empty. Figure 13-4 shows the first version of the EX13A program in use.
Figure 13-4. The EX13A program in use.
If we exploited 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 EX13A example exercises Visual C++'s wysiwyg menu editor and keyboard accelerator editor together with ClassWizard. You'll need to do very little C++ coding. Simply follow these steps:
The resource editor's menu resource editor is intuitive, but you might need some help the first time you insert an item in the middle of a menu. A blank item is present at the bottom of each menu. Using the mouse, drag the blank item to the insertion position to define a new item. A new blank item will appear at the bottom when you're finished.
Now add a Transfer menu, and then define the underlying items.
Use the following command IDs for your new menu items.
Menu | Caption | Command ID |
Edit | Clear &Document | ID_EDIT_CLEAR_ALL |
Transfer | &Get Data From Document\tF2 | ID_TRANSFER_GETDATA |
Transfer | &Store Data In Document\tF3 | ID_TRANSFER_STOREDATA |
The MFC library has defined the first item, ID_EDIT_CLEAR_ALL. (Note: \t is a tab characterbut type \t; don't press the Tab key.)
When you add the menu items, type appropriate prompt strings in the Menu Item Properties dialog. These prompts will appear in the application's status bar window when the menu item is highlighted.
Accelerator ID | Key |
ID_TRANSFER_GETDATA | VK_F2 |
ID_TRANSFER_STOREDATA | VK_F3 |
Be sure to turn off the Ctrl, Alt, and Shift modifiers. The Accelerator edit screen and Accel Properties dialog are shown in the illustration below.
Object ID | Message | Member Function |
ID_TRANSFER_GETDATA | COMMAND | OnTransferGetData |
ID_TRANSFER_STOREDATA | COMMAND | OnTransferStoreData |
ID_TRANSFER_STOREDATA | UPDATE_COMMAND_UI | OnUpdateTransferStoreData |
Object ID | Message | Member Function |
ID_EDIT_CLEAR_ALL | COMMAND | OnEditClearDocument |
ID_EDIT_CLEAR_ALL | UPDATE_COMMAND_UI | OnUpdateEditClearDocument |
public: CString m_strText;
BOOL CEx13aDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; m_strText = "Hello (from CEx13aDoc::OnNewDocument)"; return TRUE; }
The Edit Clear Document message handler sets m_strText to empty, and the update command UI handler grays the menu item if the string is already empty. Remember that the framework calls OnUpdateEditClearDocument when the Edit menu pops up. Add the following boldface code:
void CEx13aDoc::OnEditClearDocument() { m_strText.Empty(); } void CEx13aDoc::OnUpdateEditClearDocument(CCmdUI* pCmdUI) { pCmdUI->Enable(!m_strText.IsEmpty()); }
public: CRichEditCtrl m_rich;
int CEx13aView::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 CEx13aView::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); }
void CEx13aView::OnTransferGetData() { CEx13aDoc* pDoc = GetDocument(); m_rich.SetWindowText(pDoc->m_strText); m_rich.SetModify(FALSE); }
The OnTransferStoreData 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 UI handler grays the menu item if the control has not been changed since it was last copied to or from the document. Add the following boldface code:
void CEx13aView::OnTransferStoreData() { CEx13aDoc* pDoc = GetDocument(); m_rich.GetWindowText(pDoc->m_strText); m_rich.SetModify(FALSE); } void CEx13aView::OnUpdateTransferStoreData(CCmdUI* pCmdUI) { pCmdUI->Enable(m_rich.GetModify()); }