Topic : Using Fonts in MFC
Author : Unknown
Page : << Previous 3  Next >>
Go to page :

CStatic as the base class is that by doing this, we can easily use subclass method to change a static control contained in dialog box to a percentage bar. Of course, we can choose other type of controls such as CButton to change a button to a percentage bar.

Two variables m_nRange and m_nCurPos along with two functions are added to class CPercent. Also, WM_PAINT message handler is added to the class through using Class Wizard, and the corresponding member funtion is OnPaint(). The following is this new class:

(Code omitted)

Variable m_nRange indicates the range of the percentage bar, and m_nCurPos indicates the current position. They are initialized in the constructor:





Funtions CPercent::SetPercentage(...) and CPercent::SetPosition(...) allow us to change the value of m_nCurPos, and CPercent::SetRange(...) allows us to change the total range.

Within function CPercent::OnPaint(), we will draw the percentage bar using the values of m_nRange and m_nCurPos.

We need to check if m_nRange is zero. If so, we can not draw the percentage bar. If not, we need to first find out the size of the window (the static control window) within which the percentage bar will be drawn. This information is stored in a local variable rect. Next, we create the text string and store it in another local variable szStr, whose format is "XXX%" (XXX represents a number between 0 and 100). To place the text in the center of the rectangle, we need to know its dimension.

To retrieve the dimension of a text string, we need to call function CDC::GetTextExtent(...) and pass the actual string to it. The function will return a CSize type value that specifies the dimension of this text.

The percentage bar is divided into two portions. On the left side of the rectangle, the text color is white and the background color is blue. The following portion of function CPercent::OnPaint() shows how to create text string, set foreground and background colors, and retrieve the dimension of the text:

(Code omitted)

Next, the dimension of the left side rectange of the percentage bar is stored in local variable rectHalf. Then function CDC::ExtTextOut(...) is called to draw the left part of the percentage bar (Mode ETO_CLIPPED is used here, it will restrict the drawing within the rectangle). Because ETO_OPAQUE flag is also used, the text will be drawn with white color and the rest part of rectangle (specified by rectHalf) will all be painted blue:

(Code omitted)

Then we swap the text and background colors, store the right side rectangle in variable rectHalf, and call CDC::ExtTextOut(...) again to draw the rest part of the percentage bar:

(Code omitted)

The last two statements resume the original text color and background color for the device context.

Implementing Percentage Bar

It is very simple to use class CPercent to implement subclass for a static control contained in a dialog box. In the sample, a dialog template IDD_DIALOG is added to the application, it contains an "OK" button and a picture control whose ID is IDC_STATIC_PROG. The control has a modal frame whose color is set to "Gray", this will let the percentage bar have a 3-D effect. The above two styles can be set in the "Picture Properties" property sheet (See Figure 9-3 and Figure 9-4).

Class CProgDlg is added to the application for template IDD_DIALOG. In the class, a CPercent type variable m_perBar along with an integer type variable m_nPercent are declared:

class CProgDlg : public CDialog



CPercent m_perBar;

int m_nPercent;



Variable m_perBar will be used to implement percentange bar, and m_nPercent will be used to record the current position of the percentage bar.

Variable m_nPercent is initialized in the constructor:

(Code omitted)

In the sample, WM_INITDIALOG message handler is added to the application through using Class Wizard, and funtion CProgDlg::OnInitDialog() is implemented as follows:

(Code omitted)

Control IDC_STATIC_PROG is changed to a progress bar through implementing subclass, then a timer is started to generate events that will be handled to advance the percentage bar.

To handle time out events, in the sample, a WM_TIMER message handler is added throgh using Class Wizard. The corresponding member function CProgDlg::OnTimer(...) is implemented as follows:

(Code omitted)

If timer times out, we advance the percentage bar one step forward (1%); if the percentage bar reaches 100%, we reset it to 0%.

We must destroy timer when the application exits. The best place of doing this is when we receive WM_DESTROY message. This message handler can also be added through using Class Wizard. In the sample, the corresponding member function is implemented as follows:

void CProgDlg::OnDestroy()




For the purpose of testing the percentage bar, a new command Dialog | Progress is added to the application, whose command ID is ID_DIALOG_PROGRESS. A WM_COMMAND message handler is added to class CGDIDoc for this command, and the corresponding member function CGDIDoc::OnDialogProgress() is implemneted as follows:

void CGDIDoc::OnDialogProgress()

CProgDlg dlg;



After all these implementations, we can execute command Dialog | Progress to test the percentage bar.

4 One-Line Text Editor, Step 1: Displaying a Static String

From now on we are going to implement a very simple one-line text editor: it will display only one line text that can be edited through using mouse and keyboard. We will implement many features of a standard editor such as font selection, changing text styles. The sample application in this section does not introduce any new concept, it is the base of later sections.

Sample 4\GDI is a standard SDI application generated by Application Wizard. Because the horizontal size of the text string may be bigger than that of the client window as the user input more and more characters, we need to add scroll bars to the application. In order to do this, we can choose CScrollView as the base class of the client window in the final step of Application Wizard.

The sample does nothing but displaying a static text in the client window. Other features of text editor will be implemented in later sections.

Two variables m_szText and m_ftDraw along with two member functions are declared in class CGDIDoc:

(Code omitted)

Variable m_szText will be used to store the text string, and m_ftDraw will be used to store the font used for text drawing. Functions CGDIDoc::GetText() and CGDIDoc::GetFont() provide a way of accessing the two member variables outside class CGDIDoc.

Because we still do not have an interactive input environment, in the constructor, variable m_szText is initialized to a fixed string:


m_szText="This is just a test string";


In the sample, function CGDIDoc::OnNewDocument() is modified as follows:

(Code omitted)

This function will be called when the document is initialized. Within the function, variable m_ftDraw is used to create a default font. Since the document is always created before the view, creating the font in this function will guarantee that m_ftDraw will be a valid font when the view is created. This procedure can also be done in the constructor.

To let the user select different types of fonts, a new command Dialog | Font is added to application's mainframe menu IDR_MAINFRAME. The resource ID of this command is ID_DIALOG_FONT and the corresponding message handler is CGDIDoc::OnDialogFont(), which is implemented as follows:

(Code omitted)

After a new font is selected by the user, we delete the old font and create a new one, then call function CDocument::UpdateAllViews(...) to update the client window.

On the view side, we need to modify function CGDIView::OnDraw(...). In this function, the text string and the font are retrieved from the document, and are used to draw text in the client window:

(Code omitted)

With the above implementation, the application will display a static string. Although we still can not input any character, the font for drawing the text can be changed through executing Dialog | Font command.

5 One Line Text Editor, Step 2: Adding Caret

Caret Functions

Caret is a very important feature for text editor, it indicates the current editing position. This makes the interface more user friendly. Because there are many types of fonts in the system, and for each font, the width of different characters may vary, we need to make careful calculation before moving the caret to the next position.

Every class derived from the CWnd supports caret, the steps of implementing caret are as follows: 1) Create a caret with specific style. 2) Show the caret. 3) Destroy the caret before the window is destroyed.

The following three member functions can be used to create a caret:

void CWnd::CreateSolidCaret(int nWidth, int nHeight);

void CWnd::CreateGrayCaret(int nWidth, int nHeight);

void CWnd::CreateCaret(CBitmap *pBitmap);

The first member function allows us to create a solid caret, here parameters nWidth and nHeight specify the dimension of the caret. Similarly, the second function can be used to create a gray caret. The last function can create a caret from a bitmap so that the caret can have a custom pattern.

After the caret is created, we can call function CWnd::ShowCaret() to display the caret or call function CWnd::HideCaret() to hide the caret.

The difficult thing on managing caret is to set its position. Because every character may have a different width, when the user presses arrow keys, we can not advance the caret with fixed distance each time. We must move the caret forward or backward according to the width of the character located before (or after) the caret. In order to

Page : << Previous 3  Next >>