Topic : MFC - Views
Author : Unknown
Page : << Previous 2  Next >>
Go to page :

is the default feature of class CRichEditView. The command ID that can be used to format the selected text using a specific font is ID_FORMAT_FONT (class CRichEditView supports this ID). So all we need to do is adding a Format | Font... command to menu IDR_MAINFRAME. With this simple implementation, we are able to format the text with any font that is available in the system.

Although it is very easy to build a fully functional application with a lot of enticing features, it is relatively difficult to make modifications. For example, the standard Wordpad application under Windows( has a ruler and a format bar, if we want to add these features, we need to add them by ourselves.

Customizing File Open Dialog Box

Class CRichEditView and CRichEditDoc can handle not only rich text format, but also plain text format (or ASCII format). By default, the two classes interpret input data using rich text format, if the format is different, the file will not be loaded. To let the application also support plain text format, we need to include multiple document types in "File Open" and "Save As" file dialog boxes, this gives the user an option for specifying file type. Although we can register more than one type of document to implement this, in the case of rich edit view, it is not an efficient way. This is because both formats are already supported by class CRichEditDoc.

To implement customized "File Open" dialog box, we can override function CWinApp::OnFileOpen(...). We need to provide "File Open" dialog box, let the user pick up a file name, and pass this name to function CWinApp::OpenDocumentFile(...). Here we need to pay special attention to file formats. Because we support more than one file format here, we need to implement a "File Open" dialog box supporting multiple file filters, and inform document the file format that was selected by the user. To customize a file open dialog box, we need the knowledge of Chapter 6; to let the document support a different file format, we can set a Boolean type member variable of class CRichEditDoc: CRichEditDoc::m_bRTF, which is a public member variable. If this variable is set to TRUE, the data in the file will be treated as formatted data stream; if it is set to FALSE, the data will be treated as unformatted data stream (plain ASCII text). We need to set this flag before function CWinApp::OpenDocumentFile(...) is called.

The following code fragment shows how function CWordPadApp::OnFileOpen() is implemented in the sample:

(Code omitted)

We must map command ID_FILE_OPEN to this function in order to make it effective. In the sample, WM_COMMAND message mapping for this command is customized as follows:

Original mapping:


New mapping:


Customizing "Save As" Dialog Box

Besides file open, we also need to think about file saving. This is more complex than file open, because we need to allow the user to save the file being edited with a different format. In case the user changes data format, we must also change the original file extension (from "rtf" to "txt" or vice versa).

To customize file saving to support multiple file formats, we need to override function CDocument:: DoSave(...). This is an undocumented member function of MFC. Unfortunately, because file dialog box is implemented within this function, we have no other choice to support multiple file format without modifying it. Although using undocumented functions is not recommendable, sometimes we have to do so in order to make our applications perfect.

Function CDocument::DoSave(...) has two parameters:

BOOL CDocument::DoSave(LPCTSTR lpszPathName, BOOL bReplace);

The first parameter is a pointer to the buffers containing the file name, the second is a Boolean type variable indicating if the file name should be changed. Actually, this parameter is always set to TRUE so we can neglect its value.

Pointer lpszPathName gives us the file name that should be used for saving data. But this pointer can also be NULL. If the file being edited is created through File | New command and the user has selected File | Save or File | Save As command, lpszPathName will be NULL. The following table lists the values of lpszPathName and bReplace under different situations:

(Table omitted)

Based on the above analysis, we can override function CDocument::DoSave(...) as follows: obtaining the file name from lpszPathName, if it is NULL, we implement the "Save As" dialog box with multiple file filters. After the user has selected a file name, we need to add extension to it according to the filter selected by the user. Also, we need to set data format for file saving. Then we can call function CDocument:: OnSaveDocument(...) and pass the file name to it to implement file saving.

In the derived function CWordPadDoc::DoSave(...), we need to implement the customized "Save As" dialog box and also, add file extension, change file format if necessary. The following is a portion of this function:

(Code omitted)

We can compare CWordPadDoc::DoSave(...) with the default MFC function CDocument::DoSave(...).

Formatting Text

Another feature we want to let this editor have is text formatting. For example, we may let the user format the selected text using bolded, italic or underlined style. Or we may let the user change the alignment of the selected paragraph (make the whole paragraph aligned left, centered or aligned right). The two types of formatting are called Character Formatting and Paragraph Formatting respectively, they can be implemented through calling functions CRichEditView::SetParaFormat(...) and CRichEditView:: SetCharFormat(...). The following shows the formats of the two functions:

void CRichEditView::SetParaFormat(PARAFORMAT &pf);

void CRichEditView::SetCharFormat(CHARFORMAT cf);

Because there are many properties we can set, we need to use structures PARAFORMAT and CHARFORMAT to specify which properties will be customized. The following is the format of structure PARAFORMAT:

typedef struct _paraformat {

UINT cbSize;

_WPAD _wPad1;

DWORD dwMask;

WORD wNumbering;

WORD wReserved;

LONG dxStartIndent;

LONG dxRightIndent;

LONG dxOffset;

WORD wAlignment;

SHORT cTabCount;



We need to set the corresponding bits of member dwMask in order use other members of this structure. For example, if we want to set paragraph alignment, we need to assign member wAllignment an appropriate value, and set PFM_ALIGNMENT bit of member dwMask. If this bit is not set, member wAlignment will have no effect when function CRichEditView::SetParaFormat(...) is called.

There are a lot of features we can set through using this function, which include text numbering (using bullets at the beginning of each line), paragraph start indent, right indent, second line offset, paragraph alignment and tabs.

The usage of function CRichEditView::SetCharFormat(...) is similar. Here we have another structure CHARFORMAT that could be used to set appropriate properties for the selected text:

typedef struct _charformat {

UINT cbSize;

_WPAD _wPad1;

DWORD dwMask;

DWORD dwEffects;

LONG yHeight;

LONG yOffset;

COLORREF crTextColor;

BYTE bCharSet;

BYTE bPitchAndFamily;


_WPAD _wPad2;


Again, member dwMask should be used to specify which properties will be customized. We can make change to character effects (make it bolded, italic, strikeout, underlined, or change its color), modify the size of characters, customize character's offset from the base line (this is useful for implementing superscript or subsript), or select a different type of font.

Counterpart functions of CRichEditView::SetParaFormat(...) and CRichEditView:: SetCharFormat(...) are CRichEditView::GetParaFormat(...) and CRichEditView:: GetCharFormat(...) respectively. They allow us to retrieve the properties of the current paragraph or the selected text (If no text is selected, the properties indicate the text at the current caret position). Similarly, we need to specify corresponding bits of member dwMask in order to retrieve certain properties: those members who have corresponding zero bits in member dwMask will not be stuffed with the paragraph or character information.

It seems that by using the above four functions, we can build a very useful editor that supports rich edit text format. However, in class CRichEditView, there exist more powerful functions that can be used to format the selected text or paragraph. These functions are also undocumented, but using them can save us much effort:

Functions used for paragraph formatting:




Functions used for character formatting:




Functions used to handle UPDATE_COMMAND_UI messages:







Instead of implementing our own message handlers, we can just add commands to the mainframe menu or tool bar, then map the commands to these functions. In the sample, we add six buttons for character and paragraphing formatting (Figure 14-1), and map the command messages to the above functions as follows:

(Code omitted)

With the above implementation, the editor can let the user set the character and paragraph properties.

3 Simple Explorer, Step 1: Preparation

Starting from this section we are going to create an Explorer-like application using classes CTreeView and CListView. The application is based on an SDI application whose client window is implemented by a 2-pane splitter window. We will use CTreeView to create the left pane, and use CListView to create the right pane. One the left pane, the file system (directories) will be displayed in a tree form, the user can click on any node to select a directory, or double click on it to expand the node (show all the sub-directories). On the right pane, all files and sub-directories contained in the currently selected directory will be listed, they can be displayed in one of the four styles supported by list view.

We have introduced how to create splitter window in Chapter 3. Obviously here we need to create static splitter windows. Application

Page : << Previous 2  Next >>