0.前言
作者大大在上一章结束的时候非常开心,终于要讲绘图相关的内容了,之后会主要讲Direct X。我也好开心,^_^
1.详述HDC(Handle to Device Context)
各种句柄或者设备描述表什么的,实际上是对系统中的对应功能的详细描述,也就是说,记录了对应功能的所有信息。
因此,当获得了对一个图形设备描述表或者句柄的访问权的时候,也就意味着关于这个功能的所有信息都可以知道了。
在调用GDI函数的时候,传入给的HDC句柄参数,是GDI函数用来访问和跟踪编程过程中可能改变的软件设置。
图形设备描述表不仅是视频系统的硬件描述,而且还是记录和保存设置的信息库。
总之,得到了HDC就得到了所有的信息;将所有的GDI函数需要的信息都放到HDC中,省去了函数调用时的许多参数,也方便了功能的扩展。
2.GDI绘图的流程
GDI就像一个画家,在绘画的时候,需要使用工具画笔、画刷。颜色由画笔和画刷自己决定。
画笔:用于画线条和轮廓,具有颜色、粗细和线型。
画刷:用于填充任何封闭的对象,具有颜色、样式,或者本身可以是位图。
GDI同时只是用一个画笔或画刷,因此,需要将要是用的工具先选择对象到图形设备描述表中,这个过程叫选定(selection)。
一旦描述表中选中了一个绘图对象,该对象会一直被是用,直到被修改。
在完成绘图之后,必须删除该画笔或者画刷。这是因为Windows GDI关于画笔和画刷句柄只有有限书面的存取位置,可能会被用光。
总结一下,流程就是:
创建画笔/画刷 ——> 选择对象 ——> 绘制 ——> 选择对象(old_xx,恢复设置) ——> 删除画笔/画刷
3.画笔(HPEN)
画笔句柄:HPEN
1.获得HPEN
1.存储对象(Stock Objects)
Windows已经定义好的有限数目的对象,叫做存储对象。
GetStockedObject()函数获得存储对象。1
2// 返回fnObject类型对象的句柄
HGDIOBJ GetStockedObject(int fnObject); // 存储对象的类型
部分存储对象类型:
值 | 描述 |
---|---|
BLACK_PEN | 黑色画笔 |
NULL_PEN | 空画笔 |
WHITE_PEN | 白色画笔 |
BLACK_BRUSH | 黑色画刷。颜色还可以是WHITE/DKGRAY/GRAY/LTGRAY等 |
NULL_BRUSH | 空画刷 |
HOLLOW_BRUSH | 中空画刷,相当于NULL_BRUSH |
ANSI_FIXED_FONT | 标准的Widnows固定间距(等宽)系统字体 |
SYSTEM_FONT | 系统字体 |
eg.1
2HPEN white_pen=NULL;
white_pen = GetStockedObject(WHITE_PEN);
2. 创建用户自定义画笔
使用CreatePen()函数:1
2
3HPEN CreatePen(int fnPenStyle, // 线型(实线、虚线、点形、点划线等)
int nWidth, // 画笔的宽度(pixel)
COLORREF crColor); // 画笔颜色
fnPenStyle:可以使用“与”运算组合
线型 | 描述 |
---|---|
PS_NULL | 画笔不可见 |
PS_SOLID | 实线 |
PS_DASH | 虚线 |
PS_DOT | 点 |
PS_DASHDOT | 点划线 |
PS_DASHDOTDOT | 双点划线 |
eg.1
HPEN pen = CreatePen(PS_SOLID,1,RGB(0,255,0));
2.选中对象、恢复对象、删除画笔
使用SelectObject()函数选中对象,并且返回旧的对象,以便恢复。1
2
3// 返回值是旧的对象
HDIOBJ SelectObject(HDC hdc, // 设备描述
HGDIOBJ hdgiObj); // 要选中的对象
所有GDI对象句柄都是HDIOBJ的子类。
使用DeleteObject()函数删除GDI句柄:1
BOOL DeleteObject(HGDIOBJ hObject);
当选中对象,并且绘画完成之后,记得恢复对象:1
2
3
4
5
6
7HPEN red_pen = CreatePen(PS_SOLID,1,RGB(255,0,0));
HPEN old_pen = (HPEN)SelectObject(hdc,red_pen);
// 在这里绘制
SelectObject(hdc, old_pen); // 恢复对象
DeleteObject(red_pen); // 删除对象
4.画刷
画刷的创建和使用流程和画笔基本一样。简要介绍画刷特有的:
画刷句柄:HBRUSH
GDI将画刷分为两类:实心的(Solid)和阴影线的(Hatched)。
创建实心画刷:1
HBRUSH CreateSolidBrush(CORLORREF crColor); // 参数:画刷颜色
创建阴影线画刷:
1 | HBRUSH CreateHatchBrush(int fnStyle, // 样式值 |
值 | 描述 |
---|---|
HS_BDIAGONAL | 从左上到右下的45°阴影线 |
HS_CROSS | 水平和垂直的交叉阴影线 |
HS_DIAGCROSS | 45°交叉阴影线 |
HS_FDIAGONAL | 从左下到右上的45°阴影线 |
HS_HORIZONTAL | 水平阴影线 |
HS_VERTICAL | 垂直阴影线 |
使用例子:1
2
3
4
5
6HBRUSH red_hbrush = CreateHatchBrush(HS_CROSS,RGB(255,0,0)); // 创建一个红色交叉阴影线的画刷
HBRUSH old_hbrush = (HBRUSH)SelectObject(hdc,red_hbrush); // 选中画刷
// 在这里进行绘制
// ...
SelectObject(hdc,old_hbrush); // 恢复画刷
DeleteObject(red_hbrush); // 删除画刷
5.绘制图形函数
1.点
不需要画笔或者画刷。
点只是一个像素,只需要HDC、坐标和颜色就可以了。
SetPixel()返回实际的绘制颜色:1
2
3
4COLORREF SetPixel(HDC hdc,
int x, // 相对于hdc的x坐标
int y, // 相对于hdc的y坐标
COLORREF crColor); // 颜色
GetWindowDC():获得整个窗口。可以在窗口的控件区域绘图。
GetDC():获取窗口中用户区域。不可以在窗口的控件区域绘图
2.线
步骤:
- 1.创建画笔,并选中画笔
- 2.设定线段的起始位置(光标位置)
- 3.从起始位置绘制到终点位置
- 4.重复3
- 5.恢复画笔、删除画笔
设定位置的函数是MoveToEx():1
2
3
4BOOL MoveToEx(HDC hdc,
int x,
int y,
LPPOINT lpPoint); // 旧光标位置点,如果不保存,可以设置为NULL
其中LPPOINT是点的数据结构:1
2
3
4
5typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT;
绘制线段的函数是LineTo:1
2
3BOOL LineTo(HDC hdc,
int xEnd,
int yEnd)
3.矩形
需要使用画笔或者画刷(如果需要内部区域填充的话,使用画刷)来绘制矩形。
1.Rectangle()函数:
1 | BOOL Rectangle(HDC hdc, |
注意:Rectangle默认会有至少1pixel的边框。
2.FillRect()函数: 填充矩形,不绘制边框。其中lprc只包含左上角,不包含右下角
1 | int FillRect(HDC hdc, |
3.FrameRect()函数:绘制矩形边框,即绘制中空的矩形。只能使用画刷。
其中画刷只是一个临时的对象,不需要选中到设备中,也不需要删除。
1 | int FrameRect(HDC hdc, |
4.圆
GDI绘制圆形实际上是通过绘制一个椭圆得到的。
定义一个椭圆的长轴和短轴,使用的是定义一个矩形,由矩形的长和宽作为椭圆的长轴和短轴。
使用当前的画笔和画刷来绘制椭圆:
Ellipse()函数:
1 | BOOL Ellipse(HDC hdc, |
5.多边形
使用画笔或者画刷绘制多边形的函数Polygon():
1 | BOOL Polygon(HDC hdc, |
6.函数总结
- GetStockedObject:获取存储对象
- CreatePen:创建画笔
- CreateSolidBrush:创建实心画刷
- CreateHatchBrush:创建带阴影线的画刷
- SelectObject:选中对象
- DeleteObject:删除对象
- SetPixel:改变像素颜色
- GetWindowDC:获得整个窗口。可以在窗口的控件区域绘图。
- GetDC:获取窗口中用户区域。不可以在窗口的控件区域绘图
- MoveToEx:移动光标位置
- LineTo:绘制线
- Rectangle:绘制矩形
- FillRect:填充矩形,不画框
- FrameRect:矩形框
- Ellipse:椭圆
- Polygon:多边形