Upcoming Events
Unite 2010
11/10 - 11/12 @ Montréal, Canada

GDC China
12/5 - 12/7 @ Shanghai, China

Asia Game Show 2010
12/24 - 12/27  

GDC 2011
2/28 - 3/4 @ San Francisco, CA

More events...
Quick Stats
97 people currently visiting GDNet.
2406 articles in the reference section.

Help us fight cancer!
Join SETI Team GDNet!
Link to us Events 4 Gamers
Intel sponsors gamedev.net search:

Contents
 Device Contexts
 Tracking
 Paint Message
 Closing Your
 Application

 Plotting Pixels
 GDI Text Functions
 Displaying Bitmaps
 One Last Thing

 Demo program
 Printable version
 Discuss this article
 in the forums



The Series
 Beginning Windows
 Programming

 Using Resources
 in Win32 Programs

 Tracking Your
 Window/Using GDI

 Introduction
 to DirectX

 Palettes and Pixels
 in DirectDraw

 Bitmapped Graphics
 in DirectDraw

 Developing the
 Game Structure

 Basic Tile Engines
 Adding Characters
 Tips and Tricks

GDI Text Functions

There are two functions for actually plotting text that you need to be concerned with. The simpler of the two is TextOut(), as shown here:

BOOL TextOut( HDC hdc, // handle to device context int nXStart, // x-coordinate of starting position int nYStart, // y-coordinate of starting position LPCTSTR lpString, // pointer to string int cbString // number of characters in string );

By now we've seen enough BOOL-returning functions to know what that means: TRUE for success, FALSE for failure. The parameters are:

HDC hdc: The device context to use.

int nXStart, nYStart: These are the coordinates of the starting point for the text, called the reference point. By default, this is the upper-left corner of the rectangular area occupied by the string. You can change this setting, as we'll see in just a bit.

LPCTSTR lpString: The text to print out. Since the number of characters is given in the final parameter, this string does not need to be null-terminated.

int cbString: This is the length of the string, in characters.

TextOut() uses the current settings for text color, background color, and background type. Before looking at the other, more complicated text-rendering function, let's take a look at the functions you can use to control the colors being used.

COLORREF SetTextColor( HDC hdc, // handle to device context COLORREF crColor // text color ); COLORREF SetBkColor( HDC hdc, // handle of device context COLORREF crColor // background color value );

SetTextColor() sets the active text color, and SetBkColor() sets the active background color. The parameters are obviously the device context to apply the settings to, and the colors to use. Since these are COLORREFs, remember that you can use the RGB() macro for specifying your colors. Each function returns the previous value of the attribute it deals with. For instance, if you call SetTextColor(hdc, RGB(255, 0, 0)), the return value will be the active color that was being used before you turned it red. Finally, to set the background type, use SetBkType() as shown:

int SetBkMode( HDC hdc, // handle of device context int iBkMode // flag specifying background mode );

The device context parameter we've seen before, but the other, iBkMode, can take one of two values: TRANSPARENT or OPAQUE. If set to TRANSPARENT, any text you plot will not disturb the background around the text itself. If set to OPAQUE, plotting text will cause the rectangular region surrounding that text to be filled with the active background color. The return value of SetBkMode() is simply the previous background mode.

One more thing about TextOut(). I said you could change the way the reference point is interpreted, and the way to do it is by using SetTextAlign(), whose prototype is shown below.

UINT SetTextAlign( HDC hdc, // handle to device context UINT fMode // text-alignment flag );

The parameters are:

HDC hdc: The device context again. No surprises here.

UINT fMode: A flag or set of flags (logically combined with |) that determine the meaning of the reference point in a call to TextOut(). Only one flag can be selected from those affecting horizontal and vertical alignment, and only one of the two flags affecting use of the current position can be used. The flags are:

TA_BASELINE The reference point will be on the baseline of the text.
TA_BOTTOM The reference point will be on the bottom edge of the bounding rectangle.
TA_TOP The reference point will be on the top edge of the bounding rectangle.
TA_CENTER The reference point will be aligned horizontally with the center of the bounding rectangle.
TA_LEFT The reference point will be on the left edge of the bounding rectangle.
TA_RIGHT The reference point will be on the right edge of the bounding rectangle.
TA_NOUPDATECP The current position is not updated by a call to a text output function. The reference point is passed with each call.
TA_UPDATECP The current position is updated by each call to a text output function, and is used as the reference point.

The default setting is TA_LEFT | TA_TOP | TA_NOUPDATECP. If you set TA_UPDATECP, subsequent calls to TextOut() will ignore the nXStart and nYStart parameters, and render the text where the last call left off. Now that that's out of the way, let's look at the bells-and-whistles version of TextOut(), called DrawText():

int DrawText( HDC hDC, // handle to device context LPCTSTR lpString, // pointer to string to draw int nCount, // string length, in characters LPRECT lpRect, // pointer to struct with formatting dimensions UINT uFormat // text-drawing flags );

This one gets a bit complicated. Since DrawText() formats text, possibly to multiple lines, the return value is the height of the text in pixels, or 0 if the function fails. Let's take a look at the parameters, shall we?

HDC hDC: Nothing new here; it's just our good buddy the DC.

LPCTSTR lpString: This is the string to print.

int nCount: This is the length of the string in characters.

LPRECT lpRect: Here's where things start to get a bit different. DrawText() does several different methods of formatting, including word wrapping, so you must specify a RECT within which to format the text, rather than simply passing coordinates.

UINT uFormat: For this, you can use one or more (logically combined with |) of a long list of flags that represent different methods of formatting. I'll show you a few of them.

DT_BOTTOM Justifies text to the bottom of the RECT. This must be combined with DT_SINGLELINE.
DT_CALCRECT Calculates the RECT needed to hold the text. If the text is on multiple lines, DrawText() uses your RECT's width and alters the height. If the text is on a single line, DrawText() alters your RECT's width. In both cases, DrawText() adjusts the RECT but does not actually draw the text.
DT_CENTER Centers text within the RECT you specify.
DT_EXPANDTABS If the string contains any tabs (\t), this attribute causes DrawText() to expand them. The default is eight spaces per tab.
DT_LEFT Left-justifies the text.
DT_NOCLIP Draws without clipping. This speeds up DrawText() a bit.
DT_RIGHT Right-justifies the text.
DT_SINGLELINE Displays text on a single line only. Carriage returns and line feeds do not overrule this attribute.
DT_TABSTOP Alters the number of spaces per tab. The number of spaces per tab must be specified in bits 15-8 (the high byte of the low word) of uFormat. Again, the default setting is eight.
DT_TOP Justifies text to the top of the RECT. This must be combined with DT_SINGLELINE.
DT_VCENTER Centers the text vertically within the RECT. This must be combined with DT_SINGLELINE.

There are more of these flags, but you get the idea. All in all, this constitutes a pretty powerful text rendering system, but remember, all those cool features are going to slow the function down. You can usually get by just fine by using TextOut(). That takes care of the text rendering system, so let's do something a little more exciting.




Next : Displaying Bitmaps With GDI