Chapter 5 Basic Drawing 第五章 绘图基础 — The Device Context - 关联设备

类别:编程语言 点击:0 评论:0 推荐:
ps:您可以转载,但请注明出处;你可以修改,但请将修改结果告诉我。
  The Device Context 关联设备   Before we begin drawing, let's examine the device context with more rigor than we did in Chapter 4. 在我们开始绘图之前,让我们比在第四章中做的更严格地考察关联设备。   When you want to draw on a graphics output device such as the screen or printer, you must first obtain a handle to a device context (or DC). In giving your program this handle, Windows is giving you permission to use the device. You then include the handle as an argument to the GDI functions to identify to Windows the device on which you wish to draw. 当你想在诸如屏幕或打印机的图形输出设备上绘图时,你必须首先获得关联设备(或 DC)的句柄。你给你的程序该句柄期间,Windows 允许你使用该关联设备。然后你包含该句柄作为 GDI 函数的参数以向 Windows 确定你希望在哪一个关联设备上绘图。   The device context contains many "attributes" that determine how the GDI functions work on the device. These attributes allow GDI functions to have just a few arguments, such as starting coordinates. The GDI functions do not need arguments for everything else that Windows needs to display the object on the device. For example, when you call TextOut, you need specify in the function only the device context handle, the starting coordinates, the text, and the length of the text. You don't need to specify the font, the color of the text, the color of the background behind the text, or the intercharacter spacing. These are all attributes that are part of the device context. When you want to change one of these attributes, you call a function that does so. Subsequent TextOut calls to that device context use the new attribute. 关联设备包含许多确定 GDI 函数如何在设备上工作的属性。这些属性允许 GDI 函数只有少量参数,比如开始坐标。GDI 函数不需要 Windows 需要在关联设备上显示对象的所有其它参数。例如,当你调用 TextOut 时,你只需要在函数中指定关联设备句柄,开始坐标,文本和文本长度。你不需要指定字体,文本颜色,文本后的背景颜色或字符间距。这些都是作为关联设备一部分的属性。当你想改变这些属性之一时,你调用这样做的函数。后来的调用该关联设备的 TextOut 用新的属性。   Getting a Device Context Handle 获得关联设备句柄   Windows provides several methods for obtaining a device context handle. If you obtain a video display device context handle while processing a message, you should release it before exiting the window procedure. After you release the handle, it is no longer valid. For a printer device context handle, the rules are not as strict. Again, we'll look at printing in Chapter 13. Windows 提供几个获得关联设备句柄的方法。如果你在处理消息时获得视频显示器关联设备句柄,那么你应该在退出窗口处理函数之前释放它。在你释放该句柄之后,它不再有效。对于打印机关联设备句柄,规则不是严格。同样,我们将在第 13 章中看到打印。   The most common method for obtaining a device context handle and then releasing it involves using the BeginPaint and EndPaint calls when processing the WM_PAINT message: 最常用的获得关联设备句柄然后释放它的方法包括在处理 WM_PAINT 消息时使用 BeginPaint 和 EndPaint 调用:   hdc = BeginPaint (hwnd, &ps) ; [other program lines] EndPaint (hwnd, &ps) ;   The variable ps is a structure of type PAINTSTRUCT. The hdc field of this structure is the same handle to the device context that BeginPaint returns. The PAINSTRUCT structure also contains a RECT (rectangle) structure named rcPaint that defines a rectangle encompassing the invalid region of the window's client area. With the device context handle obtained from BeginPaint you can draw only within this region. The BeginPaint call also validates this region. 变量 ps 是 PAINTSTRUCT 类型的结构。该结构的 hdc 域是和 BeginPaint 返回的关联设备句柄一样的句柄。PAINSTRUCT 结构也包含叫做 rcPaint 的 RECT(矩形)结构,它定义了一个包含窗口客户区的无效区域的矩形。用从 BeginPaint 获得的关联设备句柄,你只可以在该区域中绘图。BeginPaint 调用也可以使该区域有效。   Windows programs can also obtain a handle to a device context while processing messages other than WM_PAINT: 当处理非 WM_PAINT 消息时,Windows 程序也可以获得关联设备句柄:   hdc = GetDC (hwnd) ; [other program lines] ReleaseDC (hwnd, hdc) ;   This device context applies to the client area of the window whose handle is hwnd. The primary difference between the use of these calls and the use of the BeginPaint and EndPaint combination is that you can draw on your entire client area with the handle returned from GetDC. However, GetDC and ReleaseDC don't validate any possibly invalid regions of the client area. 该关联设备应用于句柄是 hwnd 的窗口的客户区。在这些调用的使用和 BeginPaint 和 EndPaint 组合使用之间最主要的不同是你可以用从 GetDC 返回的句柄在你的整个客户区上绘制。然而,GetDC 和 ReleaseDC 不会使客户区的任何可能无效的区域有效。   A Windows program can also obtain a handle to a device context that applies to the entire window and not only to the window's client area: Windows 程序可以可获得应用于整个窗口而不只是窗口的客户区的关联设备句柄:   hdc = GetWindowDC (hwnd) ; [other program lines] ReleaseDC (hwnd, hdc) ;   This device context includes the window title bar, menu, scroll bars, and frame in addition to the client area. Applications programs rarely use the GetWindowDC function. If you want to experiment with it, you should also trap the WM_NCPAINT ("nonclient paint") message, which is the message Windows uses to draw on the nonclient areas of the window. 这个关联设备除客户区之外还包括窗口标题栏,菜单,滚动调和框架。应用软件程序很少用 GetWindowDC。如果你想实践它,那么你应该也捕获 WM_NCPAINT(“noclient paint”)消息,它是 Windows 用来在窗口的非客户区上绘图的消息。   The BeginPaint, GetDC, and GetWindowDC calls obtain a device context associated with a particular window on the video display. A much more general function for obtaining a handle to a device context is CreateDC: BeginPaint,GetDC 和 GetWindowDC 调用包含与视频显示器上特殊窗口相关的关联设备。获得关联设备句柄的最常用的函数是 CreateDC:   hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData) ; [other program lines] DeleteDC (hdc) ;   For example, you can obtain a device context handle for the entire display by calling 例如,你可以通过调用    hdc = CreateDC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;   Writing outside your window is generally impolite, but it's convenient for some unusual applications. (Although this fact is not documented, you can also retrieve a device context for the entire screen by calling GetDC with a NULL argument.) In Chapter 13, we'll use the CreateDC function to obtain a handle to a printer device context. 获得整个显示器的关联设备句柄;输出到你的窗口外面通常是不合适的,但是它便于一些非普通的应用程序。(尽管这个事实是没有文档说明的,但是你也可以通过调用有 NULL 参数的 GetDC 保留整个屏幕的关联设备。)在第 13 章中,我将用 CreateDC 函数获得打印机关联设备的句柄。   Sometimes you need only to obtain some information about a device context and not do any drawing. In these cases, you can obtain a handle to an "information context" by using CreateIC. The arguments are the same as for the CreateDC function. For example, 有时你只需要获得一些关于关联设备的信息而不做任何绘图。在这些情况下,你可以通过用 CreateIC 获得 “关联信息”的句柄。参数和 CreateDC 函数的相同。例如,   hdc = CreateIC (TEXT ("DISPLAY"), NULL, NULL, NULL) ;   You can't write to the device by using this information context handle. When working with bitmaps, it can sometimes be useful to obtain a "memory device context": 你不可以通过使用该关连信息句柄输出到设备。当和位图一起工作时,它有时可以用于获得“内存关联设备”:   hdcMem = CreateCompatibleDC (hdc) ; [other program lines] DeleteDC (hdcMem) ;   You can select a bitmap into the memory device context and use GDI functions to draw on the bitmap. I'll discuss these techniques in Chapter 14. 你可以将位图选进内存关联设备并使用 GDI 函数在位图上绘制。我将在第 14 章讨论这些技术。   I mentioned earlier that a metafile is a collection of GDI function calls encoded in binary form. You can create a metafile by obtaining a metafile device context: 我早先提到元文件是以二进制形式编码的 GDI 函数调用的集合。你可以通过获得元文件关联设备创建元文件:   hdcMeta = CreateMetaFile (pszFilename) ; [other program lines] hmf = CloseMetaFile (hdcMeta) ;   During the time the metafile device context is valid, any GDI calls you make using hdcMeta are not displayed but become part of the metafile. When you call CloseMetaFile, the device context handle becomes invalid. The function returns a handle to the metafile (hmf). I'll discuss metafiles in Chapter 18. 在元文件关联设备有效期间,任何你用 hdcMeta 的 GDI 调用除了变成元文件的一部分之外不显示。当你调用 CloseMetaFile 时,关联设备句柄变成无效的。函数返回元文件的句柄(hmf)。我将在第 18 章中讨论元文件。   Getting Device Context Information 获得关联设备信息   A device context usually refers to a physical display device such as a video display or a printer. Often, you need to obtain information about this device, including the size of the display, in terms of both pixels and physical dimensions, and its color capabilities. You can get this information by calling the GetDeviceCap ("get device capabilities") function: 关联设备通常指的是诸如视频显示器或打印机的物理显示设备。经常,你需要获得关于该设备的信息,包括按照像素和物理尺度的显示器的尺寸和她的颜色能力。你可以通过调用 GetDeviceCap(“活的设备能力”)函数获得该信息:   iValue = GetDeviceCaps (hdc, iIndex) ;   The iIndex argument is one of 29 identifiers defined in the WINGDI.H header file. For example, the iIndex value of HORZRES causes GetDeviceCaps to return the width of the device in pixels; a VERTRES argument returns the height of the device in pixels. If hdc is a handle to a screen device context, that's the same information you can get from GetSystemMetrics. If hdc is a handle to a printer device context, GetDeviceCaps returns the height and width of the printer display area in pixels. iIndex 参数是在 WINGDI.H 头文件中定义的 29 个标识符之一。例如,HORZRES 的 iIndex 值使得 GetDeviceCap 返回以像素为单位的设备的宽度;VERTRES 参数返回以像素为单位的设备高度。如果 hdc 是屏幕关联设备的句柄,那么这和你可以从 GetSystemMetrics 获得的信息相同。如果 hdc 是打印机关联设备的句柄,那么 GetDeviceCaps 返回以像素为单位的打印机显示区域的高度和宽度。   You can also use GetDeviceCaps to determine the device's capabilities of processing various types of graphics. This is usually not important for dealing with the video display, but it becomes more important with working with printers. For example, most pen plotters can't draw bitmapped images and GetDeviceCaps can tell you that. 你也可以用 GetDeviceCaps 确定关联设备处理各种图形类型的能力。这对涉及视频显示器来说通常不重要,但是和打印机一起工作时它变得更加重要。例如,大多数绘图机不可以绘制位图图像,而 GetDeviceCaps 可以告诉你这些。   The DEVCAPS1 Program DEVCAPS1 程序   The DEVCAPS1 program, shown in Figure 5-1, displays some (but not all) of the information available from the GetDeviceCaps function using a device context for the video display. In Chapter 13, I'll present a second, expanded version of this program, called DEVCAPS2, that gets information for the printer. 在图 5-1 中显示的 DEVCAPS1 程序显示了一些(但不是全部)来自用视频显示器关联设备的 GetDeviceCaps 函数的可用信息。在第 13 章中,我将介绍这个程序的第二个扩展版本,叫做 DEVCAPS2,它获得打印机的信息。   Figure 5-1. The DEVCAPS1 program. 图 5-1 DEVCAPS1 程序

DEVCAPS1.C

/*--------------------------------------------------------- DEVCAPS1.C -- Device Capabilities Display Program No. 1 (c) Charles Petzold, 1998 ---------------------------------------------------------*/ #include <windows.h> #define NUMLINES ((int) (sizeof devcaps / sizeof devcaps [0])) struct { int iIndex ; TCHAR * szLabel ; TCHAR * szDesc ; } devcaps [] = { HORZSIZE, TEXT ("HORZSIZE"), TEXT ("Width in millimeters:"), VERTSIZE, TEXT ("VERTSIZE"), TEXT ("Height in millimeters:"), HORZRES, TEXT ("HORZRES"), TEXT ("Width in pixels:"), VERTRES, TEXT ("VERTRES"), TEXT ("Height in raster lines:"), BITSPIXEL, TEXT ("BITSPIXEL"), TEXT ("Color bits per pixel:"), PLANES, TEXT ("PLANES"), TEXT ("Number of color planes:"), NUMBRUSHES, TEXT ("NUMBRUSHES"), TEXT ("Number of device brushes:"), NUMPENS, TEXT ("NUMPENS"), TEXT ("Number of device pens:"), NUMMARKERS, TEXT ("NUMMARKERS"), TEXT ("Number of device markers:"), NUMFONTS, TEXT ("NUMFONTS"), TEXT ("Number of device fonts:"), NUMCOLORS, TEXT ("NUMCOLORS"), TEXT ("Number of device colors:"), PDEVICESIZE, TEXT ("PDEVICESIZE"), TEXT ("Size of device structure:"), ASPECTX, TEXT ("ASPECTX"), TEXT ("Relative width of pixel:"), ASPECTY, TEXT ("ASPECTY"), TEXT ("Relative height of pixel:"), ASPECTXY, TEXT ("ASPECTXY"), TEXT ("Relative diagonal of pixel:"), LOGPIXELSX, TEXT ("LOGPIXELSX"), TEXT ("Horizontal dots per inch:"), LOGPIXELSY, TEXT ("LOGPIXELSY"), TEXT ("Vertical dots per inch:"), SIZEPALETTE, TEXT ("SIZEPALETTE"), TEXT ("Number of palette entries:"), NUMRESERVED, TEXT ("NUMRESERVED"), TEXT ("Reserved palette entries:"), COLORRES, TEXT ("COLORRES"), TEXT ("Actual color resolution:") } ; LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("DevCaps1") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; if (!RegisterClass (&wndclass)) { MessageBox (NULL, TEXT ("This program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("Device Capabilities"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxChar, cxCaps, cyChar ; TCHAR szBuffer[10] ; HDC hdc ; int i ; PAINTSTRUCT ps ; TEXTMETRIC tm ; switch (message) { case WM_CREATE: hdc = GetDC (hwnd) ; GetTextMetrics (hdc, &tm) ; cxChar = tm.tmAveCharWidth ; cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ; cyChar = tm.tmHeight + tm.tmExternalLeading ; ReleaseDC (hwnd, hdc) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; for (i = 0 ; i < NUMLINES ; i++) { TextOut (hdc, 0, cyChar * i, devcaps[i].szLabel, lstrlen (devcaps[i].szLabel)) ; TextOut (hdc, 14 * cxCaps, cyChar * i, devcaps[i].szDesc, lstrlen (devcaps[i].szDesc)) ; SetTextAlign (hdc, TA_RIGHT | TA_TOP) ; TextOut (hdc, 14 * cxCaps + 35 * cxChar, cyChar * i, szBuffer, wsprintf (szBuffer, TEXT ("%5d"), GetDeviceCaps (hdc, devcaps[i].iIndex))) ; SetTextAlign (hdc, TA_LEFT | TA_TOP) ; } EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

As you can see, this program is quite similar to the SYSMETS1 program shown in Chapter 4. To keep the code short, I didn't include scroll bars because I knew the information would fit on one screen. The results for a 256-color, 640-by-480 VGA are shown in Figure 5-2. 正如你可以看到的,这个程序十分类似于在第 4 章中显示的 SYSMETS1 程序。为了使代码保持简短,我不包含滚动条,因为我知道这些信息将适合在一个屏幕上。在 256 色,640×480 VGA 上的结果如图 5-2 中显示。

Figure 5-2. The DEVCAPS1 display for a 256-color, 640-by-480 VGA. 图 5-2 256 色,640×480 VGA 上显示的DEVCAPS1   The Size of the Device 设备的尺寸   Suppose you want to draw a square with sides that are 1 inch in length. To do this, either you (the programmer) or Windows (the operating system) would need to know how many pixels corresponded to 1 inch on the video display. The GetDeviceCaps function helps you obtain information regarding the physical size of the output device, be it the video display or printer. 假设你想绘制一个边长是 1 英寸的正方形。为了绘制它,你(程序员)或 Windows(操作系统)将需要知道在视频显示器上 1 英寸相当多少像素。GetDeviceCaps 函数帮助你获得关于输出设备(视频显示器或打印机)的物理尺寸的信息。   Video displays and printers are two very different devices. But perhaps the least obvious difference is how the word "resolution" is used in connection with the device. With printers, we often indicate a resolution in dots per inch. For example, most laser printers have a resolution of 300 or 600 dots per inch. However, the resolution of a video display is given as the total number of pixels horizontally and vertically, for example, 1024 by 768. Most people couldn't tell you the total number of pixels their printers display horizontally and vertically on a sheet of paper or the number of pixels per inch on their video displays. 视频显示器和打印机是两个非常不同的设备。但是也许最明显的不同是单词“分辨率”如何连同设备使用。对于打印机,我们常常以每英寸点数指出分辨率。例如,大多数光栅打印机都有每英寸 300 或 600 点的分辨率。然而,视频显示器的分辨率是作为水平和垂直像素的总量给出的,例如,1024×768。大多数人不会告诉你他们的打印机在一张纸上水平地和垂直地显示的像素总量和他们的视频显示器上每英寸像素的量。   In this book I'm going to use the word "resolution" in the strict sense of a number of pixels per metrical unit, generally an inch. I'll use the phrase "pixel size" or "pixel dimension" to indicate the total number of pixels that the device displays horizontally or vertically. The "metrical size" or "metrical dimension" is the size of the display area of the device in inches or millimeters. (For a printer page, this is not the whole size of the paper but only the printable area.) Dividing the pixel size by the metrical size gives you a resolution. 在本书中我打算用单词“分辨率”来精确表示每度量单位(通常是英寸)像素的量。我将用惯用语“像素大小”和“像素尺寸”指出设备水平或垂直显示的像素总量。“度量大小”或“度量尺寸”是以营村或毫米为单位的设备的显示区的大小。(对于打印机页,这不是纸张的整个大小而仅仅是可打印区域的大小。)用度量大小除像素大小得到分辨率。   Most video displays used with Windows these days have screens that are 33 percent wider than they are high. This represents an aspect ratio of 1.33:1 or (as it's more commonly written) 4:3. Historically, this aspect ratio goes way back to when Thomas Edison was making movies. It remained the standard aspect ratio for motion pictures until various types of widescreen projection started to be used beginning in 1953. Television sets also have an aspect ratio of 4:3. 目前大多数和 Windows 一起使用的视频显示器有比它们的高度宽 33% 的宽度。这代表屏幕宽高比是 1.33:1 或(正如它更通用的写法)4:3。在历史上,这个屏幕宽高比返回了托马斯•爱迪生发明电影的时代。它保留了电影胶片的标准屏幕宽高比,直到 1953 年各种类型的宽屏幕放映开始使用。电视装置也有 4:3 的屏幕宽高比。   However, your Windows applications should not assume that the video display has a 4:3 aspect ratio. People who do mostly word processing sometimes prefer a video display that resembles the height and width of a sheet of paper. The most common alternative to a 4:3 display is a 3:4 display—essentially a standard display turned on its side. 然而,你的 Windows 应用程序应该不假定视频显示器有 4:3 的屏幕宽高比。做大量字处理的人有时更喜欢类似一张纸的高度和宽度的视频显示器。相对 4:3 显示最普通的选择是 3:4 显示——本质上是旋转了它的一边的显示。   If the horizontal resolution of a device equals the vertical resolution, the device is said to have "square pixels." Nowadays all video displays in common use with Windows have square pixels, but this was not always the case. (Nor should your applications assume that the video display always has square pixels.) When Windows was first introduced, the standard video adapter boards were the IBM Color Graphics Adapter (CGA), which had a pixel dimension area of 640 by 200 pixels; the Enhanced Graphics Adapter (EGA), which had a pixel dimension of 640 by 350 pixels; and the Hercules Graphics Card, which had a pixel dimension of 720 by 348 pixels. All these video boards used a display that had a 4:3 aspect ratio, but the number of pixels horizontally and vertically was not in the ratio 4:3. 如果设备的水平分辨宽度等于垂直分辨高度,那么设备被称作有“正方形像素”。现在所有通常和 Windows 一起使用的视频显示器有正方形的像素,但是这不总是这样。(你的应用程序不应该假定视频显示器总是有正方形像素。)当 Windows 首先被引入时,标准的视频适配器板是 IBM 彩色图形适配器(CGA),它有 640×200 像素的像素尺寸区域;增强的图形适配器,它有 640×350 像素的像素尺寸;Hercules 图形卡,它有 720×348 像素的像素尺寸。所有这些视频板都使用 4:3 屏幕宽高比的显示,但是水平地和垂直地的像素数量不是比率 4:3。   It's quite easy for a user running Windows to determine the pixel dimensions of a video display. Run the Display applet in Control Panel, and select the Settings tab. In the area labeled Screen Area, you'll probably see one of these pixel dimensions: 对于运行 Windows 的用户来说确定视频显示器的像素尺寸是非常容易的。在控制面板中运行“显示”小程序,并且选择“设置”标签。在标有“屏幕区域”的区域中,你将可能看到这些像素尺寸之一: 640 by 480 pixels    640×480 像素 800 by 600 pixels    800×600 像素 1024 by 768 pixels   1024×768 像素 1280 by 1024 pixels  1280×1024 像素 1600 by 1200 pixels  1600×1200 像素 All of these are in the ratio 4:3. (Well, all except the 1280 by 1024 pixel size. This should probably be considered an annoying anomaly rather than anything more significant. As we'll see, all these pixel dimensions when combined with a 4:3 monitor are considered to yield square pixels.) 所有这些都是比例 4:3。(哦,所有的但除了 1280×1024 像素尺寸。这应该可能被看作是一个讨厌的不规则而非任何更有意义的事。正如我们将看到的,当和 4:3 显示器结合时所有这些像素尺寸被看作是产生正方形像素。)   A Windows application can obtain the pixel dimensions of the display from GetSystemMetrics with the SM_CXSCREEN and SM_CYSCREEN arguments. As you'll note from the DEVCAPS1 program, a program can obtain the same values from GetDeviceCaps with the HORZRES ("horizontal resolution") and VERTRES arguments. This is a use of the word "resolution" that means the pixel size rather than the pixels per metrical unit. Windows 应用程序可以由有 SM_CXSCREEN 和 SM_CYSCREEN 参数的 GetSystemMetrics 获得显示器的像素尺寸。正如你将从 DEVCAPS1 程序注意到的,程序可以由有 HORZRES(“水平分辨宽度”)和 VERTRES 参数的 GetDeviceCaps 获得相同的值。这是意味着像素尺寸而非每度量单位像素的单词“分辨率”的一个用处。   That's the simple part of the device size. Now the confusion begins. 那是设备尺寸的一个简单的部分。现在混淆开始了。   The first two device capabilities, HORZSIZE and VERTSIZE, are documented as "Width, in millimeters, of the physical screen" and "Height, in millimeters, of the physical screen" (in /Platform SDK/Graphics and Multimedia Services/GDI/Device Contexts/Device Context Reference/Device Context Functions/GetDeviceCaps). These seem like straightforward definitions until one begins to think through their implications. For example, given the nature of the interface between video display adapters and monitors, how can Windows really know the monitor size? And what if you have a laptop (in which the video driver conceivably could know the exact physical dimensions of the screen) and you attach an external monitor to it? And what if you attach a video projector to your PC? 前两个设备能力 HORZSIZE 和 VERTSIZE 由文档说明为“以毫米为单位的物理屏幕的宽度”和“以毫米为单位的物理屏幕的高度”(在 /Platform SDK/Graphics and Multimedia Services/GDI/Device Contexts/Device Context Reference/Device Context Functions/GetDeviceCaps 中)。直到开始思考它们的含义时这些似乎像直截了当的定义。例如,给出视频显示适配器和显示器之间的接口的种类,Windows 如何可以真正地知道显示器尺寸?并且如果你有一个膝上型电脑(它的视频驱动程序可以方便地知道屏幕的确切物理尺寸)那么你给它配置一个什么样的外部显示器?并且如果你给你的 PC 配置一个什么样的视频放映机?   In the 16-bit versions of Windows (and in Windows NT), Windows uses a "standard" display size for the HORZSIZE and VERTSIZE values. Beginning with Windows 95, however, the HORZSIZE and VERTSIZE values are derived from the HORZRES, VERTRES, LOGPIXELSX, and LOGPIXELSY values. Here's how it works. 在 16 位版本的 Windows(和 Windows NT)中,Windows 将“标准的”显示器尺寸用于 HORZSIZE 和 VERTSIZE 值。然而,从 Windows 95 开始,HORZSIZE 和 VERTSIZE 值被派生为 HORZRES, VERTRES, LOGPIXELSX, 和 LOGPIXELSY 值。这里是它如何工作的。   When you use the Display applet of the Control Panel to select a pixel size of the display, you can also select a size of your system font. The reason for this option is that the font used for the 640 by 480 display may be too small to read when you go up to 1024 by 768 or beyond. Instead, you'll want a larger system font. These system font sizes are referred to on the Settings tab of the Display applet as Small Fonts and Large Fonts. 当你用控制面板的“显示”小程序选择显示器的像素尺寸时,你也可以选择你的系统字体的尺寸。这个选项存在的原因是用于 640×480 现实的字体在你换到 1024×768 或更高的分辨率时可能太小了而不能阅读。代替的,你将想要更大的系统字体。这些系统字体尺寸在“显示”小程序的“设置”标签上被引用为“小字体”和“大字体”。   In traditional typography, the size of the characters in a font is indicated by a "point size." A point is approximately 1/72 inch and in computer typography is often assumed to be exactly 1/72 inch. 在传统印刷中,字体中字符的大小由“点尺寸”指出。一个点是大约 1/72 英寸,而在计算机印刷中常常被假定为精确的 1/72 英寸。   In theory, the point size of a font is the distance from the top of the tallest character in the font to the bottom of descenders in characters such as j, p, q, and y, excluding accent marks. For example, in a 10-point font this distance would be 10/72 inch. In terms of the TEXTMETRIC structure, the point size of the font is equivalent to the tmHeight field minus the tmInternalLeading field, as shown in Figure 5-3. (This figure is the same as Figure 4-3 in the last chapter.) 理论上,字体的点大小是从字体中最高的字符的顶端到下降的字符(比如 j,p,q 和 y,包括重音符号)的底端的距离。例如,在 10 点字体中这个距离将是 10/72 英寸。用 TEXTMETRIC 结构的话,字体的点大小等价于 tmHeight 域减去 tmInternalLeading 域,正如图 5-3 中所示。(这幅图和上一章中的图 4-3 相同。)

Figure 5-3. The small font and the TEXTMETRIC fields. 图 5-3 小字体和 TEXTMETRIC 的域   In real-life typography, the point size of a font is not so precisely related to the actual size of the font characters. The designer of the font might make the actual characters a bit larger or smaller than the point size would indicate. After all, font design is an art rather than a science. 在现实生活的印刷中,字体的点大小不是如此正好和字体字符的实际大小相关的。字体设计者可能使实际字符比将指出的点大小更大或更小一点。毕竟,字体设计是一门艺术而非科学。   The tmHeight field of the TEXTMETRIC structure indicates how successive lines of text should be spaced on the screen or printer. This can also be measured in points. For example, a 12-point line spacing indicates the baselines of successive lines of text should be 12/72 (or 1/6) inch apart. You don't want to use 10-point line spacing for a 10-point font because the successive lines of text could actually touch each other. TEXTMETRIC 结构的  tmHeigh 域指出连续的文本行应该如何在屏幕或打印机上被隔开。这也可以是以点为标准的。例如,分隔连续文本行的基线的 12 点线应该是分开 12/72(或 1/6)。对于 10 点字体你不想用 10 点行间距 ,因为连续的文本行实际可以相互接触。   This book is printed with a 10-point font and 13-point line spacing. A 10-point font is considered comfortable for reading. Anything much smaller than 10 points would be difficult to read for long periods of time. 这本书是用 10 点字体和 13 点行间距打印的。10 点字体被认为适合阅读。任何比 10 点更小的字体将难于长时间地阅读。   The Windows system font—regardless of whether it is the "small font" or the "large font" and regardless of what video pixel dimension you've selected—is assumed to be a 10-point font with a 12-point line spacing. I know this sounds odd. Why call the system fonts "small font" and "large font" if they're both 10-point fonts? Windows 系统字体——不管它是“小字体”或“大字体”,也不管你选择什么视频像素尺寸——被假定为有 12 点行间距的 10 点字体。我知道这听起来是临时的。如果它们都是 10 点字体,那么这些系统字体为什么还叫“小字体”和“大字体”呢?   Here's the key: When you select the small font or the large font in the Display applet of the Control Panel, you are actually selecting an assumed video display resolution in dots per inch. When you select the small font, you are saying that you want Windows to assume that the video display resolution is 96 dots per inch. When you select the large font, you want Windows to assume that the video display resolution is 120 dots per inch. 这里是答案:当你在控制面板的“显示”小程序中选择小字体或大字体时,你实际上是选择一个以每英寸点的视频显示器分辩率。当你选择小字体时,你就是说你希望 Windows 假定视频显示器的分辨率是每英寸 96 点。当你选择大字体时,你希望 Windows 假定视频显示器的分辨率是每英寸 120 点。   Look at Figure 5-3 again. That's the small font, which is based on a display resolution of 96 dots per inch. I said it's a 10-point font. Ten points is 10/72 inch, which if you multiply by 96 dots per inch yields a result of (approximately) 13 pixels. That's tmHeight minus tmInternalLeading. The line spacing is 12 points, or 12/72 inch, which multiplied by 96 dots per inch yields 16 pixels. That's tmHeight. 再看一下图 5-3。那是小字体,它是基于每英寸 96 点的视频分辨率的。我说它是 10 点字体。十点是 10/72 英寸,如果你用它乘以每英寸 96 点就会产生一个(大约)13 像素的结果。那就是 tmHeight 减去 tmInternalLeading。行间距是 12 点或 12/72 英寸,它乘以每英寸 96 点产生 16 像素。那就是 tmHeight。   Figure 5-4 shows the large font. This is based on a resolution of 120 dots per inch. Again, it's a 10-point font, and 10/72 times 120 dots per inch equals 16 pixels (if you round down), which is tmHeight minus tmInternalLeading. The 12-point line spacing is equivalent to 20 pixels, which is tmHeight. (As in Chapter 4, let me emphasize again that I'm showing you actual metrics so that you can understand how this works. Do not code these numbers in your programs.) 图 5-4 显示大字体。这是基于每英寸 120 点的分辨率。同样,它是 10 点字体,并且 10/72 乘以每英寸 120 点等于 16 像素(如果你乡下舍入),它就是 tmHeight 减去 tmInternalLeading。12 点行间距等价于 20 像素,它是 tmHeight。(正如在第 4 章中,让我再次强调我正向你展示实际的度量以便你可以理解这是如何工作的。不要在你的程序中编码这些数字。)

  Figure 5-4. The large font and the FONTMETRIC fields. 图 5-4 大字体和 FONTMETRIC 的域   Within a Windows program you can use the GetDeviceCaps function to obtain the assumed resolution in dots per inch that the user selected in the Display applet of the Control Panel. To get these values—which in theory could be different if the video display doesn't have square pixels—you use the indices LOGPIXELSX and LOGPIXELSY. The name LOGPIXELS stands for "logical pixels," which basically means "not the actual resolution in pixels per inch." 在 Windows 程序内你可以用 GetDeviceCaps 函数获得以用户在控制面板的“显示”小程序中选择的每英寸点数的假定分辨率。为了获得这些值——如果视频显示器没有矩形像素,那么理论上它们可以是不同的——你使用索引 LOGPIXELSX 和 LOGPIXELSY。名称 LOGPIXELS 代表“逻辑像素”,它主要意味着“非实际的以每英寸像素的分辨率”。   The device capabilities that you obtain from GetDeviceCaps with the HORZSIZE and VERTSIZE indices are documented (as I indicated earlier) as "Width, in millimeters, of the physical screen" and "Height, in millimeters, of the physical screen." These should be documented as a "logical width" and a "logical height," because the values are derived from the HORZRES, VERTRES, LOGPIXELSX, and LOGPIXELSY values. The formulas are 你由有 HORZSIZE 和 VERTSIZE 索引的 GetDeviceCaps 获得的设备能力备有文档说明(正如我早先指出的)为“以毫米为单位的物理屏幕的宽度”和“以毫米为单位的物理屏幕的高度”。这些应该被文档说明为“逻辑宽度”和“逻辑高度”,因为这些值源自 HORZRES,VERTRES,LOGPIXELSX 和 LOGPIXELSY 值。公式是   Horizontal Size (mm) = 25.4 × Horizontal Resolution (pixels)/ Logical Pixels X (dots per inch) Vertical Size (mm) = 25.4 × Vertical Resolution (pixels)/ Logical Pixels Y (dots per inch)   The 25.4 constant is necessary to convert from inches to millimeters. 常量 25.4 对于由英寸转换为毫米是必要的。   This may seem backward and illogical. After all, your video display has a size in millimeters that you can actually measure with a ruler (at least approximately). But Windows 98 doesn't care about that size. Instead it calculates a display size in millimeters based on the pixel size of the display the user selects and also the resolution the user selects for sizing the system font. Change the pixel size of your display and according to GetDeviceCaps the metrical size changes. How much sense does that make? 你可能似乎是倒退和不合逻辑的。毕竟,你的视频显示器有你可以用尺子实际测量(至少大约地)的以毫米为单位的尺寸。但是 Windows 98 不关心那些尺寸。代替的它基于用户选择的显示器的像素尺寸和用户为缩放系统字体选择的分辨率计算以毫米为单位的显示器尺寸。改变你的显示器的像素尺寸并且依照 GetDeviceCaps 度量尺寸改变。那样做有多少认识?   It makes more sense than you might suspect. Let's suppose you have a 17-inch monitor. The actual display size will probably be about 12 inches by 9 inches. Suppose you were running Windows with the minimum required pixel dimensions of 640 by 480. This means that the actual resolution is 53 dots per inch. A 10-point font—perfectly readable on paper—on the screen would be only 7 pixels in height from the top of the A to the bottom of the q. Such a font would be ugly and just about unreadable. (Ask people who ran Windows on the old Color Graphics Adapter.) 它可能比你想到的有更多认识。让我们假定你有一个 17 英寸显示器。实际的显示尺寸将可能是大约 12 英寸 × 9 英寸。假设你正运行最少需要 640×480 像素尺寸的 Windows。这意味着实际分辨率是每英寸 53 点。10 点字体——在纸上更可读——在屏幕上从 A 的顶端到 q 的底端的高度将只有 7 像素。这样的字体将是难看的和几乎不可读的。(询问在旧的彩色图形适配器上运行 Windows 的人。)   Now hook up a video projector to your PC. Let's say the projected video display is a 4 feet wide and 3 feet high. That same 640 by 480 pixel dimension now implies a resolution of about 13 dots per inch. It would be ridiculous to try displaying a 10-point font under such conditions. 现在关注你的 PC 的视频放映机。让我们说放映视频显示器是 4 英尺宽和 3 英尺高。同样的 640×480 像素尺寸现在意味着大约每英寸 13 点的分辨率。它将在如此条件下可笑地尝试显示 10 点字体。   A 10-point font should be readable on the video display because it is surely readable when printed. The 10-point font thus becomes an important frame of reference. When a Windows application is guaranteed that a 10-point screen font is of average size, it can then display smaller (but still readable) text using an 8-point font and larger text using fonts of point sizes greater than 10. Thus, it makes sense that the video resolution (in dots per inch) be implied by the pixel size of that 10-point font. 10 点字体在视频显示器上应该是可读的,因为当打印时它的确可读。因此 10 点字体成为一个重要的参考框架。当 Windows 应用程序保证 10 点屏幕字体是平均大小时,它于是可以用 8 点字体显示更小的(但仍然可读的)文本而用比 10 大的点字体显示更大的文本。因此,可以理解为视频分辨率(以每英寸点为单位)由 10 点字体的像素大小暗指。   In Windows NT, however, an older approach is used in defining the HORZSIZE and VERTSIZE values. This approach is consistent with 16-bit versions of Windows. The HORZRES and VERTRES values still indicate the number of pixels horizontally and vertically (of course), and LOGPIXELSX and LOGPIXELSY are still related to the font that you choose when setting the video resolution in the Display applet of the Control Panel. As with Windows 98, typical values of LOGPIXELSX and LOGPIXELSY are 96 and 120 dots per inch, depending on whether you select a small font or large font. 然而,在 Windows NT 中,一个更老的方法是用定义 HORZSIZE 和 VERTSIZE 值。这个方式是和 16 位 Windows 一致的。HORZRES 和 VERTRES 只仍然指出水平地和垂直地(当然)像素数量,并且 LOGPIXELSX 和 LOGPIXELSY 仍然是和当你在控制面板的“显示”小程序中设置视频分辨率时选择的字体相关的。正如在 Windows 98 中,LOGPIXELSX 和 LOGPIXELSY 的典型值是每英寸 96 和 120 点,它依赖于你选择小字体或大字体。   The difference in Windows NT is that the HORZSIZE and VERTSIZE values are fixed to indicate a standard monitor size. For common adapters, the values of HORZSIZE and VERTSIZE you'll obtain are 320 and 240 millimeters, respectively. These values are the same regardless of what pixel dimension you choose. Therefore, these values are inconsistent with the values you obtain from GetDeviceCaps with the HORZRES, VERTRES, LOGPIXELSX, and LOGPIXELSY indices. However, you can always calculate HORZSIZE and VERTSIZE values like those you'd obtain under Windows 98 by using the formulas shown earlier. 在 Windows NT 中的区别是 HORZSIZE 和 VERTSIZE 值是固定的以指出标准显示器尺寸。对于普通的适配器,你将获得的 HORZSIZE 和 VERTSIZE 分别是 320 和 240 毫米。无论你选择什么像素尺寸这些值是相同的。这些值和你由有 HORZRES,VERTRES,LOGPIXELSX 和 LOGPIXELSY 索引获得的值是不一致的。然而,你可以总是计算 HORZSIZE 和 VERTSIZE 值,就像在 Windows 98 下你通过使用先前显示的公式获得的那样。   What if your program needs the actual physical dimensions of the video display? Probably the best solution is to actually request them of the user with a dialog box. 如果你的程序需要视频显示器实际的物理尺寸该怎么办?可能最好的解决办法是用对话框实际要求用户确定。   Finally, three other values from GetDeviceCaps are related to the video dimensions. The ASPECTX, ASPECTY, and ASPECTXY values are the relative width, height, and diagonal size of each pixel, rounded to the nearest integer. For square pixels, the ASPECTX and ASPECTY values will be the same. Regardless, the ASPECTXY value equals the square root of the sum of the squares of the ASPECTX and ASPECTY values, as you'll recall from Pythagoras. 最后,来自 GetDeviceCaps 的其它三个值是和视频尺寸相关的。ASPECTX,ASPECTY 和 ASPECTXY 值是每一个像素的相对宽度,高度和对角线尺寸,四舍五入到最近的整数。对于正方形像素,ASPECTX 和 ASPECTY 值将是相同的。不管怎样,ASPECTXY 值等于 ASPECTX 和 ASPECTY 值的正方形的和的平方根。   Finding Out About Color 关于颜色的发现   A video display capable of displaying only black pixels and white pixels requires only one bit of memory per pixel. Color displays require multiple bits per pixels. The more bits, the more colors; or more specifically, the number of unique simultaneous colors is equal to 2 to the number of bits per pixel. 只可以显示黑色像素和白色像素的视频显示器只需要每像素一位内存。彩色显示器需要每像素多个位。位越多,颜色越多;或者更明确地,唯一的同步颜色数量等于 2 的每像素位数次方。   A "full color" video display resolution has 24 bits per pixel—8 bits for red, 8 bits for green, and 8 bits for blue. Red, green, and blue are known as the "additive primaries." Mixes of these three primary colors can create many other colors, as you can verify by peering at your color video display through a magnifying glass. “全彩色”视频显示器分辩率有每像素 24 位——8 位用于红色,8 位用于绿色,8 位用于蓝色。红,绿和蓝被称作“附加的原色”。这三种原始颜色的混合可以创建许多其它的颜色,正如你可以通过经过放大镜看你的彩色显示器核实。   A "high color" display resolution has 16 bits per pixel, generally 5 bits for red, 6 bits for green, and 5 bits for blue. More bits are used for the green primary because the human eye is more sensitive to variations in green than to the other two primaries. “高彩色”显示器分辩率是每像素 16 位,通常地 5 位用于红色,6 位用于绿色,5 位用于蓝色。因为人眼对于绿色的变化比其它两种原始色更敏感,所以更多的位用于绿原色。   A video adapter that displays 256 colors requires 8 bits per pixel. However, these 8-bit values are generally indices into a palette table that defines the actual colors. I'll discuss this more in Chapter 16. 显示 256 色的视频适配器要求每像素 8 位。然而, 这 8 位值通常索引到定义实际颜色的调色板表中。我将在第 16 章中更多地讨论这个问题。   Finally, a video board that displays 16 colors requires 4 bits per pixel. These 16 colors are generally fixed as dark and light versions of red, green, blue, cyan, magenta, yellow, two shades of gray, black, and white. These 16 colors date back to the old IBM CGA. 最后,显示 16 色的视频板要求每像素 4 位。这 16 种颜色通常被固定为暗的和亮的红,绿,蓝,青,洋红,黄,二灰度梯度的灰,黑和白色。这 16 种颜色从旧的 IBM CGA 时代就有了。   Only in some odd programming jobs is it necessary to know how memory is organized on the video adapter board, but GetDeviceCaps will help you determine that. Video memory can be organized either with consecutive color bits for each pixel or with each color bit in a separate plane of memory. This call returns the number of color planes: 只有在一些临时的程序设计工作中知道内存是如何在视频适配器板上组织的是必要的,但是 GetDeviceCaps 将帮助你确定它。视频内存可以由每像素连续的颜色位或由在内存中分开平面的每个颜色位组织。这个调用返回颜色平面的数量:   iPlanes = GetDeviceCaps (hdc, PLANES) ;   and this call returns the number of color bits per pixel: 而这个调用返回每像素颜色位的数量:   iBitsPixel = GetDeviceCaps (hdc, BITSPIXEL) ;   One of these calls will return a value of 1. The number of colors that can be simultaneously rendered on the video adapter can be calculated by the formula 这两个调用之一将返回值 1。可以同时在视频适配器上着色的颜色的数量可以由公式   iColors = 1 << (iPlanes * iBitsPixel) ;   This value may or may not be the same as the number of colors obtainable with the NUMCOLORS argument: 计算;这个值可能或不可能与由 NUMCOLORS 参数获得的颜色数量相同:   iColors = GetDeviceCaps (hdc, NUMCOLORS) ;   I mentioned that 256-color video adapters use color palettes. In that case, GetDeviceCaps with the NUMCOLORS index returns the number of colors reserved by Windows, which will be 20. The remaining 236 colors can be set by a Windows program using the palette manager. For high-color and full-color display resolutions, GetDeviceCaps with the NUMCOLORS index often returns -1, making it a generally unreliable function for determining this information. Instead, use the iColors formula shown earlier that uses the PLANES and BITSPIXEL values. 我提到 256 色视频适配器用调色板。如果是那样的话,有 NUMCOLORS 索引的 GetDeviceCaps 返回由 Windows 保留的颜色数量,它将是 20。剩下的 236 种颜色可以由 Windows 程序用调色板管理器设置。对于高彩色和真彩色显示器分辩率,有 NUMCOLORS 索引的 GetDeviceCaps 常常返回 -1,对于确定这个信息它通常是不可靠的函数。代替的是,用早前显示的 iColors 公式使用 PLANES 和 BITSPIXEL 值。   In most GDI function calls, you use a COLORREF value (which is simply a 32-bit unsigned long integer) to refer to a particular color. The COLORREF value specifies a color in terms of red, green, and blue intensities and is often called an "RGB color." The 32 bits of the COLORREF value are set as shown in Figure 5-5. 在大多数 GDI 函数调用中,你用 COLOREF 值(它仅仅是一个 32 位的无符号长整型)引用特殊的颜色。COLORREF 值指定按照红,绿和蓝亮度配的颜色并且常常称作“RGB 颜色”。32 位的 COLOREF 值如图 5-5 中所示被设置。

Figure 5-5. The 32-bit COLORREF value. 图 5-5 32 位 COLOREF 值   Notice that the most-significant 8 bits are zero, and that each primary is specified as an 8-bit value. In theory, a COLORREF value can refer to 224 or about 16 million colors. 注意最重要的 8 位是零,并且每一个原始颜色被指定为 8 位值。理论上,COLOREF 值可以指定 224 或大约 16 百万颜色。   The Windows header file WINGDI.H provides several macros for working with RGB color values. The RGB macro takes three arguments representing red, green, and blue values and combines them into an unsigned long: Windows 头文件 WINGDI.H 提供了几个用于和 RGB 颜色值一起工作的宏。RGB 宏使用代表红,绿和蓝色值的三个参数并且将它们组合成一个无符号长整型:   #define RGB(r,g,b) ((COLORREF)(((BYTE)(r) | \ ((WORD)((BYTE)(g)) << 8)) | \ (((DWORD)(BYTE)(b)) << 16)))   Notice that the order of the three arguments is red, green, and blue. Thus, the value 注意三个参数的顺序是红,绿和蓝。因此,值   RGB (255, 255, 0)   is 0x0000FFFF or yellow—the combination of red and green. When all three arguments are set to 0, the color is black; when all the arguments are set to 255, the color is white. The GetRValue, GetGValue, and GetBValue macros extract the primary color values from a COLORREF value. These macros are sometimes handy when you're using a Windows function that returns RGB color values to your program. 是 0x0000FFFF 或黄色——红和绿的组合。当所有三个参数都被设置为 0 时,颜色是黑色;当所有三个参数都被设置为 255 时,颜色是白色。GetRValue,GetGValue 和 GetBValue 宏从 COLORREF 值提取出原始颜色值。当你使用返回 RGB 颜色值给你的程序的 Windows 函数时,这些宏有时是很方便的。   On 16-color or 256-color video adapters, Windows can use "dithering" to simulate more colors than the device can display. Dithering involves a small pattern that combines pixels of different colors. You can determine the closest pure nondithered color of a particular color value by calling GetNearestColor: 在 16 色或 256 色视频适配器上,Windows 可以使用“抖动”模拟比设备可以显示的颜色更多的颜色。“抖动”包含一个小的组合不同颜色的像素的模式。你可以通过调用 GetNearestColor 确定最接近纯的特殊颜色值的非抖动颜色:   crPureColor = GetNearestColor (hdc, crColor) ;   The Device Context Attributes 关联设备属性   As I noted above, Windows uses the device context to store "attributes" that govern how the GDI functions operate on the display. For instance, when you display some text using the TextOut function, you don't have to specify the color of the text or the font. Windows uses the device context to obtain this information. 正如我上面提到的,Windows 使用关联设备存储管理 GDI 函数如何在显示器上操作的“属性”。例如,当你用 TextOut 函数显示一些文本时,你不必指定文本或字体的颜色。Windows 使用关联设备获得这个信息。   When a program obtains a handle to a device context, Windows sets all the attributes to default values. (However, see the next section for how to override this behavior.) The following table shows many of the device context attributes supported under Windows 98, along with the default values and the functions to change or obtain their values. 当程序获得关联设备的句柄时,Windows 将所有的属性设置为缺省值。(然而,参看下一节如何越过这个行为。)下表显示在 Windows 98 下许多关联设备的属性,连同缺省值和改变或获得这些值的函数。

Device Context Attribute Default Function(s) to Change Function to Obtain Mapping Mode MM_TEXT SetMapMode GetMapMode Window Origin (0, 0) SetWindowOrgEx

OffsetWindowOrgEx

GetWindowOrgEx Viewport Origin (0, 0) SetViewportOrgEx

OffsetViewportOrgEx

GetViewportOrgEx Window Extents (1, 1)

SetWindowExtEx

SetMapMode

ScaleWindowExtEx

GetWindowExtEx Viewport Extents (1, 1) SetViewportExtEx SetMapMode ScaleViewportExtEx GetViewportExtEx Pen BLACK_PEN SelectObject SelectObject Brush WHITE_BRUSH SelectObject SelectObject Font SYSTEM_FONT SelectObject SelectObject Bitmap None SelectObject SelectObject Current Position (0, 0) MoveToEx

LineTo

PolylineTo

PolyBezierTo

GetCurrentPositionEx Background Mode OPAQUE SetBkMode GetBkMode Background Color White SetBkColor GetBkColor Text Color Black SetTextColor GetTextColor Drawing Mode R2_COPYPEN SetROP2 GetROP2 Stretching Mode BLACKONWHITE SetStretchBltMode GetStretchBltMode Polygon Fill Mode ALTERNATE SetPolyFillMode GetPolyFillMode Intercharacter Spacing 0 SetTextCharacterExtra GetTextCharacterExtra Brush Origin (0, 0) SetBrushOrgEx GetBrushOrgEx Clipping Region None

SelectObject

SelectClipRgn

IntersectClipRgn

OffsetClipRgn

ExcludeClipRect

SelectClipPath

GetClipBox Saving Device Contexts 保存关联设备   Normally when you call GetDC or BeginPaint, Windows gives you a device context with default values for all the attributes. Any changes you make to the attributes are lost when the device context is released with the ReleaseDC or EndPaint call. If your program needs to use nondefault device context attributes, you'll have to initialize the device context every time you obtain a new device context handle: 通常当你调用 GetDC 或 BeginPaint 时,Windows 给你一个有所有属性缺省值的关联设备。当关联设备被用 ReleaseDC 或 EndPaint 调用释放时,你对属性做的任何改变都是失败的。如果你的程序需要使用非缺省的关联设备属性,那么每当你获得新的关联设备句柄时你将不得不初始化该关联设备句柄:

case WM_PAINT:         hdc = BeginPaint (hwnd, &ps) ;         [initialize device context attributes 初识关联设备属性]          [paint client area of window 绘制窗口客户区]         EndPaint (hwnd, &ps) ;         return 0 ;
Although this approach is generally satisfactory, you might prefer that changes you make to the attributes be saved when you release the device context so that they will be in effect the next time you call GetDC or BeginPaint. You can accomplish this by including the CS_OWNDC flag as part of the window class style when you register the window class: 尽管这个方法通常是令人满意的,但是你可能更喜欢在你释放关联设备时你对属性做的改变被保存,以便在你下一次调用 GetDC 或 BeginPaint 时它们是有效的。当你注册窗口类时,你可以通过包含 CS_OWNDC 标志作为窗口类风格的一部分完成它:   wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC ;   Now each window that you create based on this window class will have its own private device context that continues to exist when the window is destroyed. When you use the CS_OWNDC style, you need to initialize the device context attributes only once, perhaps while processing the WM_CREATE message: 现在你基于该窗口类创建的每一个窗口将有它们自己私有的关联设备,当窗口被销毁时它们继续存在。当你使用 CS_OWNDC 风格时,你只需要初始化关联设备属性一次,也许是在处理 WM_CREATE 消息 时:   case WM_CREATE:         hdc = GetDC (hwnd) ;         [initialize device context attributes 初始化关联设备属性]         ReleaseDC (hwnd, hdc) ;
The attributes continue to be valid until you change them. 这些属性继续是有效的,知道你改变它们。   The CS_OWNDC style affects only the device contexts retrieved from GetDC and BeginPaint and not device contexts obtained from the other functions (such as GetWindowDC). Employing CS_OWNDC was once discouraged because it required some memory overhead; nowadays it can improve performance in some graphics-intensive Windows NT applications. Even if you use CS_OWNDC, you should still release the device context handle before exiting the window procedure. CS_OWNDC 风格只影响由 GetDC 和 BeginPaint 保留而不是由其他函数(比如 GetWindowDC)获得的关联设备。使用 CS_OWNDC 曾经是令人气馁的,因为它要求需要一些额外的内存;现在在一些多图形的 Windows NT 应用程序中它可以提高性能。即使你使用 CS_OWNDC,你仍然应该在退出窗口处理函数之前释放关联设备句柄。   In some cases you might want to change certain device context attributes, do some painting using the changed attributes, and then revert to the original device context. To simplify this process, you save the state of a device context by calling 在某些情况下你可能想改变某个关联设备属性并用改变的属性做一些绘图,然后回复到原来的关联设备。为了简化这个处理,你通过调用   idSaved = SaveDC (hdc) ;   Now you can change some attributes. When you want to return to the device context as it existed before the SaveDC call, you use 保存关联设备的状态;现在你可以改变某些属性。当你想要返回 SaveDC 调用之前存在的关联设备时,你用   RestoreDC (hdc, idSaved) ;   You can call SaveDC any number of times before you call RestoreDC. 你可以在调用 RestroeDC 之前调用 SaveDC 许多次。   Most programmers use SaveDC and RestoreDC in a different manner, however, much like PUSH and POP instructions in assembly language. When you call SaveDC, you don't need to save the return value: 然而许多程序员以不同的方式使用 SaveDC 和 RestoreDC,非常像汇编语言中 PUSH 和 POP 用法。当你调用 SaveDC 时,你不需要保存该返回值:   SaveDC (hdc) ;   You can then change some attributes and call SaveDC again. To restore the device context to a saved state, call 然后你可以改变一些属性并再次调用 SaveDC。为了恢复关联设备到保存的状态,调用   RestoreDC (hdc, -1) ;   This restores the device context to the state saved by the most recent SaveDC function. 这将恢复关联设备到由最近的 SaveDC 函数保存的状态。

本文地址:http://com.8s8s.com/it/it26608.htm