第五章 图像基础(绘制填入区域)
来源:互联网 发布:热血三国马装数据 编辑:程序博客网 时间:2024/05/29 08:37
绘制填入区域
现在再更进一步,从画线到画图形。Windows中七个用来画带边缘的填入图形的函数列于表5-3中。
表5-3
函数
图形
Rectangle
直角矩形
Ellipse
椭圆
RoundRect
圆角矩形
Chord
椭圆周上的弧,两端以弦连接
Pie
椭圆上的饼图
Polygon
多边形
PolyPolygon
多个多边形
Windows用设备内容中选择的目前画笔来画图形的边界框,边界框还使用目前背景方式、背景色彩和绘图方式,这跟Windows画线时一样。关于直线的一切也适用于这些图形的边界框。
图形以目前设备内容中选择的画刷来填入。内定情况下,使用现有对象,这意味着图形内部将画为白色。Windows定义六种现有画刷:WHITE_BRUSH、LTGRAY_BRUSH、GRAY_BRUSH、DKGRAY_BRUSH、BLACK_BRUSH和NULL_BRUSH (也叫HOLLOW_BRUSH)。您可以将任何一种现有画刷选入您的设备内容中,就和您选择一种画笔一样。Windbws将HBRUSH定义为画刷的句柄,所以可以先定义一个画刷句柄变量:
HBRUSH hBrush ;
您可以通过呼叫GetStockObject来取得GRAY_BRUSH的句柄:
hBrush = GetStockObject (GRAY_BRUSH) ;
您可以呼叫SelectObject将它选进设备内容:
SelectObject (hdc, hBrush) ;
现在,如果您要画上表中的任一个图形,则其内部将为灰色。
如果您想画一个没有边界框的图形,可以将NULL_PEN选进设备内容:
SelectObject (hdc, GetStockObject (NULL_PEN)) ;
如果您想画出图形的边界框,但不填入内部,则将NULL_BRUSH选进设备内容:
SelectObject (hdc, GetStockobject (NULL_BRUSH) ;
您也可以自订画刷,就如同您自订画笔一样。我们将马上谈到这个问题。
Polygon函数和多边形填入方式
我已经讨论过了前五个区域填入函数,Polygon是第六个画带边界框的填入图形的函数,该函数的呼叫与Polyline函数相似:
Polygon (hdc, apt, iCount) ;
其中,apt参数是POINT结构的一个数组,iCount是点的数目。如果该数组中的最后一个点与第一个点不同,则Windows将会再加一条线,将最后一个点与第一个点连起来(在Polyline函数中,Windows不会这么做)。PolyPolygon函数如下所示:
PolyPolygon (hdc, apt, aiCounts, iPolyCount) ;
该函数绘制多个多边形。最后一个参数给出了所画的多边形的个数。对于每个多边形,aiCounts数组给出了多边形的端点数。apt数组具有全部多边形的所有点。除传回值以外,PolyPolygon在功能上与下面的代码相同:
for (i = 0, iAccum = 0 ; i < iPolyCount ; i++)
{
Polygon (hdc, apt + iAccum, aiCounts[i]) ;
iAccum += aiCounts[i] ;
}
对于Polygon和PolyPolygon函数,Windows使用定义在设备内容中的目前画刷来填入这个带边界的区域。至于填入内部的方式,则取决于多边形填入方式,您可以用SetPolyFillMode函数来设定:
SetPolyFillMode (hdc, iMode) ;
内定情况下,多边形填入方式是ALTERNATE,但是您可以将它设定为WINDING。两种方式的区别参见图5-15所示。
图5-15 用两种多边形填入方式画出的图:ALTERNATE(左)和WINDING(右)
首先,ALTERNATE和WINDING方式之间的区别很容易察觉。对于ALTERNATE方式,您可以设想从一个无穷大的封闭区域内部的点画线,只有假想的线穿过了奇数条边界线时,才填入封闭区域。这就是填入了星的角而中心没被填入的原因。
五角星的例子使得WINDING方式看起来比实际上更简单一些。在绘制单个的多边形时,大多数情况下,WINDING方式会填入所有封闭的区域。但是也有例外。
在WINDING方式下要确定一个封闭区域是否被填入,您仍旧可以设想从那个无穷大的区域画线。如果假想的线穿过了奇数条边界线,区域就被填入,这和ALTERNATE方式一样。如果假想的线穿过了偶数条边界线,则区域可能被填入也可能不被填入。如果一个方向(相对于假想线)的边界线数与另一个方向的边界线数不相等,就填入区域。
例如,考虑图5-16中的物体。在线的箭头指出了画线的方向。两种方式都会填入三个封闭的L形区域,号码从1到3。号码为4和5的两个小内部区域,在ALTERNATE方式下不会被填入。但是,在WINDING方式下,号码为5的区域会被填入,因为从区域内必须穿过两条相同方向的线才能到达图形外部。号码为4的区域不会被填入,因为必须穿过两条方向相反的线。
如果您怀疑Windows没有这么聪明,那么程序5-5 ALTWIND会展示给您看。
图5-16 WINDING方式不能填入所有内部区域的图形
程序5-5 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) ;
}
图形的坐标(划分为100×100个单位)储存在aptFigure数组中。这些坐标是依据显示区域的宽度和高度划分的。程序显示图形两次,一次使用ALTERNATE填入方式,另一次使用WINDING方式。结果见图5-17。
图5-17 ALTWIND的显示
用画刷填入内部
Rectangle、RoundRect、Ellipse、Chord、Pie、Polygon和PolyPolygon图形的内部是用选进设备内容的目前画刷(也称为「图样」)来填入的。画刷是一个8×8的位图,它水平和垂直地重复使用来填入内部区域。
当Windows用混色的方法来显示多于可从显示器上得到的色彩时,实际上是将画刷用于色彩。在单色系统上,Windows能够使用黑色和白色图素的混色建立64种不同的灰色,更精确地说,Windows能够建立64种不同的单色画刷。对于纯黑色,8×8位图中的所有位均为0。第一种灰色有一位为1,第二种灰色有两位为1,以此类推,直到8×8位图中所有位均为1,这就是白色。在16色或256色显示系统上,混色也是位图,并且可以得到更多的色彩。
Windows还有五个函数,可以让您建立逻辑画刷,然后就可使用SelectObject将画刷选进设备内容。与逻辑画笔一样,逻辑画刷也是GDI对象。您建立的所有画刷都必须被删除,但是当它还在设备内容中时不能将其删除。
下面是建立逻辑画刷的第一个函数:
hBrush = CreateSolidBrush (crColor) ;
函数中的Solid并不是指画刷为纯色。在将画刷选入设备内容中时,Windows建立一个混色色的位图,并为画刷使用该位图。
您还可以使用由水平、垂直或者倾斜的线组成的「影线标记(hatch marks)」来建立画刷,这种风格的画刷对着色条形图的内部和在绘图机上进行绘图最有用。建立影线画刷的函数为:
hBrush = CreateHatchBrush (iHatchStyle, crColor) ;
iHatchStyle参数描述影线标记的外观。图5-18显示了六种可用的影线标记风格。
图5-18 六种影线画刷风格
CreateHatchBrush中的crColor参数是影线的色彩。在将画刷选进设备内容时,Windows将这种色彩转换为与之最相近的纯色。影线之间的区域根据设备内容中定义的背景方式和背景色来着色。如果背景方式为OPAQUE,则用背景色(它也被转换为纯色)来填入线之间的空间。在这种情况下,影线和填入色都不能是混色而成的颜色。如果背景方式为TRANSPARENT,则Windows只画出影线,不填入它们之间的区域。
您也可以使用CreatePatternBrush和CreateDIBPatternBrushPt建立自己的位图画刷。
建立逻辑画刷的第五个函数包含其它四个函数:
hBrush = CreateBrushIndirect (&logbrush) ;
变量logbrush是一个型态为LOGBRUSH(「逻辑画刷」)的结构,该结构的三个字段如表5-4所示,lbStyle字段的值确定了Windows如何解释其它两个字段的值:
表5-4
lbStyle (UINT)
lbColor (COLORREF)
lbHatch (LONG)
BS_SOLID
画刷的色彩
忽略
BS_HOLLOW
忽略
忽略
BS_HATCHED
影线的色彩
影线画刷风格
BS_PATTERN
忽略
位图的句柄
BS_DIBPATTERNPT
忽略
指向DIB的指标
前面我们用SelectObject将逻辑画笔选进设备内容,用DeleteObject删除画笔,用GetObject来取得逻辑画笔的信息。对于画刷,同样能使用这三个函数。一旦您取得到了画刷句柄,就可以使用SelectObject将该画刷选进设备内容:
SelectObject (hdc, hBrush) ;
然后,您可以使用DeleteObject函数删除所建立的画刷:
DeleteObject (hBrush) ;
但是,不要删除目前选进设备内容的画刷。
如果您需要取得画刷的信息,可以呼叫GetObject:
GetObject (hBrush, sizeof (LOGBRUSH), (LPVOID) &logbrush) ;
其中,logbrush是一个型态为LOGBRUSH的结构。
- 第五章 图像基础(绘制填入区域)
- 画线,绘制填入区域
- 第五章 图像基础(矩形、区域和剪裁)
- 绘制填入区域 之 ALTERNATE 与 WINDING
- 第26周-window程序设计(基础篇)-第5章(图形基础)-填入空隙和填入区域
- 绘制填入区域 之 ALTERNATE 与 WINDING 的解释
- 第五章 图像基础(设备内容)
- 第五章 图像基础(GDI 映像方式)(1)
- 第五章 图像基础(GDI 映像方式)(2)
- 第五章 图像基础(GDI 的结构)
- 如何使用图像绘制区域wpf
- 第五章 绘图基础 (GDI、设备环境、点线绘制、填充)
- OPENCV图像处理基础(二)感兴趣区域ROI
- 利用鼠标绘制矩形和截取图像的矩形区域并保存(OpenCV2.4.5)
- Halcon学习之八:图像区域叠加与绘制
- OpenCV鼠标绘制矩形和截取图像的矩形区域
- opencv鼠标绘制矩形和截取图像的矩形区域
- 第五章 图像数据压缩
- 切换数据挖掘系统后台有感---我也谈一次“架构”
- 复习15:类的层次结构
- 第五章 图像基础(GDI 映像方式)(1)
- 第五章 图像基础(GDI 映像方式)(2)
- 第五章 图像基础(矩形、区域和剪裁)
- 第五章 图像基础(绘制填入区域)
- 第五章 图像基础(GDI 的结构)
- 第五章 图像基础(设备内容)
- 第四章 输出文字(滚动条)
- 第四章 输出文字(滚动条)
- 第四章 输出文字(滚动条)
- CV界的几个华人大牛
- 第四章 输出文字(绘制和更新,GDI 简介)
- 802.15.4中文版