GDI编程基础总结

来源:互联网 发布:淘宝人生全文阅读小说 编辑:程序博客网 时间:2024/06/05 08:30

所谓GDI就是图形设备接口(Graphics Device Interface)的英文缩写。负责在显示器和打印机上显示图形 。Windows给我们展现的丰富的图形界面都是靠GDI接口函数来实现,如果我们想在窗口上画一条线,贴上一张图都需要通过图形设备接口来实现。所以说系统和用户完成图形元素的显示都是调用的同一套接口。

在打印机上显示图形对于身为学生的我们还难以有实践机会,而在显示器和打印机上显示图形的原理大致相同。所以这里的总结重点是在显示器上显示图形。

计算机图形输出设备分为两大类:光栅设备(Raster devices)和矢量设备(Vector devices) 。我们的重点是在光栅设备上显示图形。所谓光栅设备就是以像素为基础方式的图形显示设备。如:显示器、投影仪、打印机等。

下面是我绘制的一张结构图。



图很简单,里面的东西足够我们慢慢的去深入体会理解和实践。

这里重点需要理解的是DC。DC(Device Context设备描述表),我们可以把它看做系统提供给我们让我们能够在显示器上显示元素的所有必需资源。
在Windows中代表DC的就是设备描述表句柄。要在一个图形输出设备上绘图时,首先必须获得一个设备描述表句柄。将句柄传回给程序时,Windows就赋予了程序使用设备的权限。
特别注意:设备描述表句柄的取得和释放必须成对使用,否则会引起严重问题。

获取设备环境句柄有多种方法:

1.在处理WM_PAINT消息时,使用BeginPaint()和EndPaint()调用
case WM_PAINT:           hdc = BeginPaint (hwnd, &ps) ;          .......使用GDI函数...........                  EndPaint (hwnd, &ps) ;          return 0;
需要注意的是它们两个是配对的
变量ps是型态为PAINTSTRUCT的结构(见MSDN),其定义如下
typedef struct tagPAINTSTRUCT {   HDC  hdc;   BOOL fErase;   RECT rcPaint;   BOOL fRestore;   BOOL fIncUpdate;   BYTE rgbReserved[32]; } PAINTSTRUCT, *PPAINTSTRUCT; 

该结构的hdc字段是BeginPaint传回的设备内容句柄。 PAINTSTRUCT结构又包含一个名为rcPaint的RECT(矩形)结构,rcPaint定义一个包围窗口显示区域无效范围的矩形。使用从BeginPaint获得的设备描述表句柄,只能在这个区域内绘图。BeginPaint调用使该区域有效。
重点理解:
DC(Device Context)设备描述表,我们取得HDC就相当于拿到了设备描述表。hdc有多种拿法,但是在WM_PAINT下只有这种拿法,同时在别处也不能用这种拿法。这种方法只能绘制无效区。有效区不绘制。


2.在处理非WM_PAINT消息时取得设备描述表句柄
hdc = GetDC (hwnd) ;……        ReleaseDC (hwnd, hdc) ;

这个设备描述表适用于窗口句柄为hwnd的显示区域。这些调用与BeginPaint和EndPaint组合之间的基本区别是,利用从GetDC传回的句柄可以在整个显示区域(客户区域)上绘图。GetDC和ReleaseDC不使显示区域中任何可能的无效区域变成有效。

3. 取得适用于整个窗口(而不仅限于窗口的显示区域)的设备内容句柄
hdc = GetWindowDC (hwnd) ;        ……        ReleaseDC (hwnd, hdc) ;

这个设备描述表除了显示区域之外,还包括窗口的标题列、菜单、滚动条和框架(frame)。
GetWindowDC函数很少使用,如果想尝试用一用它,则必须拦截处理WM_NCPAINT消息,Windows使用该消息在窗口的非显示区域上绘图。

4. 取得设备描述表句柄的更常用的函数是CreateDC
hdc = CreateDC (pszDriver, pszDevice, pszOutput, pData) ;        ……     DeleteDC (hdc) ;

例如,你可以通过调用下面的函数获取当前整个屏幕的设备环境句柄:
hdc = CreateDC(TEXT("DISPLAY"),NULL,NULL,NULL);
在窗口外输出文字或图像不是很好,但是对于一些特殊的应用还是有用的。比如酷我K歌这些软件播放音乐时在屏幕上显示歌词的应用。

使用位图时,取得一个“内存设备描述表”有时是有用的(扫雷就可以用此方法)
hdcMem = CreateCompatibleDC (hdc);        ……        DeleteDC (hdcMem) ;

总结到此忽然想到某次在倒腾一个例程,我把WM_PAINT消息下的BeginPaint()和EndPaint()调用全部注释掉了,就像下面这样
case WM_PAINT:      MessageBox(NULL,TEXT("xiaobai"),TEXT("test"),0);      return 0;
然后奇怪的事情发生了,程序编译运行后窗口就一直在那里闪,当时很奇怪为什么会出现这种情况。后来看书才明白原来是因为客户区在无效时,windows才会在消息队列中放置一条WM_PAINT消息,除非调用BeginPaint()和EndPaint()函数对(或者ValidateRect()),否则Windows不会将那个区域有效化。在我们的程序创建时系统发送了WM_PAINT消息,但是在响应消息时没有调用BeginPaint()使窗口有效,因此,Windows将会不停地在那里发生WM_PAINT消息,直到永远。这就是为什么闪屏的原因。

看来技术这东西真的很需要注重细节,学习一门新技术时一定要先狠狠的扎实基础,不让在后续的进阶过程中真的会让人很头疼!





原创粉丝点击