第五章 图形基础
图形设备接口(GDI:Graphics Device Interface),菜单,滚动条、图标和鼠标光标的实现都由GDI来完成。
GDI原理:
GDI的主要目的之一是支持与设备无关的图形。
图形输出设备分为两大类:映像设备和向量设备。
映像设备:以图点构成的数组来表示图像。
微量设备使用线来绘制图像,通常局限于绘图机。
你可以认为GDI是图形设备硬件之间的一种高阶界面。
GDI函数调用:
GDI函数分类:
1、 取得或建立和释放或清除设备内容的函数
2、 取得有关设备内容信息的函数
3、 绘图函数
4、 设定和取得设备内容参数的函数,设备内容的属性决定有关绘图函数如何工作的细节。
5、 使用GDI对象的函数(要使用自己建立的对象就要把对象选进设备)
GDI基本图形:
1、 直线和曲线
2、 填入区域
3、 位图:是位的矩形数组,这些位对应于显示设备上的点(设备相关和设备无关位图)
4、 文字:
GDI其它部分:
1、 映像模式和变换:
2、 Metafile是以二进制形式的GDI命令集合,主要用于通过剪贴板传输向量图形。
3、 绘图区域:是形状任意的复杂区域
4、 路径:是GDI内部储存的直线和曲线的集合。
5、 剪裁:绘图可以限制在显示区域的某一部分。
6、 调色盘:自定调色盘通常限于显示256色的显示器。
7、 打印:
设备内容:
当您想在一个图形输出设备上绘图时,当然包括屏幕,那你就要得到他的设备内容即DC的句柄,将句柄传回给程序时windows就给了您使用设备的权限。
例如:HDC m_hdc = GetDC(); 这样你就得到了windows的屏幕DC也就是这个屏幕设备的控件权掌握在你程序的m_hdc中,你要用他当然把他做为一个参数什么的来使用来更改他。
设备内容中包含许多确定GDI函数如何在设备上工作的属性,但这些属性不是设备句柄可以直接用的(允许传递给GDI函数的参数只包含起始坐标或者尺寸信息),不包含windows在设备上显示对象时需要的所有其它信息。简言之:你想改变设备的属性你可以通过用selectObject把相关的属性传入到设备句柄中
取得设备内容句柄:
Windows提供了几种取得设备内容句柄的方法。如果在处理一个消息时取得了设备内容句柄,应该在退出窗口函数之前释放它。例如:在消息循环中的hdc = BeginPaint(hwnd, &ps);
EndPaint(hwnd, &ps);就是一个得到句柄和释放句柄的两对体。(方法一)
非处理WM_PAINT消息时取得设备内容句柄:
Hdc = GetDC(hwnd);
ReleaseDC(hwnd, hdc);
这个设备内容适用于窗口句柄为hwnd的显示区域。不使显示区域中任何可能的无效区域变成有效。(方法二)
还有可以得到整个窗口的设备内容句柄:(包括菜单栏,标题列和框架)
Hdc = GetWindowDC(hwnd);
ReleaseDC(hwnd, hdc );
想要使用他就必须拦截WM_NCPAINT消息,window使用此消息在窗口的非显示区域上绘图。(这不是方法三,这是得到整个程序设备DC了,方法一二是得到显示区域的DC)
BeginPaint,GetDC,GetWindowDC获得的设备内容都与视讯显示器上的某个特定窗口相关。还有更牛的函数不过有点累要自己建
hdc = CreateDC(pszDriver, pszDevice, pszOutput, pData); deleteDC(hdc);
MSDN的解释如下:(这是得到指定设备的DC了)
HDC CreateDC(
LPCTSTR lpszDriver, // pointer to string specifying driver name 这是什么设备呢在这写入
LPCTSTR lpszDevice, // pointer to string specifying device name
LPCTSTR lpszOutput, // do not use; set to NULL
CONST DEVMODE *lpInitData
// pointer to optional printer data
);
使用:hdc = CreateDC(TEXT(“DISPLAY”),NULL,NULL,NULL);
这是得到全屏DC(什么是全屏,那就是你整个显示器)
有时你只是需要取得关于某设备内容的一些信息而并不进行任何绘画,在这种情况下你可以使用CreateaIC来取得一个信息内容的句柄,太帅了,这是一个偷窥函数,只看不可以摸
例如:Hdc = CreateIC(TEXT(“DISPLAY”),NULL,NULL,NULL);就像const你不可以动里面的东西!
下面的很重要,取得一个内存设备内容很有用。
hdcMem = CreateCompatibleDC(hdc);
DeleteDC(hdcMem);
用selectObject(hdcMem, HBITMAP)你可以把位图选进去,对位图更改其实就相当于在hdcMem中更改。
Metafile是一些GDI调用的集合,以二进制形式编码,如下:
hdcMeta = CreateMetaFile(pszFilename);
hmf = CloseMetaFile(hdcMeta);
取得设备内容信息:
一个设备内容通常是指一个实际显示设备,你要得到设备的信息如大小啦色彩你可以通过GetDeviceCaps取得设备功能函数来得到
iValue = GetDeviceCaps(hdc, iIndex);
例如:int ihorzresSize = GetDeviceCaps(hdc, HORZSIZE);得到水平分辨率
iIndex主要就是你想得到的设备的什么内容iValue就是返回你想得到设备的什么内容信息。
以上的GetDeviceCaps和GetSystemMetrics其实很像
设备的大小:
分辨率 = 像素 / 设备显示区域大小
分辨率有水平分辨率与垂直分辨率,如果两个相等就是正方形图像。
HORZRES, VERTRES 这是逻辑的宽度和高度,HORZSIZE和VERTSIZE值固定表示标准显示器大小
关于色彩:
每个像素点都要内存中的一位(黑白)或多位。位数多色就多。
一个24位的图素 红,绿,蓝各8位(即三原色)
一个16位是 红蓝各5绿色为6
显示256种颜色的显示卡每个像素需要8位,然而这些8位的值一般由定义实际着色的调色盘组织的。
iBitPixel = GetDeviceCaps(hdc, BITSPIXEL)每个像素的位数:
设备内容属性:
设备内容属性 | 默认值 | 修改该值的函数 | 取得该值的函数 |
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 |
保存设备内容:
通常,在你调用GetDC或BeginPaint时,windows用默认值建立一个新的设备内容,你对属性所做的一切改变在设备内容用ReleaseDC或EndPaint调用释放时,都会丢失。如果你的程序需要使用非内定的设备内容属性,则你必须在每次取得设备内容句柄时初始化设备内容。
你可以用一个DC来管理整个设备DC,可以在wndclass.style = CS_HREDRAW |…|CS_OWNDC;来进行管理。都只用一个DC管理一个窗口,只影响GetDC和BeginPaint获得的设备内容不影响其它函数。
某些情况下你可能想改变某些设备内容属性,用改变后的属性进行绘图,然后恢复原来的设备内容。那就通过保存原有DC然后再恢复的方法来做。
idSaved = SaveDC(hdc);这里是保存原有DC
RestoreDC(hdc, idSaved);这里是恢复你可以在调用RestoreDC之前调用SaveDC很多次。
如果你觉得累还可以不用返回值来完成以上操作
SaveDC(hdc), RestoreDC(hdc, -1)。太成功了这就是异曲同工。
画点和画线
设定图素:
SetPixel(hdc, x, y, crColor);
成功时返回crColor的颜色,不成功返回-1
GetPixel函数传回指定坐标处理的像素颜色:
CrColor = GetPixel(hdc , x, y);
直线
七个画线函数:
LineTo画直线
Polyline和PolylineTo画一系列相连的直线
PolyPolyline画多组相连的线
Arc画椭圆线
PolyBezier和PolyBezierTo画贝塞尔曲线
ArcTo和AngleArc画椭圆线
PolyDraw画一系列相连的线以入贝塞尔曲线
填入区域函数:
Rectangle画矩形
Ellipse画椭圆
RoundRect画带圆角的矩形
Pie画椭圆的一部分,使其看起来像一个扇形
Chord画椭圆的一部分,以呈弓形
画线函数:
MoveToEx(hdc, xBeg, yBeg, NULL);指定了线的开始点,最后一个函数传回先前的目标位置
LineTo(hdc, xEnd, yEnd);指定了线的终点
默认的目前位置初设定在(0,0)如果在调用LineTo之前没有设定目前位置那么它将从显示区域的左上角开始画线。
如果你需要目前位置,就可以通过以下调用获得:
GetCurrentPositionEx(hdc, &pt);
//================================================================
边界框函数:
RoundRect, Chord, Pie, Ellipse, Rectangle, 等都是一个矩形边界框来绘图的。
矩形:
Rectangle(hdc, xLeft, yTop, xRight, yBotton);
Ellipse(hdc, xLeft, yTop, xRight, yBottom);
RoundRect(hdc, xLeft, yTop, xRight, yBottom, xCornerEllipse, yCornerEllipse);
xCornerEllipse = (xRight - xLeft)/4;
yCornerEllipse = (yBottom - yTop)/4;
Arc椭圆曲线:
Arc(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
Chrod(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
Pie(hdc, xLeft, yTop, xRight, yBottom, xStart, yStart, xEnd, yEnd);
三个的区别Arc只是椭圆外的一个弧,而chrod是一个小块,Pie是平分后过中点的块
使用现有画笔(stock Pens)
画笔决定线的色彩、宽度和画笔样式,默认画笔为BLACK_PEN。默认的画笔都画出一个像素的黑色黑色实线,还有WHITE_PEN,NULL_PEN(什么也不画也可以自己自订画笔)。
GetStockObject可以获得现有画笔的句柄。
HPEN = hPen;
hPen = GetStockObject(WHITE_PEN);//获得现有白色画笔的句柄。
SelectObject(hdc, hPen);//把画笔先进设备内容
以上的步骤可以缩为SelectObject(hdc, GetStockObject(WHITE_PEN));
SelectObject(hdc, GetStockObject(BLACK_PEN));//这样又选入黑笔
还有一个好的应用SelectObject的传回值是此调用前设备内容中的画笔句柄。
hPen = SelectObject(hdc, GetStockObject(WHITE_PEN));
则设备内容中的目前画笔将为WHITE_PEN变量hPen将会是BLACK_PEN的句柄。
SelectObject(hdc, hPen);
画笔的建立选择和删除:
建立画笔:
使用函数CreatePen或CreatePenIndirect建立一个逻辑画笔,这些函数传回逻辑画笔的句柄然后调用SelectObject将画笔选进设备内容。现在就可以使用新的画笔来画线了。在任何时候,都只有一种画笔选进设备内容。在释放设备内容之后,可以调用DeleteObject来删除所建立的逻辑画笔了。在删除后,该画笔的句柄就不再有效了。
逻辑画笔是一种GDI对象,它是你可以建立的六种GDI对象之一,其它五种是画刷、位图、区域、字体和调色盘。除了调色盘之外,这些对象都是通过SelectObject选进设备内容的。
在使用画笔等GDI对象时,就遵守以下三条规则:
1、 最后要删除自己建立的所有GDI对象
2、 当GDI对象正在一个有效的设备内容中使用时,不要删除它。
3、 不要删除现有对象。
hPen = CreatePen(iPenStyle, iWidth, crColor);
HPEN CreatePen(
int fnPenStyle, // pen style
int nWidth, // pen width
COLORREF crColor // pen color
);
在这里要注意一个地方如果指定的是点划线或虚线式画笔样式,同时又指定一个大于1的实际宽度,那么windows将使用实线画笔来代替。PS_INSIDEFRAME是唯一一种可以使用的画笔样式,并且只有在宽度大于1的情况下才如此,在使用边界框时他将边界框画在边界框之内。
使用CreatePenIndirect首先定义一个LOGPEN形态的结构
使用方法如下:
LOGPEN logpen;
hPen = CreatePenIndirect(&logpen);
LOGPEN中有三个成员,lopnStyle是画笔样式,lopnWidth是按逻辑单位度量的画笔宽度,lopenColor是画笔颜色。
CreatePen,CreatePenIndirect函数不需要设备内容句柄作为参数。这些函数建立与设备内容没有联系的逻辑画笔,直到调用SelectObject之后,画笔才与设备内容发生联系。
如果有一个画笔的句柄,就可以通过调用GetObject取得LOGPEN结构各个成员的值:
GetObject(hPen, sizeof(LOGPEN), (LPVOID)&logpen);
如果需要目前先进设备内容的画笔句柄可以调用:
hPen = GetCurrentObject(hdc, OBJ_PEN);
填入空隙:
使用点式画笔和虚线画笔会产生一个问题:点和虚线之间的空隙会怎么确定?
空隙的着色取决于设备内容的两个属性-前景模式和背景颜色。内定背景模式为OPAQUE(不透明)在这种方式下,windows使用背景色来填入空隙,内定的背景色为白色。
可以通过改变windows用来填入空隙的背景色。
SetBkColor(hdc, crColor);
可以通过用GetBkColor来取得设备内容中定义的目前背景色。通过将背景模式转换为TRANSPARENT可以阻止windows填入空隙:
SetBkMode(hdc, TRANSPARENT);
绘图方式:
像素间的位运算叫做位映像运算,简称ROP,由于画一条直线只涉及两种图素(画笔和目标),因此这种运算又称为”二元位映像运算”,简记为ROP2,在windows中默认的定义为R2_COPYPEN,这意味着windows只是将画笔像素复制到目标图像。还有15种ROP 2 码 。
不管画笔和目标的色彩画出的线总是黑色的R2_BLACK
十六种画笔:
画笔(P):目标(D): | 1 1 | 1 0 | 0 1 | 0 0 | 布尔操作 | 绘图模式 |
结果: | 0 | 0 | 0 | 0 | 0 | R2_BLACK |
| 0 | 0 | 0 | 1 | ~(P | D) | R2_NOTMERGEPEN |
| 0 | 0 | 1 | 0 | ~P & D | R2_MASKNOTPEN |
| 0 | 0 | 1 | 1 | ~P | R2_NOTCOPYPEN |
| 0 | 1 | 0 | 0 | P & ~D | R2_MASKPENNOT |
| 0 | 1 | 0 | 1 | ~D | R2_NOT |
| 0 | 1 | 1 | 0 | P ^ D | R2_XORPEN |
| 0 | 1 | 1 | 1 | ~(P & D) | R2_NOTMASKPEN |
| 1 | 0 | 0 | 0 | P & D | R2_MASKPEN |
| 1 | 0 | 0 | 1 | ~(P ^ D) | R2_NOTXORPEN |
| 1 | 0 | 1 | 0 | D | R2_NOP |
| 1 | 0 | 1 | 1 | ~P | D | R2_MERGENOTPEN |
| 1 | 1 | 0 | 0 | P | R2_COPYPEN(内定) |
| 1 | 1 | 0 | 1 | P | ~D | R2_MERGEPENNOT |
| 1 | 1 | 1 | 0 | P | D | R2_MERGEPEN |
| 1 | 1 | 1 | 1 | 1 | R2_WHITE |
可以用SetROP2(hdc, iDrawModel)来设定
当然有Set就有Get了iDrawModel = GetROP2(hdc);
绘制填入区域:
Windows中七个用来画带边缘的填入图形的函数:
函数 | 图形 |
Rectangle | 直角矩形 |
Ellipse | 椭圆 |
RoundRect | 圆角矩形 |
Chord | 椭圆周上的弧,两端以弦连接 |
Pie | 椭圆上的饼图 |
Polygon | 多边形 |
PolyPolygon | 多个多边形 |
Windows用设备内容中选择的目前画笔来画图形的边界框,边界框还使用目前背景方式、前景色彩和绘图方式。以上图形以目前设备内容中选择的画刷来填入。Windows定义六种现有画刷:WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH, DKGRAY_BRUSH, BLACK_BRUSH, NULL_BRUSH。你可以把这些选入设备中。
HBRUSH hBrush;
hBrush = GetStockObject(GRAY_BRUSH);可以用GetStockObject来得到现有画刷句柄。
可以用SelectObject(hdc, hBrush);选进设备内容。
Polygon(hdc, apt, iCount);
这个函数会把apt合成一个封闭区域,iCount是点的数目
PolyPolygon(hdc, apt, aiCounts, iPolyCount);
该函数绘制多个多边形,iPolyCount给出了所画的多边形的个数,aiCount给出了多边形的端点数,apt有全部多边形的所有点。
填入方式可用SetPolyFillMode(hdc, iMode);来设置有两个方法
ALTERNATE 或 WINDING(填入所有封闭区域)
用画刷填入内部:
所有封闭区间的函数内部是用先进设备内容的目前画刷(图样)来填入的。画刷是一个8*8的位图,它水平和垂直地重复使用来填入内部区域。
逻辑画刷的建立:
hBrush = CreateSolidBrush(crColor);
有影线标记的画刷就是内部填充为线条的画刷。
bBrush = CreateHatchBrush(iHatchStyle, crColor);
iHatchStyle有六种风格:HS_HORIZONTAL, HS_BDIAGONAL, HS_VERTICAL, HS_CROSS, HS_FDIAGONAL, HS_DIAGCROSS
CreateHatchBrush中的crColor参数是影线的色彩。在将画刷选进设备内容时,windows将这种色彩转换为与之最相近的纯色。
hBrush = CreateBrushIndirect(&logbrush)
LOGBRUSH logbrush逻辑画刷的结构。
字段为:
lbStyle (UINT) | lbColor (COLORREF) | lbHatch (LONG) |
BS_SOLID | 画刷的色彩 | 忽略 |
BS_HOLLOW | 忽略 | 忽略 |
BS_HATCHED | 影线的色彩 | 影线画刷风格 |
BS_PATTERN | 忽略 | 位图的句柄 |
BS_DIBPATTERNPT | 忽略 | 指向DIB的指标 |
使用过程也是用SelectObject来将逻辑画笔选举法进设备内容。然后使用DeletcObject函数删除所建立的画刷。用GetObject来取得逻辑画笔的信息。
GetObject(hBrush, sizeof(LOGBRUSH), (LPVOID)&logbrush)
GDI 映像方式:
映像方式是一种几乎影响任何显示区域绘图的设备内容属性。他们使用的都是逻辑单位。Windows必须将逻辑单位转换为设备单位。
共有八种映像方式:
映像方式 | 逻辑单位 | 增加值 | |
x值 | y值 | ||
MM_TEXT | 图素 | 右 | 下 |
MM_LOMETRIC | 0.1 mm | 右 | 上 |
MM_HIMETRIC | 0.01 mm | 右 | 上 |
MM_LOENGLISH | 0.01 in . | 右 | 上 |
MM_HIENGLISH | 0.001 in . | 右 | 上 |
MM_TWIPS | 1/ 1440 in . | 右 | 上 |
MM_ISOTROPIC | 任意(x = y) | 可选 | 可选 |
MM_ANISOTROPIC | 任意(x != y) | 可选 | 可选 |
设置映射方式:
SetMapMode(hdc, iMapMode);iMapMode如上面八种映射方式
iMapMode = GetMapMode(hdc);得到设备使用的映射方式
设备坐标和逻辑坐标:
设备坐标系:
Windows将GDI函数中指定的逻辑坐标映像为设备坐标。
如果以DISPLAY为参数调用CreateDC以取得整个屏幕的设备内容,则内定GDI调用中指定的逻辑坐标将被映像为“屏幕坐标”。用GetWindowsDC取得设备内容的区域坐标为“全窗口坐标”。“显示区域坐系”用GetDC或BeginPaint取得设备内容。用ClinetToScreen和ScreenToClient可以将显示区域坐标转换为屏幕坐标,或者反过来,将屏幕坐标转换为显示区域坐标。也可以使用GetWindowRect函数取得屏幕坐标下的整个窗口的位置和大小。这三个函数为一咱设备坐标转换为另一种提供了足够的信息。
映像方式定义了windows如何将GDI函数中指定的逻辑坐标映像为设备坐标,这里的设备坐标系取决于你用哪个函数来取得设备内容。
取得显示区域大小:GetClientRect(hwnd, &rect);
关于映像方式和计算个人基本没遇到过这个问题所以没去研究,有兴趣以后用到了再学学。嘻嘻有一个大体上的概念就好了!
矩形、区域和剪裁
Windows包含了几种使用RECT结构和区域的绘图函数。区域就是屏幕上的一块地方,它是矩形、多边形和椭圆的组合。
三个绘图函数:
FillRect(hdc, &rect, hBrush);//指定画刷矩形
FrameRect(hdc, &rect, hBrush);使用画刷画矩形框,但是不填入矩形。
InvertRect(hdc, &rect);将矩形中所有像素翻转,1转换成0, 0转换为1。
可以用rect.right = ??,rect.bottom=??,还可以用SetRect(&rect, xLeft, yTop, xRight, yBottom)来做给rect赋值的操作。
offsetRect(&rect, x, y); 将矩形沿x轴和y轴移动几个单元
InflateRect(&rect, x, y); 增减矩形的尺寸
SetRectEmpty(&rect); 矩形各字段设定为0
CopyRect(&DestRect, &SrcRect); 将矩形复制给另一个矩形
IntersectRect(&DestRect, &SrcRect1, &SrcRect2);取得两个矩形的交集.
UnionRect(&DestRect, &SrcRect1, &SrcRect2);取得两个矩形的联集。
bEmpty = IsRectEmpty(&rect);确定矩形是否为空。
bInRect = PtInRect(&rect, point);确定点是否在矩形内
RECT重载了=号可以用DestRect = SrcRect来取代CopyRect
随机矩形:
PeekMessage调用:
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
BOOL PeekMessage(
LPMSG lpMsg, // pointer to structure for message
HWND hWnd, // handle to window NULL
UINT wMsgFilterMin, // first message NULL
UINT wMsgFilterMax, // last message NULL
UINT wRemoveMsg // removal flags NULL
);
将第二,三,四个参数设定为NULL或0,表明我们想让它传回程序中所有窗口的所有消息。如果要将消息从消息队列中删除,则将PeekMessage的最后一个参数设定为PM_REMOVE。如果你不希望删除消息,那么可以将这个参数设定为PM_NOREMOVE这就是为什么PeekMessage是“偷看”而不是“取得”的原因它使得程序可以检查程序的队列中的下一个消息,而不实际删除它。
GetMessage不将控制传回程序,直到从程序的消息队列中取得消息,但是PeekMessage总是立刻传回,而不论一个消息是否出现。当消息队列中有一个消息时,PeekMessage的传回值为true并且将按通常方式处理消息。当队列中没有消息时,PeekMessage传回false。
这样我们就可以利用PeekMessage传回为false时也就是消息队列中无消息时进行一些处理。
建立和绘制剪裁区域
剪裁区域是对显示器上一个范围的描述,这个范围是矩形、多边形和椭圆的组合。剪裁区域可以用于绘制和剪裁,通过将剪裁区域选进设备内容,就可以用剪裁区域来进行剪裁,就是说将可以绘图的范围限制为显示区域的一部分。与画笔、画刷和位图一样,剪裁区域是GDI对象,你应该调用DeleteObject来删除你所建立的剪裁区域。
HRGN hRgn = CreateRectRgn(xLeft, yTop, xRight, yBottom);
或hRgn = CreateRectRgnIndirect(&rect);建立一个剪裁区域。
还可以建立椭圆剪裁区域hRgn = CreateEllipticRgn(xLeft, yTop, xRight, yBottom);
或 hRGn = CreateEllipticRgnIndirect(&rect);
CreateRoundRectRgn是圆角的矩形剪裁区域。
多边形剪裁区域的函数类似于Polygon
hRgn = CreatePolygonRgn(&point, iCount, iPolyFillModel );
iRgnType = CombineRgn(hDestRgn, hSrcRgn1, hSrcRgn2, iCombine);
这一函数将两个剪裁区域hSrcRgn1/2组合起来并用够本hDestRgn指向组合成的剪裁区域。
iCombine的值
表5-9 |
iCombine值 | 新剪裁区域 |
RGN_AND | 两个剪裁区域的公共部分 |
RGN_OR | 两个剪裁区域的全部 |
RGN_XOR | 两个剪裁区域的全部除去公共部分 |
RGN_DIFF | hSrcRgn1不在hSrcRgn2中的部分 |
RGN_COPY | hSrcRgn1的全部(忽略hSrcRgn2) |
从CombineRgn传回的iRgnType值是下列之一:NULLREGION表示得到一个空剪裁区域,SIMPLEREGION表示得到一个简单的矩形椭圆或者多边形,COMPLEXREGION表示多个矩形或多边形的组合,ERROR表示出错了.
FillRgn(hdc, hRgn,hBrush);
FrameRgn(hdc, hRgn, hBrush, xFrame, yFrame);
InvertRgn(hdc, hRgn);
PaintRgn(hdc, hRgn);
他们和FillRect,FrameRect,InverRect都是相同的只是他们的hRgn不同一个是rect一个是HRGN。
用完后要删除DeleteObject(hRgn);
矩形与区域的剪裁:
InvalidateRect(hwnd, NULL, TRUE);
你可以通过调用GetUpdateRect来取得失效矩形的坐标,并且可以使用ValidateRect函数使显示区域的矩形有效当你接收到一个WM_PAINT消息时,无效矩形的坐标可以从PAINTSTRUCT结构中得到,该结构是用BeginPaint函数填入的。这个无效矩形还定义了一个剪裁区域你不能在剪裁区域外绘图。
Windows有两个作用于剪裁区域而不是矩形的函数,它们类似于InvalidateRect和ValidateRect:
InvalidateRgn(hwnd, hRgn, bErase);
ValidateRgn(hwnd, hRgn);
当你接收到一个由无效区域引起的WM_PAINT消息时,剪裁区域不一定是矩形。
你可以使用以下函数之一:
SelectObject(hdc, hRgn)或SelectClipRgn(hdc, hRgn);
通过将一个剪裁区域选进设备内容来建立自己的剪裁区域,这个剪裁区域使用设备坐标。
GDI为剪裁区域建立一份副本,所以在将它选进设备内容之后,使用者可以删除它。Windows还提供了几个对剪裁区域进行操作的函数,如ExcludeClipRect用于将一个矩形从剪裁区域里排除掉,IntersectClipRect用于建立一个新的剪裁区域,它是前一个剪裁区域与一个矩形的交,offsetClipRgn用于将剪裁区域移动到显示区域的另一部分。