[ Home | Syllabus |Course Notes]
Users expect certain features in modern application UI designs:
MFC encapsulates a lot of the hard work.
IDR_TOOLBAR BITMAP Toolbar.bmp IDR_TOOLBAR TOOLBAR 16, 15 BEGIN BUTTON ID_FILE_NEW BUTTON ID_FILE_OPEN BUTTON ID_FILE_SAVE SEPARATOR BUTTON ID_EDIT_CUT BUTTON ID_EDIT_COPY BUTTON ID_EDIT_PASTE SEPARATOR BUTTON ID_EDIT_UNDO END
Combo Boxes
Use SaveBarState. LoadBarState
Resource File (MyWord.rc)
//*********************************************************************** // // MyWord.rc // //*********************************************************************** #include <afxres.h> #include "Resource.h" IDR_TOOLBAR BITMAP Toolbar.bmp IDR_STYLE_BAR BITMAP StyleBar.bmp IDR_TOOLBAR TOOLBAR 16, 15 BEGIN BUTTON ID_FILE_NEW BUTTON ID_FILE_OPEN BUTTON ID_FILE_SAVE SEPARATOR BUTTON ID_EDIT_CUT BUTTON ID_EDIT_COPY BUTTON ID_EDIT_PASTE SEPARATOR BUTTON ID_EDIT_UNDO END IDR_STYLE_BAR TOOLBAR 16, 15 BEGIN BUTTON ID_CHAR_BOLD BUTTON ID_CHAR_ITALIC BUTTON ID_CHAR_UNDERLINE SEPARATOR BUTTON ID_PARA_LEFT BUTTON ID_PARA_CENTER BUTTON ID_PARA_RIGHT SEPARATOR SEPARATOR // Placeholder for font name combo box SEPARATOR SEPARATOR // Placeholder for font size combo box END IDR_MAINFRAME MENU BEGIN POPUP "&File" { MENUITEM "&New\tCtrl+N", ID_FILE_NEW MENUITEM "&Open...\tCtrl+O", ID_FILE_OPEN MENUITEM "&Save\tCtrl+S", ID_FILE_SAVE MENUITEM "Save &As...\tCtrl+A", ID_FILE_SAVE_AS MENUITEM SEPARATOR MENUITEM "Sen&d...", ID_FILE_SEND_MAIL MENUITEM SEPARATOR MENUITEM "Recent File", ID_FILE_MRU_FILE1 MENUITEM SEPARATOR MENUITEM "E&xit", ID_APP_EXIT } POPUP "&Edit" { MENUITEM "&Undo\tCtrl+Z", ID_EDIT_UNDO MENUITEM SEPARATOR MENUITEM "Cu&t\tCtrl+X", ID_EDIT_CUT MENUITEM "&Copy\tCtrl+C", ID_EDIT_COPY MENUITEM "&Paste\tCtrl+V", ID_EDIT_PASTE MENUITEM "Paste &Special...", ID_EDIT_PASTE_SPECIAL MENUITEM "C&lear\tDel", ID_EDIT_CLEAR MENUITEM "Select A&ll\tCtrl+A", ID_EDIT_SELECT_ALL MENUITEM SEPARATOR MENUITEM "&Find...\tCtrl+F", ID_EDIT_FIND MENUITEM "F&ind Next\tF3", ID_EDIT_REPEAT MENUITEM "R&eplace...\tCtrl+H", ID_EDIT_REPLACE } POPUP "&View" { MENUITEM "&Toolbar", ID_VIEW_TOOLBAR MENUITEM "Style &Bar", ID_VIEW_STYLE_BAR MENUITEM "&Status Bar", ID_VIEW_STATUS_BAR } END IDR_MAINFRAME ACCELERATORS BEGIN "N", ID_FILE_NEW, VIRTKEY, CONTROL "O", ID_FILE_OPEN, VIRTKEY, CONTROL "S", ID_FILE_SAVE, VIRTKEY, CONTROL "A", ID_FILE_SAVE_AS, VIRTKEY, CONTROL "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL "X", ID_EDIT_CUT, VIRTKEY, CONTROL "C", ID_EDIT_COPY, VIRTKEY, CONTROL "V", ID_EDIT_PASTE, VIRTKEY, CONTROL "A", ID_EDIT_SELECT_ALL, VIRTKEY, CONTROL "F", ID_EDIT_FIND, VIRTKEY, CONTROL VK_F3, ID_EDIT_REPEAT, VIRTKEY "H", ID_EDIT_REPLACE, VIRTKEY, CONTROL "B", ID_CHAR_BOLD, VIRTKEY, CONTROL "I", ID_CHAR_ITALIC, VIRTKEY, CONTROL "U", ID_CHAR_UNDERLINE, VIRTKEY, CONTROL END STRINGTABLE BEGIN IDR_MAINFRAME "MyWord\n\n\nMyWord Files (*.mwd)\n.mwd\nMyWord.Document\nMyWord Document" END STRINGTABLE BEGIN AFX_IDS_IDLEMESSAGE "Ready" ID_VIEW_TOOLBAR "Show or hide the main toolbar" ID_VIEW_STYLE_BAR "Show or hide the style bar" ID_CHAR_BOLD "Toggle boldface on or off\nBold" ID_CHAR_ITALIC "Toggle italics on or off\nItalic" ID_CHAR_UNDERLINE "Toggle underline on or off\nUnderline" ID_PARA_LEFT "Align text flush left\nAlign Left" ID_PARA_CENTER "Center text between margins\nAlign Center" ID_PARA_RIGHT "Align text flush right\nAlign Right" IDC_FONTNAMES "Select a typeface\nTypeface" IDC_FONTSIZES "Select a point size\nFont Size" ID_INDICATOR_LINE "Line 00000" ID_INDICATOR_CAPS "CAPS" END
//*********************************************************************** // // MainFrame.h // //*********************************************************************** class CMainFrame : public CFrameWnd { DECLARE_DYNCREATE (CMainFrame) private: CToolBar m_wndToolBar; CStyleBar m_wndStyleBar; CStatusBar m_wndStatusBar; BOOL CreateToolBar (); BOOL CreateStyleBar (); BOOL CreateStatusBar (); protected: afx_msg int OnCreate (LPCREATESTRUCT); afx_msg void OnClose (); DECLARE_MESSAGE_MAP () };
//*********************************************************************** // // MainFrame.cpp // //*********************************************************************** #include <afxwin.h> #include <afxext.h> #include "Resource.h" #include "StyleBar.h" #include "MainFrame.h" IMPLEMENT_DYNCREATE (CMainFrame, CFrameWnd) BEGIN_MESSAGE_MAP (CMainFrame, CFrameWnd) ON_WM_CREATE () ON_COMMAND_EX (ID_VIEW_STYLE_BAR, OnBarCheck) ON_UPDATE_COMMAND_UI (ID_VIEW_STYLE_BAR, OnUpdateControlBarMenu) ON_WM_CLOSE () END_MESSAGE_MAP () int CMainFrame::OnCreate (LPCREATESTRUCT lpcs) { if (CFrameWnd::OnCreate (lpcs) == -1) return -1; EnableDocking (CBRS_ALIGN_ANY); if (!CreateToolBar () || !CreateStyleBar () || !CreateStatusBar ()) return -1; LoadBarState ("BarSettings"); return 0; } void CMainFrame::OnClose () { SaveBarState ("BarSettings"); CFrameWnd::OnClose (); } BOOL CMainFrame::CreateToolBar () { if (!m_wndToolBar.Create (this) || !m_wndToolBar.LoadToolBar (IDR_TOOLBAR)) return FALSE; m_wndToolBar.SetBarStyle (m_wndToolBar.GetBarStyle () | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); m_wndToolBar.SetWindowText ("Main"); m_wndToolBar.EnableDocking (CBRS_ALIGN_ANY); DockControlBar (&m_wndToolBar); return TRUE; } BOOL CMainFrame::CreateStyleBar () { if (!m_wndStyleBar.Create (this, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, IDW_STYLE_BAR)) return FALSE; m_wndStyleBar.SetWindowText ("Styles"); m_wndStyleBar.EnableDocking (CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM); DockControlBar (&m_wndStyleBar); return TRUE; } BOOL CMainFrame::CreateStatusBar () { static UINT nIndicators[] = { ID_SEPARATOR, ID_INDICATOR_LINE, ID_INDICATOR_CAPS, ID_INDICATOR_NUM }; if (!m_wndStatusBar.Create (this)) return FALSE; m_wndStatusBar.SetIndicators (nIndicators, 4); return TRUE; }
//*********************************************************************** // // MyWordDoc.h // //*********************************************************************** class CWordDoc : public CRichEditDoc { DECLARE_DYNCREATE (CWordDoc) public: virtual BOOL OnNewDocument (); virtual CRichEditCntrItem* CreateClientItem (REOBJECT*) const; protected: DECLARE_MESSAGE_MAP () };
//*********************************************************************** // // MyWordDoc.cpp // //*********************************************************************** #include <afxwin.h> #include <afxcmn.h> #include <afxrich.h> #include "Resource.h" #include "MyWordDoc.h" IMPLEMENT_DYNCREATE (CWordDoc, CRichEditDoc) BEGIN_MESSAGE_MAP (CWordDoc, CRichEditDoc) ON_COMMAND (ID_FILE_SEND_MAIL, OnFileSendMail) ON_UPDATE_COMMAND_UI (ID_FILE_SEND_MAIL, OnUpdateFileSendMail) END_MESSAGE_MAP () BOOL CWordDoc::OnNewDocument () { if (!CRichEditDoc::OnNewDocument ()) return FALSE; CHARFORMAT cf; cf.cbSize = sizeof (CHARFORMAT); cf.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_PROTECTED | CFM_STRIKEOUT | CFM_FACE | CFM_SIZE; cf.dwEffects = 0; cf.yHeight = 240; // 240 twips == 12 points ::lstrcpy (cf.szFaceName, "Times New Roman"); GetView ()->SetCharFormat (cf); return TRUE; } CRichEditCntrItem* CWordDoc::CreateClientItem (REOBJECT* preo) const { return new CRichEditCntrItem (preo, (CWordDoc*) this); }
//*********************************************************************** // // MyWordView.cpp // //*********************************************************************** #include <afxwin.h> #include <afxcmn.h> #include <afxrich.h> #include "Resource.h" #include "StyleBar.h" #include "MainFrame.h" #include "MyWordView.h" IMPLEMENT_DYNCREATE (CWordView, CRichEditView) BEGIN_MESSAGE_MAP (CWordView, CRichEditView) ON_COMMAND (ID_CHAR_BOLD, OnCharBold) ON_COMMAND (ID_CHAR_ITALIC, OnCharItalic) ON_COMMAND (ID_CHAR_UNDERLINE, OnCharUnderline) ON_COMMAND (ID_PARA_LEFT, OnParaLeft) ON_COMMAND (ID_PARA_CENTER, OnParaCenter) ON_COMMAND (ID_PARA_RIGHT, OnParaRight) ON_UPDATE_COMMAND_UI (ID_CHAR_BOLD, OnUpdateCharBoldUI) ON_UPDATE_COMMAND_UI (ID_CHAR_ITALIC, OnUpdateCharItalicUI) ON_UPDATE_COMMAND_UI (ID_CHAR_UNDERLINE, OnUpdateCharUnderlineUI) ON_UPDATE_COMMAND_UI (ID_PARA_LEFT, OnUpdateParaLeftUI) ON_UPDATE_COMMAND_UI (ID_PARA_CENTER, OnUpdateParaCenterUI) ON_UPDATE_COMMAND_UI (ID_PARA_RIGHT, OnUpdateParaRightUI) ON_UPDATE_COMMAND_UI (ID_INDICATOR_LINE, OnUpdateLineNumber) END_MESSAGE_MAP () void CWordView::OnCharBold () { CHARFORMAT cf; cf = GetCharFormatSelection (); if (!(cf.dwMask & CFM_BOLD) || !(cf.dwEffects & CFE_BOLD)) cf.dwEffects = CFE_BOLD; else cf.dwEffects = 0; cf.dwMask = CFM_BOLD; SetCharFormat (cf); } void CWordView::OnCharItalic () { CHARFORMAT cf; cf = GetCharFormatSelection (); if (!(cf.dwMask & CFM_ITALIC) || !(cf.dwEffects & CFE_ITALIC)) cf.dwEffects = CFE_ITALIC; else cf.dwEffects = 0; cf.dwMask = CFM_ITALIC; SetCharFormat (cf); } void CWordView::OnCharUnderline () { CHARFORMAT cf; cf = GetCharFormatSelection (); if (!(cf.dwMask & CFM_UNDERLINE) || !(cf.dwEffects & CFE_UNDERLINE)) cf.dwEffects = CFE_UNDERLINE; else cf.dwEffects = 0; cf.dwMask = CFM_UNDERLINE; SetCharFormat (cf); } void CWordView::OnParaLeft () { OnParaAlign (PFA_LEFT); } void CWordView::OnParaCenter () { OnParaAlign (PFA_CENTER); } void CWordView::OnParaRight () { OnParaAlign (PFA_RIGHT); } void CWordView::OnUpdateCharBoldUI (CCmdUI* pCmdUI) { OnUpdateCharEffect (pCmdUI, CFM_BOLD, CFE_BOLD); } void CWordView::OnUpdateCharItalicUI (CCmdUI* pCmdUI) { OnUpdateCharEffect (pCmdUI, CFM_ITALIC, CFE_ITALIC); } void CWordView::OnUpdateCharUnderlineUI (CCmdUI* pCmdUI) { OnUpdateCharEffect (pCmdUI, CFM_UNDERLINE, CFE_UNDERLINE); } void CWordView::OnUpdateParaLeftUI (CCmdUI* pCmdUI) { OnUpdateParaAlign (pCmdUI, PFA_LEFT); } void CWordView::OnUpdateParaCenterUI (CCmdUI* pCmdUI) { OnUpdateParaAlign (pCmdUI, PFA_CENTER); } void CWordView::OnUpdateParaRightUI (CCmdUI* pCmdUI) { OnUpdateParaAlign (pCmdUI, PFA_RIGHT); } void CWordView::OnUpdateLineNumber (CCmdUI* pCmdUI) { int nLine = GetRichEditCtrl ().LineFromChar (-1) + 1; CString string; string.Format ("Line %d", nLine); pCmdUI->Enable (TRUE); pCmdUI->SetText (string); } void CWordView::ChangeFont (LPCSTR pszFaceName) { CHARFORMAT cf; cf.cbSize = sizeof (CHARFORMAT); cf.dwMask = CFM_FACE; ::lstrcpy (cf.szFaceName, pszFaceName); SetCharFormat (cf); } void CWordView::ChangeFontSize (int nSize) { CHARFORMAT cf; cf.cbSize = sizeof (CHARFORMAT); cf.dwMask = CFM_SIZE; cf.yHeight = nSize; SetCharFormat (cf); } void CWordView::GetFontInfo (LPSTR pszFaceName, int& nSize) { CHARFORMAT cf = GetCharFormatSelection (); ::lstrcpy (pszFaceName, cf.dwMask & CFM_FACE ? cf.szFaceName : ""); nSize = cf.dwMask & CFM_SIZE ? cf.yHeight : -1; }
//*********************************************************************** // // StyleBar.h // //*********************************************************************** class CStyleBar : public CToolBar { private: CFont m_font; CComboBox m_ctlNameComboBox; CComboBox m_ctlSizeComboBox; void FillNameComboBox (CDC*); public: virtual void OnUpdateCmdUI (CFrameWnd*, BOOL); static int CALLBACK EnumFontNameProc (ENUMLOGFONT*, NEWTEXTMETRIC*, int, LPARAM); protected: afx_msg int OnCreate (LPCREATESTRUCT); afx_msg void OnSelectFont (); afx_msg void OnSelectSize (); afx_msg void OnCloseUp (); DECLARE_MESSAGE_MAP () };
//*********************************************************************** // // StyleBar.cpp // //*********************************************************************** #include <afxwin.h> #include <afxext.h> #include <afxcmn.h> #include <afxrich.h> #include <stdlib.h> #include "Resource.h" #include "MyWordView.h" #include "StyleBar.h" BEGIN_MESSAGE_MAP (CStyleBar, CToolBar) ON_WM_CREATE () ON_CBN_SELENDOK (IDC_FONTNAMES, OnSelectFont) ON_CBN_SELENDOK (IDC_FONTSIZES, OnSelectSize) ON_CBN_CLOSEUP (IDC_FONTNAMES, OnCloseUp) ON_CBN_CLOSEUP (IDC_FONTSIZES, OnCloseUp) END_MESSAGE_MAP () int CStyleBar::OnCreate (LPCREATESTRUCT lpcs) { static int nFontSizes[] = { 8, 9, 10, 11, 12, 14, 16, 18, 20, 22, 24, 26, 28, 32, 36, 48, 72 }; if (CToolBar::OnCreate (lpcs) == -1) return -1; // Load the toolbar if (!LoadToolBar (IDR_STYLE_BAR)) return -1; // Create an 8-point MS Sans Serif font for the combo boxes CClientDC dc (this); int nHeight = -((dc.GetDeviceCaps (LOGPIXELSY) * 8) / 72); m_font.CreateFont (nHeight, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "MS Sans Serif"); CFont* pOldFont = dc.SelectObject (&m_font); TEXTMETRIC tm; dc.GetTextMetrics (&tm); int cxChar = tm.tmAveCharWidth; int cyChar = tm.tmHeight + tm.tmExternalLeading; dc.SelectObject (pOldFont); // Add the font name combo box to the toolbar SetButtonInfo (8, IDC_FONTNAMES, TBBS_SEPARATOR, cxChar * 32); CRect rect; GetItemRect (8, &rect); rect.bottom = rect.top + (cyChar * 16); if (!m_ctlNameComboBox.Create (WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST | CBS_SORT, rect, this, IDC_FONTNAMES)) return -1; m_ctlNameComboBox.SetFont (&m_font); FillNameComboBox (&dc); // Add the font size combo box to the toolbar SetButtonInfo (10, IDC_FONTSIZES, TBBS_SEPARATOR, cxChar * 12); GetItemRect (10, &rect); rect.bottom = rect.top + (cyChar * 14); if (!m_ctlSizeComboBox.Create (WS_CHILD | WS_VISIBLE | WS_VSCROLL | CBS_DROPDOWNLIST, rect, this, IDC_FONTSIZES)) return -1; m_ctlSizeComboBox.SetFont (&m_font); CString string; for (int i=0; i<17; i++) { string.Format ("%d", nFontSizes[i]); m_ctlSizeComboBox.AddString (string); } return 0; } void CStyleBar::OnSelectFont () { char szFaceName[LF_FACESIZE]; int nIndex = m_ctlNameComboBox.GetCurSel (); m_ctlNameComboBox.GetLBText (nIndex, szFaceName); CWordView* pView = (CWordView*) ((CFrameWnd*) AfxGetMainWnd ())->GetActiveView (); pView->ChangeFont (szFaceName); } void CStyleBar::OnSelectSize () { char szSize[8]; int nIndex = m_ctlSizeComboBox.GetCurSel (); m_ctlSizeComboBox.GetLBText (nIndex, szSize); int nSize = atoi (szSize) * 20; // Need twips CWordView* pView = (CWordView*) ((CFrameWnd*) AfxGetMainWnd ())->GetActiveView (); pView->ChangeFontSize (nSize); } void CStyleBar::OnCloseUp () { ((CFrameWnd*) AfxGetMainWnd ())->GetActiveView ()->SetFocus (); } void CStyleBar::FillNameComboBox (CDC* pDC) { ::EnumFontFamilies (pDC->m_hDC, NULL, (FONTENUMPROC) EnumFontNameProc, (LPARAM) this); } int CALLBACK CStyleBar::EnumFontNameProc (ENUMLOGFONT* lpelf, NEWTEXTMETRIC* lpntm, int nFontType, LPARAM lParam) { CStyleBar* pWnd = (CStyleBar*) lParam; if (nFontType & TRUETYPE_FONTTYPE) pWnd->m_ctlNameComboBox.AddString (lpelf->elfLogFont.lfFaceName); return 1; } void CStyleBar::OnUpdateCmdUI (CFrameWnd* pTarget, BOOL bDisableIfNoHndler) { CToolBar::OnUpdateCmdUI (pTarget, bDisableIfNoHndler); CWnd* pWnd = GetFocus (); if ((pWnd == &m_ctlNameComboBox) || (pWnd == &m_ctlSizeComboBox)) return; // Get the font name and size int nTwips; char szFaceName[LF_FACESIZE]; CWordView* pView = (CWordView*) ((CFrameWnd*) AfxGetMainWnd ())->GetActiveView (); pView->GetFontInfo (szFaceName, nTwips); // Update the font name combo box char szSelection[LF_FACESIZE]; m_ctlNameComboBox.GetWindowText (szSelection, sizeof (szSelection)); if (::lstrcmp (szFaceName, szSelection) != 0) { if (szFaceName[0] == 0) m_ctlNameComboBox.SetCurSel (-1); else { if (m_ctlNameComboBox.SelectString (-1, szFaceName) == CB_ERR) m_ctlNameComboBox.SetCurSel (-1); } } // Update the font size combo box char szSize[4]; m_ctlSizeComboBox.GetWindowText (szSize, sizeof (szSize)); int nSizeFromComboBox = atoi (szSize); int nSizeFromView = nTwips / 20; if (nSizeFromComboBox != nSizeFromView) { if (nTwips == -1) m_ctlSizeComboBox.SetCurSel (-1); else { CString string; string.Format ("%d", nSizeFromView); if (m_ctlSizeComboBox.SelectString (-1, string) == CB_ERR) m_ctlSizeComboBox.SetCurSel (-1); } } }