[ 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);
}
}
}