In this section, we'll show you how to draw text in the window client area. If you want to draw text in the client area, you need to set the entire client area or the rectangular area where the specified text is located as an invalid area, and then generate a WM panit message and call the GDI function to draw the text. In addition, if you want to draw text, you also need to use a device context handle, which involves the font in which the text is drawn, the size and dimensions of the characters, and the formatting of the text.
What you need to know in this section:
Invalid rectangle vs. valid rectangle
Device environment
Fonts & Characters
Exercise 19: Get system configuration information no1
Window client area
This is shown in Figure 3-1.
Figure 3-1 Window client area.
The window client area is the section below the window title bar. The user can change the size of the window by dragging the window, and also change the size of the window client area. The Windows program can draw an area in the window client area and convey visual information.
wm paint message
Most Windows programs call the UpDataWindow function before entering a message loop during the initialization of the WinMain function. Windows takes advantage of this opportunity to send an initial WM Paint message to the windowing process. The notification window process draws the client area. After that, the window process needs to be able to process new WM PAINT messages at almost any time, and redraw the entire client area if necessary. The window process receives a WM PAINT message when any of the following events occur:
The user moves a window, causing the previously masked portion of the window to be exposed.
The user resizes the window (when the window is similarly set to cs hreadram and cs vreadram values).
The program calls the scrollwindow or scrolldc function to scroll the client area.
The program calls the invalidaterect or invalidatrgn function to display the generated WM PAINT message.
In some cases, when a portion of the client area is temporarily overwritten, Windows will attempt to save the overwritten portion for future recovery. It's not always successful. Windows sometimes sends a WM Paint message in the following scenarios:
Windows closes a dialog box or message box that covers part of the window.
The drop-down menu is pulled down and then retracted.
A prompt message is displayed.
In a few cases, Windows will always save the overwritten part of the display and then restore it. These situations are as follows:
The mouse pointer moves over the client area.
Drag the ** label in the customer area.
Handling WM PAINT messages requires us to change the concept of output. The program should collect and save all the information used to draw the client area, but will only do so when it is needed - when a WM PAINT message is received, it can force Windows to generate a WM PAINT message if the program needs to update the client area at another time. This may seem like a detour, but the structure of the program will benefit from it.
Effective rectangle
In Windows windows, the effective rectangular area of the window is the area of the window where content can actually be drawn, that is, the area where the title bar, borders, and other non-client areas are excluded. The effective rectangular area is usually represented by the upper-left and lower-right coordinates of the rectangle, which can be obtained by the getclientrect function:
getclientrect: This function is used to get the coordinates of the rectangular area of the window client area. This function takes a window handle argument and a pointer to the rectangular region of the window client area, and stores the coordinates of the rectangular region in the window client area in the struct.
bool getclientrect(
hwnd hwnd, window handle.
Pointer to the lprect lprect rect structure.
Example: rect rcclient;
getclientrect(hwnd, &rcclient);
adjustwindowrect: This function calculates the coordinates of the entire window (including title bar, border, etc.) based on the specified window style and the rectangular area of the client area.
bool adjustwindowrect(
lprect lprect, the specified rectangular area.
dword dwstyle, window style.
Bool Bmenu menu.
Example: rect rcclient;
adjustwindowrect(&rcclient, dwstyle, false);
Invalid rectangle
In the Windows GUI, an invalid rectangular region usually refers to the part of the window that needs to be redrawn. When the contents of a window change, or are obscured by other windows and then revealed, the relevant area is marked as "invalid" and needs to be redrawn in the next paint cycle.
Invalid areas are handled through Windows' messaging system. When part of the window becomes invalid, the system will send a WM paint message, and in the next drawing cycle, call the window procedure function corresponding to the window to redraw the invalid area.
If you need to manually set the invalid area in your program, you can use some of the following functions:
invalidaterect: This function will mark the entire area of the window or the specified area as invalid, and the function prototype is as follows:
bool invalidaterect(
hwnd hwnd,const rect *lprect,bool berase
hwnd: window handle that specifies the window to be zone-neutralized.
lprect: A pointer to a rectangular area of a rectangular structure that is used to specify the area of the rectangular to be neutralized. If this parameter is null, the entire window will be marked as invalid.
berase: Whether to erase the background the next time the paint message is processed.
InvalidAtergn: Similar to InvalidAterect, but used to set an invalid region.
When you receive a WM paint message, you can call the BeginPaint function to get the invalid area and start the painting process, and call EndPaint to finish when you finish painting. Beginpaint automatically validates the window (i.e. clears the invalid area marker) after processing the message.
If there is already a WM PAINT message in the message queue, Windows will recalculate a new invalid rectangle. Otherwise, Windows will place a WM PAINT message in the message queue. Later in this chapter, as we will see, when the window process receives a WM paint message, it can obtain the coordinates of an invalid rectangle. And at any other time, it can get these coordinates by calling the getupdaterect function.
It is important to note that while the system will automatically handle the redraw of invalid areas, in some cases, if you don't need to update the window immediately, or if you want to update at a specific time (e.g. after a series of changes have been made), you can use the validaterect or validatrgn function to clear the invalid areas and avoid triggering the WM PAINT message right away. Then, when appropriate, use the invalidaterect or invalidatern function to set the invalid area and trigger the window redraw.
Using these functions for manual neutralization and validation can help improve the performance and user experience of your software and avoid flickering and performance degradation caused by repeated invalidations and redraws.
Overall, dealing with invalid rectangular areas is an important concept in Windows GUI programming, and it is important to understand how it works in order to have more control over the updating and redrawing of windows when writing and maintaining.
Device environment
In Windows, a device context (DC) is an abstract concept used to describe a device (such as a monitor, printer, etc.). The device environment DC is actually a data structure maintained internally by GDI, which contains all the information of the drawing, which can be regarded as the working environment of the drawing, such as various drawing parameters such as line width, color, font, etc. When we need to map a device, we need to obtain the corresponding device environment of the device.
There are three basic types of device environments: display DC, printer DC, and memory DC. We'll cover the print device environment in Chapter 13, and the memory device environment in Chapter 14. In this chapter, we're only going to cover the display device environment.
The program must first obtain a handle to the device environment before drawing. After obtaining the handle, Windows populates the internal device environment structure with the default property values. In a later chapter, we'll learn about some GDI functions that can change these defaults. Some GDI functions allow you to get the current property value. There are also GDI functions that allow you to actually draw in the current client area.
When the program has finished drawing the client area, it must release the device environment handle. After the program releases a handle, the handle is no longer valid and can no longer be used. The program must acquire and release handles in the process of processing the same message. We can't pass an environment device handle between two messages, with the only exception being the device environment created by calling the createdc function, which is not discussed in this chapter.
The display environment is the device environment associated with the display and is used to draw on the screen. Generally, it is obtained through functions such as getdc and beginpaint.
The method to get the handle of the device environment
Method 1: In the previous example, when we process the WM PAINT message, the window process first calls the Beginpaint function to erase the background of the invalid area for drawing. At the same time, the fields of the PS structure are populated.
The paintstruct structure is defined as follows:
typedef struct tagpaintstruct
hdc hdc ;
bool ferase ;
rect rcpaint ;
bool frestore ;
bool fincupdate ;
byte rgbreserved[32] ;
paintstruct ;
The program can only use the first three fields, and the other fields are for internal use in Windows. HDC is the device environment handle, and the return value of the Beginpaint function is the value of the device environment handle. In most cases, the ferase field is set to false(0). This means that Windows has erased the background of the invalid area in the previous Beginpaint function. (If you want to customize the way the background is erased during the window, you have to deal with the WM erasebkgnd message yourself). At WinMain initialization, the BHRbackground field in the WNDSoct structure used to register the window class specifies a brush, which Windows uses to erase the background. Many Windows programs specify a white background brush.
wndclass.hbrbackground = (hbrush) getstockobject (white_brush) ;Window background color.
But when your program invalidates a rectangle in the client area by calling the invalidaterect function, the last argument of the function specifies whether the background is to be erased or not. If the parameter is false(0), Windows will not erase the background, and the value of the ferase field of the PaintStruct structure will be true (non-zero) after calling the BeginPaint function.
The rcpaint field of the paintstruct structure is a rect type structure. We know that the rect structure defines a rectangle with 4 fields: left, top, right, and bottom. The rcpaint field in the paintstruct structure defines the boundaries of the invalid rectangle.
The rcpaint rectangle in the paintstruct structure is not only an invalid rectangle, but also a "cropped" rectangle, and if the invalid area is not a rectangle, Windows will limit the draw to this area.
When processing WM Paint messages, the following function can be drawn outside of the update rectangle by calling BeginPaint:
invalidaterect(hwnd,null,true);
This call neutralizes the entire client area and causes the beginpaint to be called later to erase the original background. If the last parameter is set to false, the subsequent call of the BeginPaint function will not erase the background, and the original background will be retained.
In general, the most convenient thing for Windows programs is to simply redraw the client area after receiving the WM Paint message, regardless of the value of the RCPAINT structure. For example, if the display of the client area includes a circle, but only part of it falls within the invalid area, it is not practical to draw only a part of the circle. The easy way to do this is to redraw the entire circle. When using the device environment handle returned by Beginpaint, Windows doesn't draw outside the rectangle defined by RCPAINT anyway.
The return value of the beginpaint function is the device environment handle, which is usually stored in a variable called hdc.
hdc hdc;
The HDC data type is a 32-bit unsigned integer. After that, the program can call any GDI function that requires a handle to the device's environment, such as textout. Calling the endpaint function will release the device environment handle.
The ** that typically handles WM PAINT messages is as follows:
case wm_paint:
hdc = beginpaint(hwnd,&ps);
Use the gdi function].
endpaint(hwnd,&ps);
return 0;
When processing WM Paint messages, the window procedure must call the BeginPaint and EndPaint functions in pairs. If the window procedure does not process WM PAINT messages, WM PAINT messages are passed to the Windows default window procedure DeWindowProc. ** Below:
case wm_paint:
beginpaint(hwnd,&ps);
endpaint(hwnd,&ps);
return 0;
This does not contain any ** between the two functions, except for the original invalid region.
The following ** is false:
case wm_paint:
return 0;//wrong!
Since some client areas are invalid, Windows will place a WM PAINT message in the message queue. Unless the Beginpaint and Endpaint functions are called, Windows will not validate that area. As a result, Windows will keep sending WM Paint messages forever.
Method 2: Call the getdc function to obtain the handle of the device environment. Usually the drawing is done while processing the WM Paint message. However, sometimes it is not necessarily, if you need to call the gdi drawing function to draw when processing other messages, you need to use the device environment handle, and the device environment handle cannot be used across messages, but can only be re-obtained. The Beginpaint and Endpaint functions cannot be used in other message modules, so use the getdc function to obtain the device environment handle, and the releasedc function to release the device environment handle. Similar to Beginpaint and Endpaint, getdc and releasedc must be used in pairs.
Unlike the device environment handle returned from the Beginpaint function, the clipping rectangle in the device environment handle returned from getdc is the entire client area. This means that it is possible to draw any part of the client area, not just in an invalid rectangle, which means that it doesn't matter if there is no invalid rectangle. Unlike Beginpaint, GETDC does not validate invalid areas. If you need to make the entire client area effective, you can call the function:
validaterect(hwnd,null);
Typically, the getdc and releasedc functions are used to process keyboard messages (e.g., in word processors) or mouse messages (e.g., in drawing programs). Using these two functions, the program can draw the client area in a timely manner when it receives input from the user's keyboard or mouse, without having to deliberately invalidate a portion of the client area in order to generate a WM PAINT message. However, even if the program paints while processing a non-WM PAINT message, it still has to collect enough information to update the display when it receives WM PAINT.
Another function similar to getdc is getwindowdc. getdc returns the device environment handle in the window client area, and getwindowdc returns the device environment handle for the entire window. For example, a programmer can use the device environment handle returned by GetWindowDC to output in the title bar of a window, and accordingly, the program must also process WM NCPAINT (non-client area drawing) messages.
System fonts
The device environment also defines the fonts that Windows uses when calling Textout. On Windows, there are many pre-installed fonts that you can use in your applications. These fonts are usually stored in the C: Windows Fonts folder. There are various types of fonts, and the default font is called "system font" or system font (identifiers are defined in windih header file). The system font is the default font used by Windows in the title bar, menus, and dialog boxes.
In the early days of Windows, the system font was a wide font, and a font was a non-monospaced font.
1 Monospaced font: Each character occupies an equal width. Whether it's a wide character like 'w' or a narrow character like 'i', each character will have the same width when displayed. This font is very useful in certain scenarios, such as monospaced fonts are often used in programming. Because in **, for the display of spaces and indentations, monospaced characters can make the structure clearer and the alignment more accurate. Common monospaced fonts include courier, monaco, and consolas.
2 Non-monospaced fonts: Also known as proportional fonts, individual characters and punctuation marks can occupy different widths. These fonts are more widely used in most documents, **, and graphical user interfaces because they have a better reading experience and visual appeal. For example, in a non-monospaced font, the width of the character 'i' is much smaller than that of the character 'w'. Common non-monospaced fonts include arial, times new roman, and verdana.
The choice of these two fonts depends on your specific needs. If you need features such as alignment or fixed width, you can choose monospaced fonts. For most document layout and web design, monospaced fonts are often a better choice because they feel smoother and more natural to read.
A system font is a "bitmatrix font": each character is made up of pixels. In Chapter 16 we will learn about TrueType fonts, which define characters from outlines. To some extent, the size of the characters in the system font depends on the size of the monitor: the system font involves being able to display at least 25 rows and 80 columns on the monitor.
Character size
In order to display multiple lines of text with the textout function, you need to know the size of the characters in the font. The height of a character can determine the vertical position of a line of text, while the average width of a character can determine the horizontal position of the next column of text.
There is no fixed value for the average width of characters in a system font, depending on the resolution of the display. If the screen resolution is low, the characters will be larger, and if the resolution is high, the characters will be smaller. The program can get the dimensions of the user interface by calling the getsystemmetrics function. Similarly, the getsystemmetrics function allows the program to get the font size. The getSystemMetrics function requires a handle for the device environment, as it returns information about the currently selected font in that device environment. Windows will copy the various values of the character size into the structure of the type TextMetric, which is found in WingDiThere are 20 fields defined in the h header file, but we only need to care about the first 7 of them:
typedef struct tagtextmetric
long tmheight;Character height.
long tmascent;The height of the upper part of the character (above baseline).
long **escent;The lower height of the character (below baseline).
long tminternalleading, the amount of headspace for the height of the character defined by tmheight.
long tmexternalleading, the amount of space sandwiched between two rows.
long tm**echarwidth, the average character width.
long tmmaxcharwidth, the width of the widest character.
Other structure fields.
textmetric, *ptextmetric ;
The units of the values for these fields depend on the mapping mode currently selected in the device environment. The default mapping mode, mm text, is in pixels.
Before you can call the GetSystemMetrics function, you first define a struct variable, usually named tm:
textmetric tm;
When you need to get the font size, first get the device environment handle, and then call the getsystemmetrics function:
hdc = getdc (hwnd) ;
gettextmetrics (hdc, &tm) ;
releasedc (hwnd, hdc) ;
After that, you can check the values in the text size structure and save the parts that you need to use later.
Text size
In the textmetrics structure there is various information about the current font in the device environment. However, the vertical size of the font is determined by only 5 of them, and Figure 3-2 shows 4 of them.
Figure 3-2 Font size
The most important of these is the tmheight, which is the sum of tmascent and ***escent. These two values are the maximum height of the character above and below the baseline, respectively. Spacing leading is the space between two lines of text. In the textmetrics structure, the internal spacing is included in the tmascent. This spacing is often used for Greek accent marks. The value of tminternalleading can be set to 0, in which case the accented character will be slightly shorter to include the accent.
tmexternalleading is not included in the value of tmheight. This field is the amount of space that the font designer recommends between two lines of text. When displaying multiple lines of text, you can choose to accept or ignore the suggestion.
tm**echarwidth is the weighted average width of lowercase characters;
tmmaxcharwidth is the width of the widest character in the font. In monospaced fonts, these two values are the same.
In the example program in this chapter, there is another type of character width: the average width of uppercase characters. The value size can usually be pressed by 15x calculation.
It is important to note that the size of the system font depends on the display resolution of the Windows runtime, and sometimes on the system font size selected by the user. Windows provides a graphical interface that is not related to the device. But programmers also need to be careful: don't guess the size of the text in a Windows application, don't use a fixed value, and get this information by calling the GetTextMtetricd function.
Text formatting
When the Windows system is running, the system font does not change. Therefore, the best time for an application to call the gettextmetrics function is when the windowed procedure is processing the WM CREATE message. The WM CREATE message is the first message received by the window process.
Let's say your Windows program needs to display a few lines of text in the client area, and you need to get the width and height of the characters. During the windowing process, two variables can be defined to save:
static int cxchar,cychar;
The variable name is prefixed with c for "cont", which here stands for pixels. Combined with x,y, it represents width and height. This is defined as a static variable or as a global variable.
The following ** is to get the height and width of the system font:
case wm_create:
hdc = getdc (hwnd) ;
gettextmetrics (hdc, &tm) ;
cxchar = tm.tm**echarwidth ;
cychar = tm.tmheight + tm.tmexternalleading ;
releasedc (hwnd, hdc) ;
return 0 ;
In the window, each line of text appears at the cychar pixels below the previous line of text.
Formatted numbers and strings are usually displayed. As mentioned in Chapter 2, you can't use the traditional tool printf function, but you can use the sprintf function or the Windows version of sprintf, wsprintf. These functions are similar to printf, except that formatted characters are stored in a string. This string can be output to the window via the textout function. Conveniently, the return value of the sprintf function and the wsprintf function is the length of the string, which can be passed to the textout function as an ilength parameter.
The following ** shows a typical combination of wsprintf and textout:
int ilength ;
tchar szbuffer [40] ;
Other program lines].
ilength = wsprintf (szbuffer, text ("the sum of %i and %i is %i"), ia, ib, ia + ib) ;
textout (hdc, x, y, szbuffer, ilength) ;
For such a simple case, you can put the definition of ilength in the same statement as textout, so that you don't need to define ilength:
textout (hdc, x, y, szbuffer,wsprintf (szbuffer, text ("the sum of %i and %i is %i"), ia, ib, ia + ib))
Although it doesn't look good to write like this, the function is the same as the former.
sysmets.h -- Array of system configuration information structures (see Appendix B).
019 Programming Guru Win32 API daily practice.
The 19th example is sysmets1c: Text output --- get system configuration information no1
textmetric structure.
getdc function.
releasedc function.
gettextmetrics function.
settextalign function.
getSystemMetrics function.
Note: Not all information can be displayed in the window client area.
c) www.bcdaren.com coding whiz.
#include
#include
#include "sysmets.h"Define an array of system information structures and numlines (the number of rows to be displayed).
lresult callback wndproc(hwnd, uint, wparam, lparam);
int winapi winmain(hinstance hinstance, hinstance hprevinstance,pstr szcmdline, int icmdshow)
static tchar szappname = text("sysmets1");
Omitted) return msgwparam;
lresult callback wndproc(hwnd hwnd, uint message, wparam wparam, lparam lparam)
static int cxchar;The average width of the character.
static int cxcaps;Character spacing.
static int cychar;Character leading.
hdc hdc;
int i;
paintstruct ps;
tchar szbuffer[10];
textmetric tm;Basic information about the physical font.
switch (message)
case wm_create:
hdc = getdc(hwnd);Get the device environment handle.
Obtain the current default font information from the device environment and store it in the textmetric structure variable.
gettextmetrics(hdc, &tm);
cxchar = tm.tm**echarwidth;The average width of the character.
tm.tmpitchandfamily font spacing, the low position of the tmpitchandfamily field determines whether the font is or not.
It is a monospaced font: 1 for a variable-width font and 0 for a monospaced font.
Font spacing cxcaps is set to 15 times. 1 indicates a widened font.
cxcaps = (tm.tmpitchandfamily & 1 ? 3 : 2) *cxchar / 2;
Character line spacing = character height + number of character top space.
cychar = tm.tmheight + tm.tmexternalleading;
releasedc(hwnd, hdc);Release the device environment handle.
return 0;
case wm_paint:
hdc = beginpaint(hwnd, &ps);
for (i = 0; i < numlines; i++)
Writes a string to the specified location with the currently selected font, background color, and body color.
Outputs system information.
textout(hdc, 0, cychar * i,sysmetrics[i].szlabel,lstrlen(sysmetrics[i].szlabel));
Output descriptive information.
textout(hdc, 22 * cxcaps, cychar * i,sysmetrics[i].szdesc,lstrlen(sysmetrics[i].szdesc));
Set the text alignment flag, aligned to the right and top.
settextalign(hdc, ta_right + ta_top);
Obtain the value of the System Information parameter.
textout(hdc, 22 * cxcaps + 40 * cxchar, cychar * i, szbuffer, header file generic function replaces wsprintf function.
stprintf_s(szbuffer, 10,text("%5d"), which retrieves its corresponding system information based on the index.
getsystemmetrics(sysmetrics[i].iindex)))
Restore the default alignment--- left and top alignment.
settextalign(hdc, ta_left | ta_top);
endpaint(hwnd, &ps);
return 0;
case wm_destroy:
postquitmessage(0);
return 0;
return defwindowproc(hwnd, message, wparam, lparam);
TextMetric structure: contains the basic information of the physical font. All sizes are specified in logical units;That is, they depend on the current mapping mode of the display context.
typedef struct tagtextmetric { // tm
long tmheight;Character height.
long tmascent;The height of the upper part of the character (above baseline).
long **escent;The lower height of the character (below baseline).
long tminternalleading, the amount of headspace for the height of the character defined by tmheight.
long tmexternalleading, the amount of space sandwiched between two rows.
long tm**echarwidth, the average character width.
long tmmaxcharwidth, the width of the widest character.
long tmweight;The weight of the font.
long tmoverhang, which adds additional height on some of the spliced fonts.
long **igitizedaspectx, the horizontal direction of the device for which the font is designed.
long **igitizedaspecty, the vertical direction of the device for which the font design is intended.
bchar tmfirstchar;The first character defined for the font.
bchar tmlastchar;The last character defined for the font.
bchar **efaultchar;Alternate characters for characters that are not present in the font.
bchar tmbreakchar;The character used for word splitting.
byte tmitalic, non-zero when the font is italics.
byte tmunderlined, which is non-zero when the font is underscored.
byte tmstruckout, non-zero when the font is removed.
byte tmpitchandfamily, font spacing (4 bits lower) and family (4 bits higher).
byte tmcharset;The character set of the font.
textmetrica, *ptextmetrica, *nptextmetrica, *lptextmetrica;
getdc function: The retrieval handle is used to specify the client area of the window or the device context (DC) for the entire screen. You can use the returned handle in a subsequent GDI function to plot the DC.
A device context is an opaque data structure whose value is used internally by GDI.
hdc getdc(
hwnd hwnd to get the handle of the window whose dc you want to get.
If this value is null, then getdc retrieves the DC for the entire screen.
Return value. If the function succeeds, the return value is the handle to the client area DC of the specified window.
If the function fails, the return value is null.
ReleasedC function: Releases the Device Context (DC) and frees it for use by other applications.
The effect of the ReleasedC feature depends on the type of DC. It only frees up public DC and window DC. It doesn't work for class or private DC.
int releasedc(
hwnd hwnd, the handle of the window whose dc is to be released.
HDC HDC handles the DC to be released.
Return value. The return value indicates whether the DC was freed. If DC is released, the return value is 1.
If the DC is not freed, the return value is zero.
getTextMetrics function: Fills and measures the buffer specified by the currently selected font.
bool gettextmetrics(
HDC HDC, the handle of the device context.
LPemTextMetric LPTM A pointer to the textmetric structure of the received text metric.
Return value. If the function succeeds, the return value is non-zero.
If the function fails, the return value is zero.
setTextAlign function: sets the text alignment flag for the specified device environment.
uint settextalign(
HDC HDC, the handle of the device context.
uint align text alignment by using a mask of values from the following list.
Return value. If the function succeeds, the return value is the previous text alignment setting.
If the function fails, the return value is gdi error
getSystemMetrics function: retrieves specified system metrics or system configuration settings.
int getsystemmetrics(
int nindex The system metric or configuration setting to be retrieved.
Return value. Type: int
If the function succeeds, the return value is the requested system metric or configuration setting.
If the function fails, the return value is 0. GetLastError does not provide error information for extensions.
Note] It is clear that only part of the content is displayed in the window client area.
Figure 3-3 displays the system configuration.
This article is excerpted from the programming master series textbook "Windows API Daily Practice" - Windows Programming Basics.