?? formatbar.shtml
字號:
void CFormatBar::OnSelectFontName()
{
TCHAR szFontName[LF_FACESIZE];
int nIndex = m_cmbFontName.GetCurSel();
m_cmbFontName.GetLBText( nIndex, szFontName );
// If font name is empty - return
if( szFontName[0] == 0 )
return;
CHARNMHDR fh;
CHARFORMAT& cf = fh.cf;
fh.hwndFrom = m_hWnd;
fh.idFrom = GetDlgCtrlID();
fh.code = FN_SETFORMAT;
cf.dwMask = CFM_FACE;
_tcsncpy(cf.szFaceName, szFontName, LF_FACESIZE); //strncpy
GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh);
}
void CFormatBar::OnSelectFontSize()
{
TCHAR szSize[5];
int index = m_cmbFontSize.GetCurSel();
if( index != CB_ERR )
m_cmbFontSize.GetLBText(index, szSize );
else
m_cmbFontSize.GetWindowText( szSize, 5 );
// Get size in Twips
int nSize = _ttoi( szSize ) * 20; // atoi for tchar
if( !nSize )
return;
CHARNMHDR fh;
CHARFORMAT& cf = fh.cf;
fh.hwndFrom = m_hWnd;
fh.idFrom = GetDlgCtrlID();
fh.code = FN_SETFORMAT;
cf.dwMask = CFM_SIZE;
cf.yHeight = nSize;
GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh);
}
void CFormatBar::OnUpdateCmdUI(CFrameWnd* pTarget, BOOL bDisableIfNoHndler)
{
// Take care of the regular toolbar buttons
CToolBar::OnUpdateCmdUI( pTarget, bDisableIfNoHndler);
// Don't update the combo boxes if user changing font attribute
CWnd *pWnd = GetFocus();
if( pWnd == &m_cmbFontName || m_cmbFontSize.IsChild(pWnd) )
return;
// get the current font from the view and update
CHARNMHDR fh;
CHARFORMAT& cf = fh.cf;
fh.hwndFrom = m_hWnd;
fh.idFrom = GetDlgCtrlID();
fh.code = FN_GETFORMAT;
CWnd *pOwnerWnd = GetOwner();
if( !GetOwner()->SendMessage(WM_NOTIFY, fh.idFrom, (LPARAM)&fh) )
{
TRACE0("The Rich Edit View/Control has to handle the FN_GETFORMAT\n"
"notification for the Format Bar to work properly\n");
return;
}
// Update the font only if the selection font is different
TCHAR szName[LF_FACESIZE];
m_cmbFontName.GetWindowText( szName, LF_FACESIZE );
// the selection must be same font and charset to display correctly
if ((cf.dwMask & (CFM_FACE|CFM_CHARSET)) != (CFM_FACE|CFM_CHARSET))
m_cmbFontName.SetCurSel( -1 );
else if( ::_tcscmp( szName, cf.szFaceName ) != 0 )
{
if( m_cmbFontName.SelectString( -1, cf.szFaceName ) == CB_ERR )
m_cmbFontName.SetCurSel( -1 );
}
// Update the font size
TCHAR szSize[5];
m_cmbFontSize.GetWindowText( szSize, 5 );
int nSize = _ttoi( szSize ); // atoi for tchar
// Update the font size only if selection is different
int nSelSize = (cf.dwMask & CFM_SIZE) ? cf.yHeight/20 : 0;
if( nSize != nSelSize )
{
if(cf.dwMask & CFM_SIZE)
{
CString strSize;
strSize.Format("%d", nSelSize );
m_cmbFontSize.SetWindowText( strSize );
}
else
m_cmbFontSize.SetCurSel(-1);
}
}
BOOL CFormatBar::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN)
{
NMHDR nm;
nm.hwndFrom = m_hWnd;
nm.idFrom = GetDlgCtrlID();
nm.code = NM_RETURN;
switch (pMsg->wParam)
{
case VK_RETURN:
// Send change notification
if( m_cmbFontName.IsChild(GetFocus()) )
OnSelectFontName();
else if( m_cmbFontSize.IsChild(GetFocus()) )
OnSelectFontSize();
//Fall through
case VK_ESCAPE:
GetOwner()->SendMessage(WM_NOTIFY, nm.idFrom, (LPARAM)&nm);
return TRUE;
}
}
return CToolBar::PreTranslateMessage(pMsg);
}
</FONT></TT></PRE>
<P>At the top of the file, the nFontSizes array is declared. This array is initialized to the commonly used font sizes and is used to initialize the font size combobox. To make the design simple, the CFormatBar class has beed designed so that the user is always provided with this list of sizes even though the font may not support all of these sizes. The user can also type in an arbitrary value for the font size.
<P>The OnCreate() function calls the base class version of the function so that the toolbar gets created. It then loads the toolbar from the resource and creates the two comboboxes - for font name and font size. To make place for the comboboxes, the place holder buttons are resized using the SetButtonInfo() function. We use the font that will be used in the combobox to determine a reasonable width for the control. Since a font name can have at most LF_FACESIZE characters, we use this number and the average width of a character to determine the width of the font name combobox. LF_FACESIZE by the way is a constant defined as 32. Similarly we make the font size combobox wide enough to accommodate 4 characters.
<P>The font name combobox is created with the CBS_DROPDOWNLIST style. This style forces the user to select one of the listed styles. You may want to change this style to CBS_DROPDOWN so that the user may specify a font that may not be available on the machine. The font size combobox uses the CBS_DROPDOWN style to allow the user to type in any point size or select from the list.
<P>At the end, the OnCreate() function populates the font size combobox by calling the EnumFontFamilies() function, which in turn calls the EnumFontFamProc() for each font on the system (the screen device context). It is EnumFontFamProc() that actually adds the font names to the combobox. OnCreate() also populates the font size combobox from the array of common font sizes.
<P>The OnSelectFontName() is called when the user selects a list item in the font name combobox. Notice the entry ON_CBN_SELENDOK(IDC_FONTNAME, OnSelectFontName) in the message map hooking up this function. This function is also called when the user hits the enter key. The purpose of this function is to send out a notification so that the rich edit control can be updated. It uses an extended notification header so that it can also pass on the character format information. Note that it uses a custom notification code. It is the responsibility of the rich edit control class to handle this notification and change the format accordingly. Similarly, the OnSelectFontSize() handles the font size combobox.
<P>The OnUpdateCmdUI() function is called by the framework to update the status of the toolbar. We override this function because the Format Bar has the two comboboxes. The toolbar buttons get updated by the regular ON_UPDATE_COMMAND_UI() message map macros but the combobox needs special handling. This function basically gets the font information about the current selection from the rich edit control and updates the font comboboxes. This of course doesn't make sense if the user is trying to change the font. The function, therefore returns immediately if either of the comboboxes have the input focus. Here again a custom notification is sent out. The FN_GETFORMAT should be handled by the rich edit control and the control should return the format information through the notification header structure.
<P>Overriding the PreTranslateMessage() is how we tackle the situation when the user presses the enter or the escape key. When the user presses the enter key, it calls the OnSelectFontName() or the OnSelectFontSize() function, whichever is appropriate. The function then sends the NM_RETURN notification. This is another notification that the rich edit control has to look out for. On receiving this message, the rich edit control should take back the input focus.
<H4>Step 3: Create the Format toolbar</H4>
To create the format toolbar, first add a CFormatBar member variable in the CMainFrame class. Actually any frame class that will contain the CRichEditView or CRichEditCtrl will do.
<PRE><TT><FONT COLOR="#990000">protected: // control bar embedded members
CFormatBar m_wndFormatBar;
</FONT></TT></PRE>
<P>Create the format toolbar in the OnCreate() function. Here's sample code that does that.
<PRE><TT><FONT COLOR="#990000">int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndFormatBar.Create(this, WS_CHILD | WS_VISIBLE |
CBRS_TOP |CBRS_TOOLTIPS|CBRS_FLYBY,
IDR_FORMATBAR) )
{
TRACE0("Failed to create FormatBar\n");
return -1; // fail to create
}
m_wndFormatBar.SetWindowText( _T("Format") );
m_wndFormatBar.EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar( &m_wndFormatBar );
:
:
:
return 0;
}
</FONT></TT></PRE>
<H4>Step 4: Add handlers for format toolbar notifications</H4>
As we have already covered, the CFormatBar sends a couple of custom notification as well as the NM_RETURN notification. These notifications inform the rich edit control about activities on the toolbar. The Class Wizard won't be able to help you add these handlers, so you would have to add the entries to the message map yourself.
<PRE><TT><FONT COLOR="#990000">BEGIN_MESSAGE_MAP(CMyRichEditView, CRichEditView)
//{{AFX_MSG_MAP(CMyRichEditView)
:
:
//}}AFX_MSG_MAP
ON_NOTIFY(FN_GETFORMAT, IDR_FORMATBAR, OnGetCharFormat)
ON_NOTIFY(FN_SETFORMAT, IDR_FORMATBAR, OnSetCharFormat)
ON_NOTIFY(NM_RETURN, IDR_FORMATBAR, OnBarReturn)
END_MESSAGE_MAP()
</FONT></TT></PRE>
<P>The implementation of the handler functions are quite simple. The OnGetCharFormat() function simply gets the format of the current selection and returns this through the notification header. The OnSetCharFormat() receives the format information through the notification header and applies it to the current selection. The OnBarReturn() simply sets focus to the rich edit control.
<PRE><TT><FONT COLOR="#990000">void CMyRichEditView::OnGetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
{
((CHARNMHDR*)pNMHDR)->cf = GetCharFormatSelection();
*pRes = 1;
}
void CMyRichEditView::OnSetCharFormat(NMHDR* pNMHDR, LRESULT* pRes)
{
SetCharFormat(((CHARNMHDR*)pNMHDR)->cf);
*pRes = 1;
}
void CMyRichEditView::OnBarReturn(NMHDR*, LRESULT* )
{
SetFocus();
}
</FONT></TT></PRE>
<H4>Step 5: Add UPDATE_COMMAND_UI & COMMAND handlers</H4>
The CRichEditView class already provides support for all but one of the remaining format toolbar buttons. So all we need to do is hook up the message map entries so that the proper functions get called. The only function that we have to write is for the color button. The message map entries and the OnColorPick() function is shown below. We do not have to write the other functions since they are already defined in CRichEditView.
<PRE><TT><FONT COLOR="#990000">BEGIN_MESSAGE_MAP(CMyRichEditView, CRichEditView)
//{{AFX_MSG_MAP(CMyRichEditView)
:
:
ON_COMMAND(ID_CHAR_COLOR, OnColorPick)
ON_COMMAND(ID_CHAR_BOLD, OnCharBold)
ON_UPDATE_COMMAND_UI(ID_CHAR_BOLD, OnUpdateCharBold)
ON_COMMAND(ID_CHAR_ITALIC, OnCharItalic)
ON_UPDATE_COMMAND_UI(ID_CHAR_ITALIC, OnUpdateCharItalic)
ON_COMMAND(ID_CHAR_UNDERLINE, OnCharUnderline)
ON_UPDATE_COMMAND_UI(ID_CHAR_UNDERLINE, OnUpdateCharUnderline)
ON_COMMAND(ID_PARA_CENTER, OnParaCenter)
ON_UPDATE_COMMAND_UI(ID_PARA_CENTER, OnUpdateParaCenter)
ON_COMMAND(ID_PARA_LEFT, OnParaLeft)
ON_UPDATE_COMMAND_UI(ID_PARA_LEFT, OnUpdateParaLeft)
ON_COMMAND(ID_PARA_RIGHT, OnParaRight)
ON_UPDATE_COMMAND_UI(ID_PARA_RIGHT, OnUpdateParaRight)
ON_COMMAND(ID_INSERT_BULLET, OnBullet)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CMyRichEditView::OnColorPick()
{
CColorDialog dlg;
if( dlg.DoModal() == IDOK ){
CRichEditView::OnColorPick(dlg.GetColor());
}
}
</FONT></TT></PRE>
<P>
<HR>
<TABLE BORDER=0 WIDTH="100%" >
<TR>
<TD WIDTH="33%"><FONT SIZE=-1><A HREF="http://www.codeguru.com">Goto HomePage</A></FONT></TD>
<TD WIDTH="33%">
<CENTER><FONT SIZE=-2>© 1998 Zafir Anjum</FONT> </CENTER>
</TD>
<TD WIDTH="34%">
<DIV ALIGN=right><FONT SIZE=-1>Contact me: <A HREF="mailto:zafir@home.com">zafir@home.com</A> </FONT></DIV>
</TD>
</TR>
</TABLE>
</BODY>
</HTML>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -