Chapter 5 Basic Drawing 第五章 绘图基础 — Drawing Filled Areas - 绘制已填充的区域

类别:编程语言 点击:0 评论:0 推荐:
ps:您可以转载,但请注明出处;你可以修改,但请将修改结果告诉我。
  Drawing Filled Areas 绘制已填充的区域   The next step up from drawing lines is filling enclosed areas. Windows' seven functions for drawing filled areas with borders are listed in the table below. 绘制完线的下一步是填充封闭的区域。Windows 的七个用于绘制有边界的已填充区域的函数在下表中列出。

Function Figure Rectangle Rectangle with square corners 直角矩形 Ellipse Ellipse 椭圆 RoundRect Rectangle with rounded corners 圆角矩形 Chord Arc on the circumference of an ellipse with endpoints connected by a chord 端点由弦连接的椭圆的周围的弧 Pie Pie wedge defined by the circumference of an ellipse 由椭圆的周围定义的扇形 Polygon Multisided figure 多边形 PolyPolygon Multiple multisided figures 多个多边形 Windows draws the outline of the figure with the current pen selected in the device context. The current background mode, background color, and drawing mode are all used for this outline, just as if Windows were drawing a line. Everything we learned about lines also applies to the borders around these figures. Windows 用选进关联设备的当前画笔绘制图形的轮廓。当前背景模式,背景颜色和绘制模式都用于这个轮廓,正如 Windows 绘制线。我们学到的关于线的所有东西也适用于这些图形周围的边框。   The figure is filled with the current brush selected in the device context. By default, this is the stock object called WHITE_BRUSH, which means that the interior will be drawn as white. Windows defines six stock brushes: WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH, DKGRAY_BRUSH, BLACK_BRUSH, and NULL_BRUSH (or HOLLOW_BRUSH). You can select one of the stock brushes into the device context the same way you select a stock pen. Windows defines HBRUSH to be a handle to a brush, so you can first define a variable for the brush handle: 图形由当前选进关联设备的画刷填充。缺省情况下,这是一个叫做 WHITE_BRUSH 的备用对象,这意味着内部对象将被绘制为白色。Windows 定义了六个备用对象:WHITE_BRUCH,LTGRAY_BRUSH,GRAY_BRUSH,DKGRAY_BRUSH,BLACK_BRUSH 和 NULL_BRUSH(或 HOLLOW_BRUSH)。你可以和你选择备用画笔一样选择这些被用画刷之一进入关联设备。Windows 定义 HBRUSH 为画刷的句柄,因此你可以首先定义一个画刷句柄的变量:   HBRUSH hBrush ;   You can get the handle to the GRAY_BRUSH by calling GetStockObject: 你可以通过调用 GetStrockObject 获得 GRAY_BRUSH 的句柄:   hBrush = GetStockObject (GRAY_BRUSH) ;   You can select it into the device context by calling SelectObject: 你可以通过调用 SelectObject 选择它进关联设备:   SelectObject (hdc, hBrush) ;   Now when you draw one of the figures listed above, the interior will be gray. 现在当你绘制上面列出的图形之一时,内部将是灰色的。   To draw a figure without a border, select the NULL_PEN into the device context: 为了绘制没有边框的图形,选择 NULL_PEN 进关联设备:   SelectObject (hdc, GetStockObject (NULL_PEN)) ;   If you want to draw the outline of the figure without filling in the interior, select the NULL_BRUSH into the device context: 如果你想绘制没有在内部填充的图形的轮廓,那么选择 NULL_BRUSH 进关联设备:   SelectObject (hdc, GetStockobject (NULL_BRUSH) ;   You can also create customized brushes just as you can create customized pens. We'll cover that topic shortly. 你也可以像创建自定义画笔一样创建自定义画刷。不久我们将讨论该主题。   The Polygon Function and the Polygon-Filling Mode Polygon 函数和 Polygon-Filling 模式   I've already discussed the first five area-filling functions. Polygon is the sixth function for drawing a bordered and filled figure. The function call is similar to the Polyline function: 我已经讨论前五个区域填充函数。Polygon 是第六个用于绘制有边框的和已填充的图形的函数。该函数调用类似于 Polyline 函数:   Polygon (hdc, apt, iCount) ;   The apt argument is an array of POINT structures, and iCount is the number of points. If the last point in this array is different from the first point, Windows adds another line that connects the last point with the first point. (This does not happen with the Polyline function.) The PolyPolygon function looks like this: apt 参数是 POINT 结构的数组,而 iCount 是点的数量。如果这个数组中最后一个点不同于第一个点,那么 Windows 增加另一条连接最后一个点和第一个点的线。(这不会发生在 Polyline 函数上。)PolyPolygon 函数看起来像这样:   PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;   The function draws multiple polygons. The number of polygons it draws is given as the last argument. For each polygon, the aiCounts array gives the number of points in the polygon. The apt array has all the points for all the polygons. Aside from the return value, PolyPolygon is functionally equivalent to the following code: 该函数绘制多个多边形。它绘制的多边形的数量由最后一个参数给出。对于每一个多边形,aiCount 数组给出了多边形中点的数量。apt 数组有用于所有多边形的所有点。除返回值以外,PolyPolygon 功能上等价于下面的代码:   for (i = 0, iAccum = 0 ; i < iPolyCount ; i++) {         Polygon (hdc, apt + iAccum, aiCounts[i]) ;     iAccum += aiCounts[i] ; }   For both Polygon and PolyPolygon, Windows fills the bounded area with the current brush defined in the device context. How the interior is filled depends on the polygon-filling mode, which you can set using the SetPolyFillMode function: 对于 Polygon 和 PolyPolygon,Windows 用当前在关联设备中定义的画刷填充有边界的区域。内部如何被填充依赖于多边形填充模式,你可以用 SetPolyFillMode 函数设置它:   SetPolyFillMode (hdc, iMode) ;   By default, the polygon-filling mode is ALTERNATE, but you can set it to WINDING. The difference between the two modes is shown in Figure 5-19. 缺省情况下,多边形填充模式是 ALTERNATE,但是你可以设置它为 WINDING。这两种模式之间的区别在图 5-19 中显示。   Figure 5-19. Figures drawn with the two polygon-filling modes: ALTERNATE (left) and WINDING (right). 图 5-19 用这两种多边形填充模式绘制的图形:ALTERNATE(左)和 WINDING(右)   At first, the difference between alternate and winding modes seems rather simple. For alternate mode, you can imagine a line drawn from a point in an enclosed area to infinity. The enclosed area is filled only if that imaginary line crosses an odd number of boundary lines. This is why the points of the star are filled but the center is not. 起先,ALTERNATE 和 WINDING 模式之间的区别似乎有点简单。对于 ALTERNATE 模式,你可以想象一条从封闭区域内的一点到无穷远处绘制的线。封闭区域只在如果想象的线与边界线的奇数数量交叉时才被填充。这就是星的点被填充而中心没有的原因。   The example of the five-pointed star makes winding mode seem simpler than it actually is. When you're drawing a single polygon, in most cases winding mode will cause all enclosed areas to be filled. But there are exceptions. 五个点的星的例子使得 WINDING 模式似乎比它实际上更简单。当你正在绘制一个单独的多边形时,在大多数情况下 WINDING 模式将使得所有封闭区域被填充。但是有些例外。   To determine whether an enclosed area is filled in winding mode, you again imagine a line drawn from a point in that area to infinity. If the imaginary line crosses an odd number of boundary lines, the area is filled, just as in alternate mode. If the imaginary line crosses an even number of boundary lines, the area can either be filled or not filled. The area is filled if the number of boundary lines going in one direction (relative to the imaginary line) is not equal to the number of boundary lines going in the other direction. 为了确定封闭区域是否以 WINDING 模式填充,你再想象一条从该区域内的点到无穷远处绘制的线。如果想象的线交叉过一条奇数的边界线,那么区域是已填充的,正如在 ALTERNATE 模式中。如果想象的线交叉过一条偶数的边界线,那么该区域可以是已填充的或未填充的。如果朝一个方向(相对于想象的线)的边界线的数量不等于朝其它方向的边界线的数量,那么该区域是已填充的。   For example, consider the object shown in Figure 5-20. The arrows on the lines indicate the direction in which the lines are drawn. Both winding mode and alternate mode will fill the three enclosed L-shaped areas numbered 1 through 3. The two smaller interior areas, numbered 4 and 5, will not be filled in alternate mode. But in winding mode, area number 5 is filled because you must cross two lines going in the same direction to get from the inside of that area to the outside of the figure. Area number 4 is not filled. You must again cross two lines, but the two lines go in opposite directions. 例如,考察在图 5-20 中显示的对象。箭头的方向指出这些线以什么方向绘制。WINDING 模式和 ALTERNATE 模式都将填充这三个编号 1 到 3 的封闭的 L 形。两个编号为 4 和 5 的较小的内部区域将不以 ALTERNATE 模式填充。但是在 WINDING 模式中,编号 5 的区域是已填充的,因为你必须朝和从该区域内部到图形外部相同的方向交叉两条线。编号 4 的区域不是已填充的。你必须再交叉两条线,但是这两条线朝不同的方向。   If you doubt that Windows is clever enough to do this, the ALTWIND program in Figure 5-21 demonstrates that it is. 如果你怀疑 Windows 足够聪明到这样做,那么在图 5-21 中的 ALTWIND 程序演示了这一过程。   Figure 5-20. A figure in which winding mode does not fill all interior areas. 图 5-20 WINDING 模式不填充所有内部区域的图形   Figure 5-21. The ALTWIND program. 图 5-21 ALTWIND 程序

ALTWIND.C

/*----------------------------------------------- ALTWIND.C -- Alternate and Winding Fill Modes (c) Charles Petzold, 1998 -----------------------------------------------*/ #include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("AltWind") ; 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 ("Program requires Windows NT!"), szAppName, MB_ICONERROR) ; return 0 ; } hwnd = CreateWindow (szAppName, TEXT ("Alternate and Winding Fill Modes"), 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 POINT aptFigure [10] = { 10,70, 50,70, 50,10, 90,10, 90,50, 30,50, 30,90, 70,90, 70,30, 10,30 }; static int cxClient, cyClient ; HDC hdc ; int i ; PAINTSTRUCT ps ; POINT apt[10] ; switch (message) { case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; SelectObject (hdc, GetStockObject (GRAY_BRUSH)) ; for (i = 0 ; i < 10 ; i++) { apt[i].x = cxClient * aptFigure[i].x / 200 ; apt[i].y = cyClient * aptFigure[i].y / 100 ; } SetPolyFillMode (hdc, ALTERNATE) ; Polygon (hdc, apt, 10) ; for (i = 0 ; i < 10 ; i++) { apt[i].x += cxClient / 2 ; } SetPolyFillMode (hdc, WINDING) ; Polygon (hdc, apt, 10) ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: PostQuitMessage (0) ; return 0 ; } return DefWindowProc (hwnd, message, wParam, lParam) ; }

The coordinates of the figure—scaled to an arbitrary 100-unit-by-100-unit area—are stored in the aptFigure array. These coordinates are scaled based on the width and height of the client area. The program displays the figure twice, once using the ALTERNATE filling mode and then using WINDING. The results are shown in Figure 5-22. 图形的坐标——按任意 100单位×100单位 成比例的区域——存储在 aptFigure 数组。这些坐标是基于客户区的宽度和高度成比例的。程序显示图形两次,一次用 ALTERNATE 填充模式而另一次用 WINDING。结果在图 5-22 中显示。   Figure 5-22. The ALTWIND display. 图 5-22 ALTWIND 显示   Brushing the Interior 刷内部   The interiors of the Rectangle, RoundRect, Ellipse, Chord, Pie, Polygon, and PolyPolygon figures are filled with the current brush (sometimes also called a "pattern") selected in the device context. A brush is a small 8-pixel-by-8-pixel bitmap that is repeated horizontally and vertically to fill the area. Rectangle,RoundRect,Ellipse,Chord,Pie,Polygon 和 PolyPolygon 图形的内部是已用当前选进关联设备的画刷(有时也叫做“模式”)填充的。画刷是一个小的 8像素×8像素的位图,它是水平地和垂直地重复填充区域。   When Windows uses dithering to display more colors than are normally available on a display, it actually uses a brush for the color. On a monochrome system, Windows can use dithering of black and white pixels to create 64 different shades of gray. More precisely, Windows can create 64 different monochrome brushes. For pure black, all bits in the 8-by-8 bitmap are 0. One bit out of the 64 is made 1 (that is, white) for the first gray shade, two bits are white for the second gray shade, and so on, until all bits in the 8-by-8 bitmap are 1 for pure white. With a 16-color or 256-color video system, dithered colors are also brushes and Windows can display a much wider range of color than would normally be available. 当 Windows 用抖动显示比通常在显示器上可用的更多的颜色时,它实际上用该颜色的画刷。在单色系统上,Windows 可以用抖动的黑色和白色像素创建 64 种不同的灰色梯度。更好的是,Windows 可以创建 64 种不同的单色画刷。对于纯的黑色,所有在 8×8 位图中的位都是 0。64 之外的一位是使 1(也就是白色)作为第一个灰色梯度,两位是作为第二个灰色梯度的白色,诸如此类,直到 8×8 位图中所有位是用于纯的白色的 1。对于 16 色或 256 色视频系统,抖动的颜色也是画刷并且 Windows 可以显示比通常可用的更宽范围的颜色。   Windows has five functions that let you create logical brushes. You select the brush into the device context with SelectObject. Like logical pens, logical brushes are GDI objects. Any brush that you create must be deleted, but it must not be deleted while it is selected in a device context. Windows 有五个让你创建逻辑画刷的函数。你用 SelectObject 选择画刷进入关联设备。就像逻辑画笔一样,逻辑画刷是 GDI 对象。任何你创建的画刷必须被删除,但是当它被选进关联设备时一定不可以被删除。   Here's the first function to create a logical brush: 这是第一个创建逻辑画刷的函数:   hBrush = CreateSolidBrush (crColor) ;   The word Solid in this function doesn't really mean that the brush is a pure color. When you select the brush into the device context, Windows may create a dithered bitmap and use that for the brush. 在这个函数中的单词 Solid 不是真的意味着画刷是纯色的。当你选择画刷进入关联设备时,Windows 可能创建一个抖动的位图并且将它用作画刷。   You can also create a brush with "hatch marks" made up of horizontal, vertical, or diagonal lines. Brushes of this style are most commonly used for coloring the interiors of bar graphs and when drawing to plotters. The function for creating a hatch brush is 你也可以用由水平的,垂直的或斜线组成的“hatch 标记”创建画刷。这个风格的画刷大多通常用于对 bar 图形的内部着色和当绘制到绘图机上时。用于创建“hatch”画刷的函数时   hBrush = CreateHatchBrush (iHatchStyle, crColor) ;   The iHatchStyle argument describes the appearance of the hatch marks. Figure 5-23 shows the six available hatch style constants and what they look like. iHatchStyle 参数描述了“hatch”标记的外观。图 5-23 显示了六个可用的“hatch”风格常量和它们看起来的样子。   Figure 5-23. The six hatch brush styles. 图 5-23 六种“hatch”画刷风格   The crColor argument to CreateHatchBrush specifies the color of the hatch lines. When you select the brush into a device context, Windows converts this color to the nearest pure color available on the display. The area between the hatch lines is colored based on the current background mode and the background color. If the background mode is OPAQUE, the background color (which is also converted to a pure color) is used to fill in the spaces between the lines. If the background mode is TRANSPARENT, Windows draws the hatch lines without filling in the area between them. CreateHatchBrush 的 crColor 参数指定“hatch”线的颜色。当你选择画刷进关联设备时,Windows 将这种颜色转换为在显示器上可用的最近的纯色。“hatch”线之间的区域基于当前背景模式和背景颜色着色。如果背景模式是 OPAQUE,那么背景颜色(它也转换为纯色)用于填充线之间的空间。如果背景模式是 TRANSPARENT,那么 Windows 绘制“hatch”线而不在它们之间的区域中填充。   You can also create your own brushes based on bitmaps using CreatePatternBrush and CreateDIBPatternBrushPt. The fifth function for creating a logical brush encompasses the other four functions: 你也可以用 CreatePatternBrush 和 CreateDIBPatternBrushPt 创建你自己的基于位图的画刷。创建逻辑画刷的第五个函数包含其它四个函数:   hBrush = CreateBrushIndirect (&logbrush) ;   The logbrush variable is a structure of type LOGBRUSH ("logical brush"). The three fields of this structure are shown below. The value of the lbStyle field determines how Windows interprets the other two fields: logbrush 变量是 LOGBRUSH(“逻辑画刷”)类型的结构。该结构的三个域在下面显示。lbStyle 域的值决定 Windows 如何解释其它两个域:

lbStyle (UINT) lbColor (COLORREF) lbHatch (LONG) BS_SOLID Color of brush Ignored BS_HOLLOW Ignored Ignored BS_HATCHED Color of hatches Hatch brush style BS_PATTERN Ignored Handle to bitmap BS_DIBPATTERNPT Ignored Pointer to DIB   Earlier we used SelectObject to select a logical pen into a device context, DeleteObject to delete a logical pen, and GetObject to get information about a logical pen. You can use these same three functions with brushes. Once you have a handle to a brush, you can select the brush into a device context using SelectObject: 先前我用 SelectObject 选择逻辑画笔进入关联设备,用 DeleteObject 删除逻辑画笔,而用 GetObject 获得关于逻辑画笔的信息。你可以将这三个函数用于画刷。一旦你有画刷的句柄,那么你可以用 SelectObject 选择画刷进入关联设备:   SelectObject (hdc, hBrush) ;   You can later delete a created brush with the DeleteObject function: 你可以随后用 DeleteObject 函数删除已创建的画刷:   DeleteObject (hBrush) ;   Do not delete a brush that is currently selected in a device context. 不要删除当前选进关联设备的画刷。   If you need to obtain information about a brush, you can call GetObject: 如果你需要获得关于画刷的信息,那么你可以调用 GetObject:   GetObject (hBrush, sizeof (LOGBRUSH), (LPVOID) &logbrush) ;   where logbrush is a structure of type LOGBRUSH. 这里 logbrush 是 LOGBRUSH 类型的结构。

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