文章目录
- WM_PAINT 消息中
- WM_PAINT 消息外
- 自定义画笔或者画刷
- 画笔
- 画刷
- 画点
- 矩形
- 画圆,饼图,弦图
- 颜色COLORREF
- 清屏
GDI 图形设备接口
与用户的交互,在屏幕上输出图形图像。
GDI函数的分类
- 取得和释放设备上下文的函数
- 取得有关设备内容信息的函数
- 绘图函数
- 设定和取得设备上下文参数的函数
- 调用GDI对象的函数
在屏幕上可以输出的图像分为4类
- 直线和曲线
- 填充区域
- 文字
- 位图
设备上下文:DC Device Contexts 包含有关某个设备的绘制属性信息的windows数据结构
在窗口绘制图像,图形分4步:
- 得到设备环境句柄
- 修改设备属性
- 绘制图形,图像
- 释放设备环境句柄
在window中的歌设备环境句柄有两种情况
WM_PAINT 消息中
在WM_PAINT 消息里面去得到设备环境句柄,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { //绘制消息 case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps);//1. 得到设备环境 // TODO: 在此处添加使用 hdc 的任何绘图代码...//这里包含2,3,步 EndPaint(hWnd, &ps);//释放设备环境 } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } |
1 2 3 4 5 6 7 8 | typedef struct tagPAINTSTRUCT { HDC hdc; //设备环境句柄 BOOL fErase; //是否擦除 RECT rcPaint; //矩形类,绘制区域 BOOL fRestore; // BOOL fIncUpdate; BYTE rgbReserved[32]; } PAINTSTRUCT; |
什么情况下会响应WM_PAINT消息:
- 窗口最初创建时
- 窗口出现无效区域
窗口会有四种情况出现无效区域:
- 窗口移动或者大小改变
- 窗口隐藏之后重新显示或者被其他窗口遮掩部分重新可见
- 调用函数InvallidatRect(),InvallidatRgnt(),使窗口出现无效区域
- **ScrollDC()和ScrollWindow()**函数,滚动客户去或窗口,出现无效区
WM_PAINT 消息外
在WM_PAINT 消息外面去得到设备环境句柄
在WM_PAINT消息外得到设备环境句柄有以下几种方式
第一步通过GetDC()得到设备环境句柄,
1 | hdc = GetDC(hWnd); |
第二步修改设备属性,
1 2 3 4 5 6 7 | //2.修改设备句柄 //没有设定画笔,默认为黑色 //自己定义画笔句柄 HPEN hpen = nullptr; //画笔句柄 hpen = (HPEN)GetStockObject(WHITE_PEN); //选择一个GDI(画笔)对象进DC SeletcObject(hdc,hpen); |
第三步绘制图形,图像
1 2 3 4 5 6 | //3.绘图 MoveToEx(hdc,100,100,nullptr); //把画笔移动到某一个点,这是相当窗口的位置 LineTo(hdc,200,200);//画线到某个点,如果之前没有设定起点,默认起点为0,0坐标,如果之前有画线,上个重点将是起点 LineTo(hdc,400,400); //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hpen); |
第四步通过ReleaseDC()释放设备环境句柄。
1 2 | //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
示例如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { //鼠标的左键按下,获取设备环境句柄 case WM_RBUTTONDOWN: { //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 //没有设定画笔,默认为黑色 //自己定义画笔句柄 HPEN hpen = nullptr; //画笔句柄 hpen = (HPEN)GetStockObject(WHITE_PEN);//使用系统自定义的画笔 //选择一个GDI(画笔)对象进DC SeletcObject(hdc,hpen); //3.绘图 MoveToEx(hdc,100,100,nullptr); //把画笔移动到某一个点,这是相当窗口的位置 LineTo(hdc,200,200);//画线到某个点,如果之前没有设定起点,默认起点为0,0坐标,如果之前有画线,上个重点将是起点 LineTo(hdc,400,400); //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hpen); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); } break; } return 0; } |
自定义画笔或者画刷
GDI对象,在同一个时刻只能使用同一个GDI对象
HPEN 画笔句柄
HBRUSH 画刷句柄
画笔
1 2 3 4 5 6 7 | //使用系统默认的画笔或者画刷 GetStockObject( _In_ int i); //画笔或者画刷的风格 //创建画笔 CreatePen( _In_ int iStyle, //画笔的风格 _In_ int cWidth, //画笔的宽度 _In_ COLORREF color);//画笔的颜色 |
画笔的风格参数
| 风格 | 说明 |
|---|---|
| PS_SOLID | 画笔画出的是实线 |
| PS_DASH | 画笔画出的是虚线(cWidth必须不大于1) |
| PS_DOT | 画笔画出的是点线(cWidth必须不大于1) |
| PS_DASHDOT | 画笔画出的是点划线(cWidth必须不大于1) |
| PS_DASHDOTDOT | 画笔画出的是点-点-划线(cWidth必须不大于1) |
| PS_NULL | 画笔不能画图 |
| PS_INSIDEFRAME | 由椭圆、矩形、圆角矩形、饼图以及弦等生成的封闭对象框时,画线宽度向内扩展。如指定的准确RGB颜色不存在,就进行抖动处理 |
画刷
1 2 3 4 5 6 7 8 9 | //创建画刷 //使用系统设置好的画刷 //1.创建一个纯色的画刷 CreateSolidBrush( _In_ COLORREF color); //参数画刷的颜色 //2.创建一个风格画刷 //风格画刷不是透明的 CreateHatchBrush( _In_ int iHatch, //画刷风格 _In_ COLORREF color); //画刷颜色 //3.创建一个位图画刷 //位图画刷的背景图片无法移动,是从窗口0,0,的位置开始填充 CreatePatternBrush( _In_ HBITMAP hbm); //参数为一个位图 |
画刷的风格参数
| 风格 | 说明 |
|---|---|
| HS_HORIZONTAL | 画刷样式 /* ----- */ |
| HS_VERTICAL | 画刷样式 /* ||||*/ |
| HS_FDIAGONAL | 画刷样式 /* \\\ */ |
| HS_BDIAGONAL | 画刷样式 /* ///// */ |
| HS_CROSS | 画刷样式 /* +++++ */ |
| HS_DIAGCROSS | 画刷样式 /* xxxxx */ |
画笔的代码演示如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 //没有设定画笔,默认为黑色 //自己定义画笔句柄 HPEN hpen = nullptr; //画笔句柄 hpen = CreatePen(PS_SOLID,3,RGB(255,0,0));//自定义画笔 //选择一个GDI(画笔)对象进DC SeletcObject(hdc,hpen); //3.绘图 MoveToEx(hdc,100,100,nullptr); //把画笔移动到某一个点,这是相当窗口的位置 LineTo(hdc,200,200);//画线到某个点,如果之前没有设定起点,默认起点为0,0坐标,如果之前有画线,上个重点将是起点 LineTo(hdc,400,400); //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hpen); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
画刷的代码演示如下
在使用画刷画区域的时候,如果没有设定画刷,会默认提供一个白色画刷,绘制的区域会有描边,描边默认使用黑色的画笔。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 //如果没有设定画刷,会默认提供一个白色额画刷,绘制的区域会有描边 //自定义画刷 HBRUSH hb = nullptr; //使用系统设置好的画刷 hb = (HBRUSH)GetStockObject(BLACK_BRUSH); //自定义画刷,绿色 hb = CreateSolidBrush(RGB(0,255,0)); //设定描边画笔的颜色 HPEN hpen = CreatePen(PS_SOLID,1,RGB(0,255,0));//自定义画笔.绿色画笔 //选择一个GDI(画笔,画刷)对象进DC SelectObject(hdc,hpen); SelectObject(hdc,hb); //3.绘图 Rectangle(hdc,100,100,400,400); //使用设定好的画刷画一个正方形 //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hpen); DeleteObject(hb); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
创建位图画刷代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 HBRUSH hb = nullptr; //自定义位图 HBITMAP hbit = (HBITMAP)LoadImage(hInst,_T("1.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE) //创建位图画刷 hb = CreatePatternBrush(hbit); SeletcObject(hdc,hpen); //设定描边画笔的颜色 HPEN hpen = CreatePen(PS_SOLID,1,RGB(0,255,0));//自定义画笔.绿色画笔 //选择一个GDI(画笔,画刷)对象进DC SeletcObject(hdc,hb); //3.绘图 Rectangle(hdc,100,100,400,400); //使用设定好的画刷画一个正方形 //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hpen); DeleteObject(hbit); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
画点
SetPixel() 设置像素点
GetPixel() 得到像素点
1 2 3 4 5 6 7 8 9 10 11 12 | COLORREF SetPixel(HDC hdc, //设备环境句柄。 int X, //指定要设置的点的X轴坐标 int Y, //指定要设置的点的Y轴坐标 COLORREF crColor); //指定要用来绘制该点的颜色。 //如果函数执行成功,那么返回值就是函数设置像素的RGB颜色值。这个值可能与crColor指定的颜色有所不同,之所以有时发生这种情况是因为没有找到对指定颜色进行真正匹配造成的。 //如果函数失败,那么返回值是-1。 //Windows NT:若想获得更多的错误信息,请调用GetLastError函数。 COLORREF GetPixel(HDC hdc, //设备环境句柄。 int nXPos, //指定要检查的像素点的逻辑X轴坐标。 int nYPos); //指定要检查的像素点的逻辑Y轴坐标。 //返回值是该象像点的RGB值。如果指定的像素点在当前剪辑区之外;那么返回值是CLR_INVALID。 |
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 //3.绘图 画点 for(int i = 0;i < 100; ++i) { //设置像素点 SetPixel(hdc,100 + i,100,RGB(255,0,0)); } for(int i = 0;i < 100; ++i) { //在x = 100+i,y=100处开始获取像素点的颜色,然后在x=100+i,y=200处设置像素点 SetPixel(hdc,100 + i,200,GetPixel(hdc,100 + i,100)); } //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
矩形
一个矩形是左顶右底来确定一个矩形
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | //rect结构定义了一个矩形框左上角以及右下角的坐标。 typedef struct _RECT { LONG left; //指定矩形框左上角的x坐标 LONG top; //指定矩形框左上角的y坐标 LONG right; //指定矩形框右下角的x坐标 LONG bottom; //指定矩形框右下角的y坐标 } RECT, *PRECT; //画一个矩形 Rectangle(_In_ HDC hdc, //绘画的环境句柄 _In_ int left, //指定矩形左上角X坐标 _In_ int top, //指定矩形左上角Y坐标 _In_ int right, //指定矩形右下角X坐标 _In_ int bottom);//指定矩形右下角Y坐标 //圆角矩形 RoundRect(_In_ HDC hdc, //绘画的环境句柄 _In_ int left, //指定矩形左上角X坐标 _In_ int top, //指定矩形左上角Y坐标 _In_ int right, //指定矩形右下角X坐标 _In_ int bottom, //指定矩形右下角Y坐标 _In_ int width, //指定用来画圆角的椭圆的宽。 _In_ int height);//指定用来画圆角的椭圆的高。 //填充矩形 FillRect( _In_ HDC hDC, //绘画的环境句柄 _In_ CONST RECT *lprc, //要绘制的矩形指针,矩形结构体RECT _In_ HBRUSH hbr); //指定矩形的画刷 |
代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //WndProc消息处理函数中 switch (message) { //鼠标的左键按下 case WM_LBUTTONDOWN: { //1.得到设备环境句柄 hdc = GetDC(hWnd); RECT r = {0,0,100,100}; //2.修改设备环境句柄 HBRUSH hr = CreateSolidBrush(0xffffff); //创建白色画刷 SeletcObject(hdc,hr); //3.绘图 FillRect(hdc,&r,hr);//填充矩形,没有描边 //释放画刷 DeleteObject(hr); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); } break; } |
画圆,饼图,弦图
借助这个圆的外接矩形来确定圆的大小;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | //画圆弧,是以逆时针来画的 BOOL Arc( HDC hdc, //绘画的环境句柄 int xLeft, //指定外接矩形左上角X坐标 int yTop, //指定外接矩形左上角Y坐标 int xRight, //指定外接矩形右下角X坐标 int yBottom, //指定外接矩形右下角Y坐标 int XStart, //指定圆弧开始X坐标 int YStart, //指定圆弧开始Y坐标 int XEnd, //指定圆弧结束X坐标 int YEnd); //指定圆弧结束Y坐标 //起点和终点可以不必在圆上 //如果起点(终点)在圆外,那么从圆心到点作连线与圆的焦点为起点(终点) //如果起点(终点)在圆内,那么从圆心到点连线再做延长线与圆的交点即为起点(终点) //如果点在圆心,延x轴正方向与圆的交点即为起点(终点) //填充圆 Ellipse( _In_ HDC hdc, //绘画的环境句柄 _In_ int left, //指定外接矩形左上角X坐标 _In_ int top, //指定外接矩形左上角Y坐标 _In_ int right, //指定外接矩形右下角X坐标 _In_ int bottom);//指定外接矩形右下角Y坐标 //画饼图 BOOL Pie(HDC hdc, //设备环境句柄 int nLeftRect, //指定限定矩形左上角的X坐标 int nTopRect, //指定限定矩形左上角的Y坐标 int nRightRect, //指定限定矩形右下角的X坐标 int nBottomRect, //指定限定矩形右下角的Y坐标 int nXRadial1, //指定第一条半径的端点的X坐标 int nYRadial1, //指定第一条半径的端点的Y坐标 int nXRadial2, //指定第二条半径的端点的X坐标 int nYRadial2); //指定第二条半径的端点的Y坐标 //画弦图 //像注解中那样画一个弦。 //(X1,Y1)和(X2,Y2)定义了椭圆的一个范围(约束)矩形。点(X3,Y3)和点(X4,Y4)定义了一条线段。该线段与椭圆之间的区域就是“弦” Chord( _In_ HDC hdc, //设备环境句柄 _In_ int x1, //指定限定矩形左上角的X坐标 _In_ int y1, //指定限定矩形左上角的Y坐标 _In_ int x2, //指定限定矩形右下角的X坐标 _In_ int y2, //指定限定矩形右下角的Y坐标 _In_ int x3, //指定与椭圆相交的一条线的一个点的X坐标 _In_ int y3, //指定与椭圆相交的一条线的一个点的Y坐标 _In_ int x4, //指定与椭圆相交的一条线的另一个点的X坐标 _In_ int y4); //指定与椭圆相交的一条线的另一个点的Y坐标 |
画圆的代码演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 //没有设定画笔,默认为黑色 //自己定义画笔句柄 HBRUSH hb = nullptr; //画笔句柄 hb = CreateSolidBrush(RGB(0,255,0)); //选择一个GDI(画笔)对象进DC SeletcObject(hdc,hb); //3.绘图 //画一个正圆 Arc(hdc,100,100,400,400,0,0,0,0); //画一个椭圆 Arc(hdc,500,500,600,400,0,0,0,0); //如果有SeletcObject,就一定要用DeleteObject来释放对象 DeleteObject(hb); //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |
颜色COLORREF
COLORREF 是一个unsigned long 的类型,宏 RGB (三原色) A透明度
1 2 3 4 5 6 | RGB(255,0,0); //红色 R RED //红色 G GREEN //绿色 B BLUE //蓝色 对应 0x000000FF 也可以表示红色 |
清屏
1 2 3 4 5 6 7 8 9 | //1.得到设备环境句柄 hdc = GetDC(hWnd); //2.修改设备句柄 RECT r = {0,0,1027,768}; HBRUSH hR = CreateSolidBrush(0xffffff); //创建白色画刷 //3.绘图 FillRect(hdc,&r,hr);//填充矩形 //4.释放设备环境句柄 ReleaseDC(hWnd,hdc); |