windows基础应用程序编程(三):GDI简介
2014-08-11 21:09
274 查看
GDI即Graphics Device Interface图形设备接口,计算机的输出设备是由很大的不同的。即使仅对于显示器而言也存在着不同大小的尺寸等等区别。那么为了屏蔽这些区别所造成的程序编写内容的不同。于是,这个东西就诞生了,我们可以利用这个统一的接口,利用GDI为我们提供的绘图函数,来输出我们程序所要求的输出结果。
那么我们该如何去获得这个设备描述表的句柄呢,一般来说,常见的获得设备描述表的方法有两种。(当然实际不止两种,我们这里仅介绍最常用的。)
第一个参数是要重画窗口的句柄,第二个参数是一个指向PAINTSTRUCT结构体的一个指针。返回值为HDC类型,即DC句柄。
我们不妨在看一下PAINTSTRUCT结构的定义:
第一个参数是DC的句柄,第二个参数表示背景是否需要被擦除。如果为TRUE则背景需要擦除,否则不擦出背景。第三个参数为一个RECT结构体的变量,RECT结构体是一个矩形的结构体定义,存储了一个矩形的左上角点的坐标和右下角点的坐标。这里它表示了需要重绘的矩形。(windows一般不需要对整个客户区进行重绘,如果客户区只是部分被遮挡,那么只需要重绘被遮挡的部分。)至于后三个参数是系统保留的,在系统内部被使用,这里不再解释。
大家需要注意的是,lpPaint是一个输出参数,也就是说我们不需要自己去定义这个结构体的各个值,它是由程序自动来填入的。
在获得一个设备描述表句柄之后,我们就可以调用GDI为我们提供的大量绘图函数来对输入设备进行绘制了。一般来讲,这个获得的设备描述表句柄被当做GDI绘图函数的第一个参数。
在绘制完成之后,我们需要释放这个句柄。在函数,WM_PAINT消息的处理中,我们必须成对的使用BeginPaint函数和EndPaint,EndPaint函数即用来释放句柄,它的参数类型和BeginPaint函数一致。
在这里需要说明的是如果我们需要去处理WM_PAINT消息(一般来讲,我们都需要处理这个消息),那么我们就必须调用BeginPaint函数和EndPaint函数。即使我们在这两个函数之间不调用任何GDI绘图函数。另外,在WM_PAINT消息中,我们只能用BeginPaint消息来获得DC句柄。而不能用下面所讲的方法来获得DC句柄。同样,在处理其他消息时,如果我们需要获得设备描述表句柄,我们也不会用BeginPaint函数来获取,而是采用下面所讲述的方法。
我们知道使用BeginPaint获取句柄,将传入一个rcPaint(PAINTSTRUCT结构体里的一个变量)来标识无效矩形的大小。与GetDC函数来获取DC句柄所不同的是,GetDC函数所返回的设备描述表里具有一个剪取矩形,它等于整个客户区,也就是说我们可以在整个客户区而不是仅仅在无效矩形内绘图。
上面说到只有获得一个设备描述表之后,我们才能够进行绘制图形,那么这个设备描述表中到底是什么?在解决这个问题之前,我们不妨来看一个实例。首先来认识一个函数。
这个函数用于在窗口的指定位置处显示一串字符。第一个函数即DC句柄,nXStart和nYStart是要显示字符串的起始位置,lpString是一个字符串的指针,指向我们要显示的字符串。最后一个参数是要显示字符的个数。
了解这个函数之后,如果我们想要在窗口上显示一行字符串,那么我们可以这么去做。在第一篇文章中所讲的框架的基础上,我们在窗口处理函数上添加如下代码:
[align=left][/align]
[align=left][/align]
运行程序,可以看到窗口中显示了“Hello Win32!”,如下所示:
[align=left] 我们在调用TextOut函数时,可以看到我们只像这个函数中去传入了要显示的字符串,以及字符个数,和要显示的位置。但是,我们并没有看到传入字体的大小,字体的样式,颜色等等信息,那么windows是如何知道显示出这样的样子呢?[/align]
这就是在设备描述表中为我们定义的,也就是说,设备描述表中的某些值是图形的“属性”。我们可以通过一些函数从设备描述表中来设置和获取这些值。
介绍到这里,其实我们只是仅仅的介绍了GDI的九牛一毛的东西。GDI是个相当庞大的东西,但是我们了解了这些之后,就可以很容易的利用GDI提供的一些绘图函数来绘制一些简单的图形了,至于绘图中其他的内容,我们将在以后穿插进行讲解,比如绘制文字体等等。
点的绘制
X,Y为要绘制点的坐标,crColor为COLORREF类型值,COLORREF为一个32位的数表示要绘制的颜色,高八位为0,后面以此为蓝色分量,绿色分量和红色分量。我们可以通过RGB宏来进行设置。
直线的绘制
设置直线绘制的起点,lpPoint为先前的位置,如果不需要这个值,一般设置为NULL
要绘制直线的重点坐标。
矩形的绘制
参数分别代表矩形左上角和右下角点的坐标。
椭圆的绘制
参数和矩形绘制参数一直,该椭圆为这个矩形的内切圆。
圆角矩形
借用windows程序设计一书中的配图来说明参数含义:
曲线的绘制
点(xStart,yStart)和(xEnd,yEnd)之所以不定义在矩形的边上,是为了保持更大的灵活性。
其他绘图函数,再次不再一一介绍,大家可以查看MSDN来获得。
当我们改变窗口大小时,Windows将会给窗口过程发送一个WM_SIZE消息。并且在传给窗口过程中的lParam(还记得消息是一个MSG结构体,在结构体里存在着lParam的变量,作为附属信息吗?)参数的低位字中包含客户区的宽度,高位字包含客户区的高度。所以我们可以通过处理这个参数来获得客户区的大小。
仍然使用之前的框架,在窗口过程函数中这些更改代码:
[align=left][/align]
[align=left][/align]
设备描述表
GDI中有一个很重要的概念,我们称之为设备描述表,简称为DC。实际上它是GDI内部所保存的一个数据结构,DC与特定的输出设备有关系。我们可以把它理解成沟通我们程序与具体的显示设备之间的桥梁。当我们需要在一个输出设备上输出图形时,我们首先必须要获得一个设备描述表的句柄。(还记得句柄就是一个数值,简答的用于标识windows中的某些东西吗?)当这个句柄返回给程序时,Windows函数就给了我们使用输出设备的权限。那么我们该如何去获得这个设备描述表的句柄呢,一般来说,常见的获得设备描述表的方法有两种。(当然实际不止两种,我们这里仅介绍最常用的。)
第一种方法
通过我们上一篇文章的学习,我们了解到了WM_PAINT消息是“需要回复以前窗口时”即重画窗口时,所产生的消息。那么既然要重画窗口,根据之前所讲的,如果要在窗口上绘制,那么首先我们必须要获得一个设备描述表句柄,那么在处理WM_PAINT消息中,我们在哪里看到获取到设备描述表句柄了呢?还记得上一篇文章中在介绍WM_PAINT消息一般的处理过程时的内容吗?可能大家已经猜到了,是的,我们通过BeginPaint函数就可以或得一个设备描述表句柄。我们首先来看看这个函数的原型。HDC BeginPaint( HWND hwnd, LPPAINTSTRUCT lpPaint );
第一个参数是要重画窗口的句柄,第二个参数是一个指向PAINTSTRUCT结构体的一个指针。返回值为HDC类型,即DC句柄。
我们不妨在看一下PAINTSTRUCT结构的定义:
typedef struct tagPAINTSTRUCT { HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved[32]; }PAINTSTRUCT;
第一个参数是DC的句柄,第二个参数表示背景是否需要被擦除。如果为TRUE则背景需要擦除,否则不擦出背景。第三个参数为一个RECT结构体的变量,RECT结构体是一个矩形的结构体定义,存储了一个矩形的左上角点的坐标和右下角点的坐标。这里它表示了需要重绘的矩形。(windows一般不需要对整个客户区进行重绘,如果客户区只是部分被遮挡,那么只需要重绘被遮挡的部分。)至于后三个参数是系统保留的,在系统内部被使用,这里不再解释。
大家需要注意的是,lpPaint是一个输出参数,也就是说我们不需要自己去定义这个结构体的各个值,它是由程序自动来填入的。
在获得一个设备描述表句柄之后,我们就可以调用GDI为我们提供的大量绘图函数来对输入设备进行绘制了。一般来讲,这个获得的设备描述表句柄被当做GDI绘图函数的第一个参数。
在绘制完成之后,我们需要释放这个句柄。在函数,WM_PAINT消息的处理中,我们必须成对的使用BeginPaint函数和EndPaint,EndPaint函数即用来释放句柄,它的参数类型和BeginPaint函数一致。
在这里需要说明的是如果我们需要去处理WM_PAINT消息(一般来讲,我们都需要处理这个消息),那么我们就必须调用BeginPaint函数和EndPaint函数。即使我们在这两个函数之间不调用任何GDI绘图函数。另外,在WM_PAINT消息中,我们只能用BeginPaint消息来获得DC句柄。而不能用下面所讲的方法来获得DC句柄。同样,在处理其他消息时,如果我们需要获得设备描述表句柄,我们也不会用BeginPaint函数来获取,而是采用下面所讲述的方法。
第二种方法
另外一种得到窗口客户区的设备描述表句柄的方法是GetDC函数。这个函数只有一个参数,即窗口的句柄。这个函数和ReleaseDC来成对使用,即如下所示:hdc = GetDC(hwnd); // 调用GDI绘图函数 ReleaseDC(hwnd,hdc);
我们知道使用BeginPaint获取句柄,将传入一个rcPaint(PAINTSTRUCT结构体里的一个变量)来标识无效矩形的大小。与GetDC函数来获取DC句柄所不同的是,GetDC函数所返回的设备描述表里具有一个剪取矩形,它等于整个客户区,也就是说我们可以在整个客户区而不是仅仅在无效矩形内绘图。
上面说到只有获得一个设备描述表之后,我们才能够进行绘制图形,那么这个设备描述表中到底是什么?在解决这个问题之前,我们不妨来看一个实例。首先来认识一个函数。
BOOL TextOut(HDC hdc, int nXStart, int nYStart, LPCTSTR lpString, int cbString);
这个函数用于在窗口的指定位置处显示一串字符。第一个函数即DC句柄,nXStart和nYStart是要显示字符串的起始位置,lpString是一个字符串的指针,指向我们要显示的字符串。最后一个参数是要显示字符的个数。
了解这个函数之后,如果我们想要在窗口上显示一行字符串,那么我们可以这么去做。在第一篇文章中所讲的框架的基础上,我们在窗口处理函数上添加如下代码:
[align=left][/align]
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; TCHAR *szBuffer = _T( "Hello Win32!" ); switch (message) { case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); TextOut( hdc, 10, 20, szBuffer, lstrlen(szBuffer) ); EndPaint( hWnd, &ps ); break ; case WM_DESTROY: PostQuitMessage(0); break ; default : return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
[align=left][/align]
运行程序,可以看到窗口中显示了“Hello Win32!”,如下所示:
[align=left] 我们在调用TextOut函数时,可以看到我们只像这个函数中去传入了要显示的字符串,以及字符个数,和要显示的位置。但是,我们并没有看到传入字体的大小,字体的样式,颜色等等信息,那么windows是如何知道显示出这样的样子呢?[/align]
这就是在设备描述表中为我们定义的,也就是说,设备描述表中的某些值是图形的“属性”。我们可以通过一些函数从设备描述表中来设置和获取这些值。
介绍到这里,其实我们只是仅仅的介绍了GDI的九牛一毛的东西。GDI是个相当庞大的东西,但是我们了解了这些之后,就可以很容易的利用GDI提供的一些绘图函数来绘制一些简单的图形了,至于绘图中其他的内容,我们将在以后穿插进行讲解,比如绘制文字体等等。
常用函数
下面简单的介绍几个GDI绘图函数。具体参数含义以及更复杂的图像函数,在需要时,可以通过查找MSDN上来获取。点的绘制
COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF crColor);
X,Y为要绘制点的坐标,crColor为COLORREF类型值,COLORREF为一个32位的数表示要绘制的颜色,高八位为0,后面以此为蓝色分量,绿色分量和红色分量。我们可以通过RGB宏来进行设置。
直线的绘制
BOOL MoveToEx(HDC hdc, int X, int Y, LPOINT lpPoint);
设置直线绘制的起点,lpPoint为先前的位置,如果不需要这个值,一般设置为NULL
BOOL LineTo( HDC hdc, int nXEnd, int nYEnd );
要绘制直线的重点坐标。
矩形的绘制
BOOL Rectangle( HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect );
参数分别代表矩形左上角和右下角点的坐标。
椭圆的绘制
BOOL Ellipse( HDC hdc, int nLeftRect, int nTopRect, nRightRect, int nBottomRect );
参数和矩形绘制参数一直,该椭圆为这个矩形的内切圆。
圆角矩形
BOOL RoundRect( HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int xCornerEllipse, int yCornerEllipse );
借用windows程序设计一书中的配图来说明参数含义:
曲线的绘制
BOOL Arc( HDC hdc, int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nXStartArc, int nYStartArc, int nXEndArc, int nYEndArc );
点(xStart,yStart)和(xEnd,yEnd)之所以不定义在矩形的边上,是为了保持更大的灵活性。
其他绘图函数,再次不再一一介绍,大家可以查看MSDN来获得。
实例
现在我们仍然使用Windows程序设计一书中的例子来简单的用一下这个函数,在使用之前,我们来简单说明一下WM_SIZE消息。当我们改变窗口大小时,Windows将会给窗口过程发送一个WM_SIZE消息。并且在传给窗口过程中的lParam(还记得消息是一个MSG结构体,在结构体里存在着lParam的变量,作为附属信息吗?)参数的低位字中包含客户区的宽度,高位字包含客户区的高度。所以我们可以通过处理这个参数来获得客户区的大小。
仍然使用之前的框架,在窗口过程函数中这些更改代码:
[align=left][/align]
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxClient, cyClient; HDC hdc; PAINTSTRUCT ps; switch (message) { case WM_SIZE: cxClient = LOWORD( lParam ); cyClient = HIWORD( lParam ); break ; case WM_PAINT: hdc = BeginPaint( hWnd, &ps ); Rectangle( hdc, cxClient/8, cyClient/8, 7*cxClient/8, 7*cyClient/8 ); MoveToEx( hdc, 0, 0, NULL ); LineTo( hdc, cxClient, cyClient ); MoveToEx( hdc, 0, cyClient, NULL ); LineTo( hdc, cxClient, 0 ); Ellipse( hdc, cxClient/8, cyClient/8, 7*cxClient/8, 7*cyClient/8); RoundRect( hdc, cxClient/4, cyClient/4, 3*cxClient/4, 3*cyClient/4, cxClient/4, cyClient/4 ); EndPaint( hWnd, &ps ); break ; case WM_DESTROY: PostQuitMessage(0); break ; default : return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
[align=left][/align]
运行结果
相关文章推荐
- windows基础应用程序编程(八)控件简介(一)
- windows基础应用程序编程(九)控件简介(二)
- Windows窗体编程基础学习:使用 NotifyIcon 组件向任务栏添加应用程序图标
- windows基础应用程序编程(五):图标和加速键
- windows编程之GDI基础(一)
- windows基础应用程序编程(十三)定时器
- Windows编程基础与GDI绘图基本框架复习
- windows基础应用程序编程(二):消息说明
- windows基础应用程序编程(十一)对话框
- windows基础应用程序编程(七)鼠标消息
- Microsoft 用于构建面向服务的应用程序的统一编程模型--Indigo简介 - WCF(WindowsCommunicationFoundation)构建面向服务的分布式应用
- windows基础应用程序编程(四):菜单
- windows基础应用程序编程(十)子类和超类
- Windows窗体编程基础学习:使用 NotifyIcon 组件向任务栏添加应用程序图标
- GDI 编程基础简介
- windows基础编程----第四篇(调用GDI绘制出相关图形)
- windows基础应用程序编程(六)键盘消息
- windows基础应用程序编程(一):基本框架
- Windows窗体编程基础学习:使用 NotifyIcon 组件向任务栏添加应用程序图标
- Windows窗体编程基础学习:使用 NotifyIcon 组件向任务栏添加应用程序图标