Discussion: Painting Text

What happens inside your OnPaint member function? This discussion explains the statements in the OnPaint member function and the requirements for naming the function and for making its message map entry.

The OnPaint Name

OnPaint, as a message-handler function, is predefined in the Microsoft Foundation class CWnd, where its prototype is given. OnPaint is designed to handle the WM_PAINT message, and WM_PAINT is one of the messages requiring a specific parameter signature. The OnPaint function happens to take no arguments and to return no value. Thus, its declaration in class CMainWindow looks like this:

afx_msg void OnPaint();

Its corresponding macro entry, ON_WM_PAINT, is also predefined.

Inside OnPaint

The code in Hello's OnPaint member function has three fundamental components. To paint the text, you do these three things:

1.Create a device context.

OnPaint constructs a CPaintDC object. The class name stands for class “Paint Device Context.”

2.Determine the area in which to paint.

OnPaint uses the window object's GetClientRect member function to get a rectangle corresponding to the client area of the window. CMainWindow inherits GetClientRect.

3.Paint the text.

OnPaint uses three CPaintDC member functions to align and paint the text.

In the Windows graphical user interface, it is common to speak of anything you display in a window, even text, as being “drawn” or “painted.” In Hello, the text “Hello, Windows!” is painted in the window, through the use of graphics functions.

Your program is responsible for painting its window contents when requested by Windows. Typically, a window is painted when the program starts, when the window is first displayed, and when the window changes size or is uncovered after being covered by another window, when new drawing takes place. Windows sends WM_PAINT when anything happens that requires updating the window.

The OnPaint member function handles the WM_PAINT message.

When the contents of your window's client area change or when the client area must be redrawn (“updated”), Windows sends a WM_PAINT message to the window. What your OnPaint message-handler function does in response to that message depends on your needs. No matter what your program displays in its windows, the OnPaint handler is the place to do the drawing.

What OnPaint Does

Except for its use of a “device context object,” the code for OnPaint is straightforward Windows programming. The syntax looks cleaner, but the calls made should be familiar to Windows programmers. Figure 3.5 shows the sequence of steps in Hello's OnPaint member function.

The OnPaint member function of class CMainWindow uses three local variables:

A CString object to contain the text to paint.

A device context object of class CPaintDC.

A CRect object.

The device context object, dc, is the Microsoft Foundation Class Library way to set up a Windows device context for painting on the screen. When the CPaintDC object is constructed on the stack frame, it gets a pointer to the window object that owns it, passed with the C++ this keyword. The CPaintDC object needs this information to associate the device context with the window. During its initialization, the CPaintDC object calls the Windows BeginPaint function. When the CPaintDC object is destroyed as OnPaint exits, its destructor calls the Windows EndPaint function.

OnPaint calls the main window object's GetClientRect member function, inherited from CWnd through CFrameWnd. This function returns the coordinates of the window's client area in the rect argument.

Armed with the client area information, OnPaint then calls two member functions of the device context object to align and paint the text. The call to the device context's SetTextAlign member function (of class CPaintDC) specifies that the coordinates given are to be considered the center of the text. Because Hello's OnPaint member function gives the center of the window, the text is centered in the window.

The call to the device context's SetBkMode, with an argument of TRANSPARENT, specifies that the window background remains as it is rather than being filled with the current background color before painting. If you compile and run the Hello program, you can see that if the window changes size, the text is redrawn so it is always centered.

The call to the device context's TextOut member function paints the text in the window. To center the starting point of the text in the client area, the code divides the right-side and bottom coordinates by 2, defining a point at the horizontal and vertical center of the client area. The arguments passed previously to SetTextAlign cause the output to use this point as the baseline for drawing, and the text is also centered horizontally on the point.

All CWnd and CPaintDC member functions called in OnPaint closely parallel functions of the same name in the Windows API. You could, of course, simply use the Windows calls in your OnPaint member function, but using the Microsoft Foundation Classes adds simplicity and flexibility.

The primary functionality of Hello is now in place. But Hello will have more of the Windows look if you add an About box. The next section shows how.