The Text Drawing Functions

The most common text output function is one we've used in almost all sample programs:

TextOut (hdc, xStart, yStart, lpString, nCount) ;

The xStart and yStart parameters are the starting position of the string in logical coordinates. Normally, this is the point at which Windows begins drawing the upper left corner of the first character. TextOut requires a far pointer to the character string and the length of the string. The function knows nothing about NULL-terminated character strings.

The meaning of the xStart and yStart parameters to TextOut can be altered by the SetTextAlign function. The TA_LEFT, TA_RIGHT, and TA_CENTER flags affect the horizontal positioning of the character string. For example, if you call SetTextAlign with the TA_CENTER flag, subsequent TextOut calls position the center of the string at xStart. Similarly, the TA_TOP, TA_BOTTOM, and TA_BASELINE flags affect the vertical positioning. If you call SetTextAlign with the TA_UPDATECP flag, then Windows ignores the xStart and yStart parameters to TextOut and instead uses the current position previously set by MoveTo or LineTo. The TA_UPDATECP flag also causes the TextOut function to update the current position to the end of the string (for TA_LEFT) or the beginning of the string (for TA_RIGHT). When the horizontal positioning is TA_CENTER, the current position remains the same after a TextOut call.

You'll recall that displaying columnar-aligned text in the series of SYSMETS programs in Chapter 2 required that one TextOut call be used for each column. An alternative is the TabbedTextOut function. If the text string contains embedded tab characters (`\t' or 0x09), TabbedTextOut will expand the tabs into spaces based on an array of integers you pass to the function.

The ExtTextOut function gives you much more control over the spacing of individual characters in the text string. The function also lets you specify a clipping rectangle.

A higher-level function for writing text is DrawText, which we first encountered in the HELLOWIN program in Chapter 1. Rather than specifying a coordinate starting position, you provide a structure of type RECT that defines a rectangle in which you want the text to appear:

DrawText (hdc, lpString, nCount, &rect, wFormat) ;

DrawText also requires a far pointer to the character string and the length of the string. If you use DrawText with NULL-terminated strings, however, you can set nCount to -1, and Windows will calculate the length of the string.

When wFormat is set to 0, Windows interprets the text as a series of lines that are separated by carriage-return characters (ASCII number 13) or linefeed characters (ASCII number 10). The text begins at the upper left corner of the rectangle. A carriage return or linefeed is interpreted as a ”newline“ character; Windows breaks the current line and starts a new one. The new line begins at the left side of the rectangle, spaced one character height (without external leading) below the previous line. Any text (including parts of letters) that would be displayed to the right or below the bottom of the rectangle is clipped.

You can change the default operation of DrawText by including a wFormat parameter, which consists of one or more flags defined in WINDOWS.H and separated by the C bitwise OR operator. The DT_LEFT flag (the default) specifies a left-justified line, DT_RIGHT specifies a right-justified line, and DT_CENTER specifies a line centered between the left and right sides of the rectangle. Because the value of DT_LEFT is 0, you needn't include the identifier if you want text to be left-justified only.

If you don't want carriage returns or linefeeds to be interpreted as newline characters, you can include the identifier DT_SINGLELINE. Windows then interprets those ASCII numbers as displayable characters rather than as control characters. When using DT_SINGLELINE, you can also specify whether the line is to be placed at the top of the rectangle (DT_TOP, the default), at the bottom of the rectangle (DT_BOTTOM), or halfway between the top and bottom (DT_VCENTER). DT_TOP, like DT_LEFT, has a value of 0, so you don't need to explicitly include the flag.

When displaying multiple lines of text, Windows normally breaks the lines only at carriage returns or linefeeds. If the lines are too long to fit in the rectangle, however, you can use the DT_WORDBREAK flag, which causes Windows to make breaks at the ends of words within lines. For both single-line and multiple-line displays, Windows truncates any part of the text that falls outside the rectangle. You can override this by including the flag DT_NOCLIP, which also speeds up the operation of the function. When Win- dows spaces multiple lines of text, it uses the character height without external leading. If you prefer that external leading be included in the line spacing, use the flag DT_EXTERNALLEADING.

If your text contains tab characters (ASCII number 9), you need to include the flag DT_EXPANDTABS. By default, the tab stops are set at every eighth character position. You can specify a different tab setting by using the flag DT_TABSTOP, in which case the upper byte of wFormat contains the character-position number of the new tab stops. I recommend that you avoid using DT_TABSTOP, however, because the upper byte of wFormat is also used for some other flags.