Windows API-GDI入门基础知识详解(转)
发布日期:2021-08-29 19:53:17 浏览次数:6 分类:技术文章

本文共 3545 字,大约阅读时间需要 11 分钟。

GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。

  在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。GDI的出现使程序员无需要关心硬件设备及设备驱动,就可以将应用程序的输出转化为硬件设备上的输出,实现了程序开发者与硬件设备的隔离,大大方便了开发工作。

GDI是如何实现输出的?

  要想在屏幕或者其它输出设备上输出图形或者文字,那么我们就必须先获得一个称为设备描述表( DC:Device Context)的对象的句柄,以它为参数,调用各种GDI函数实现各种文字或图形的输出。

设备描述表是GDI内部保存数据的一种数据结构,此结构中的属性内容与特定的输出设备(显示器,打印机等)相关,属性定义了GDI函数的工作细节,在稍后我们将看到如何使用TextOut函数输出文字,在这里属性确定了文字的颜色,x坐标和y坐标映射到窗口显示区域的方式等。

  设备描述表句柄一旦获得,那么系统将使用默认的属性值填充设备描述表结构。

  如果有必要,我们可以使用一些GDI函数获取和改变设备描述表中的属性值。

什么是有效矩形什么是无效矩形?

  当应用程序接受到WM_PAINT消息后通常就准备更新正个显示区域,但是通常只需要更新一个比较小的区域而不是整个区域,这种情况通常出现在当应用程序的主窗口的一部分被一个对话框覆盖,需要重画的只是被覆盖的矩形区域(见下图)。

 

  EXE示例程序下载:(90K, winzip压缩文件)

  阴影以下的部分就是需要更新的矩形区域,该区域就是我们所说的无效区域,正是因为此区域的存在,系统才会向消息队列中放入一个WM_PAINT消息。

  Windows内部为每个窗口都保留了一个绘图结构(PAINTSTRUCT),它包含了包围无效区域的最小矩形的坐标和一些其它信息,需要注意的是当窗口消息处理函数在处理WM_PAINT消息之前显示区域中出现了另一个无效区域,那么Windows会计算出一个包围两个无效区域的新无效区域,并把这种变化保存在绘图结构(PAINTSTRUCT)中,Windows是不会同时把多个WM_PAINT消息同时放到消息队列中的。

  窗口消息处理函数是通过调用InvalidateRect函数使窗口显示区域内的矩形变为无效的,如果消息队列中已经存在一个WM_PAINT消息,那么Windows将计算出新的无效矩形,在接收到WM_PAINT消息的时候,窗口消息处理函数可以获得无效矩形的座标,通过调用GetUpdateRect,可以在任何时候获得这些坐标。

 

如何获取或释放设备描述表句柄?

   当应用程序需要绘图的时候,必须先获取设备描述表句柄,绘图操作结束后必须释放设备描述表句柄。我们有两种方法获取和释放设备描述表句柄。

1. 使用BeginPaint和Endpaint函数

  通常是在应用程序接收到WM_PAINT消息,也就是需要更新窗口的显示区域的时候调用BeginPaint函数获取设备描述表句柄的,使用完后调用Endpaint函数释放设备描述表句柄。

他们的函数原型为:

HDC BeginPaint(

HWND hwnd,,             // handle to window
LPPAINTSTRUCT pPaint   // paint information
);
BOOL EndPaint(
  HWND hWnd,                   // handle to window
  CONST PAINTSTRUCT *pPaint   // paint data
);

  从上面BeginPaint函数的原形中我们可以看到需要一个PAINTSTRUCT结构对象的内存地址,PAINTSTRUCT结构包含在WinUser.h头文件中。

  定义如下:

typedef struct tagPAINTSTRUCT {

  HDC         hdc; //设备描述表句柄
  BOOL        fErase; //擦除状态
  RECT        rcPaint; //无效矩形座标
  BOOL        fRestore;
  BOOL        fIncUpdate;
  BYTE        rgbReserved[32];
}
PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;

  事实上当程序调用BeginPaint函数的时候,Windows会自动的填写此结构的各个属性,而程序作者只需要关心前三个属性。

  第一个属性hdc表示当前的设备描述表句柄。

  第二个属性fErase来说,多数情况下它是被标记成FALSE(0)的,这表示Windows已经擦除了无效矩形的背景,这个擦除动作是是在BeginPaint函数中发生的,而擦除背景用的画刷则是WNDCLASS结构中的hbrBackground属性指定的画刷来擦除背景的,在很多情况下可能程序作者想自己定义一些插除行为,那么可以通过响应消息队列中的WM_ERASEBKGND消息来完成。

  第三个属性rcPaint则表示无效矩形座标,它定义了无效矩形的边界。

  RECT结构可以在WinDef.h头文件中找到。

  定义如下:

typedef struct tagRECT

{
LONG    left;
LONG    top;
LONG    right;
LONG    bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;

  注意,我们在前面提到了InvalidateRect函数,并已经清楚了调用它可以让窗口显示区域内的矩形变为无效,那么我们就可以在处理WM_PAINT消息的时候通过调用它实现在无效矩形外绘图,该调用是在调用BegingPaint函数之前调用的。

  使用方法:

InvalidateRect(hwnd,NULL,TRUE);

  通过上面代码的调用我们让整个显示区域变为了无效,并擦除背景,要注意的是,最后一个参数如果为FALSE,则不擦除背景,原有的东西将保留在原处,这通常是在接受到WM_PAINT消息的时候而不考虑rcPaint属性的情况下简单的重绘整个显示区域最方便的方法,例如,在显示区域内我们输出了一个图形,这个图形的一小部分落在了无效矩形区域内,而这就让绘制这个图形的无效部分变的没有意义,这时就需要重绘整个图形,因为在调用BeginPaint函数传回设备描述表句柄的时候,Windows不会绘制rcPaint也就是无效矩形以外的任何部分。

  对于InvalidateRect函数的详细举例,我们将在以后的章节中看到。

2. 使用GetDC和ReleaseDC函数

  在很多情况下我们可能需要在接收到非WM_PAINT消息的时候获取设备描述表句柄,通过调用GetDC函数我们可以获得设备描述表句柄,因为程序作者可能要使用设备描述表句柄完成其它工作,例如获得设备描述表属性,或者修改设备描述表属性值等,在最后我们与第一种方法一样要释放句柄,通过调用ReleaseDC函数完成工作。

  他们的函数原型为:

HDC GetDC(

  HWND hWnd    // handle to window
);
int ReleaseDC(
        HWND hWnd,  // handle to window
        HDC hDC      // handle to DC
);

  两种方法的区别:

  <1> 使用BeginPaint函数获得的的操作区域是显示区域中的无效矩形区域,接下来绘图操作只能在窗口的无效区域范围内进行,无效区域以外的区域将被忽略不能进行操作,而GetDC函数获得的操作区域则是整个窗口的显示区域,之后的操作可以在任何部分进行,而不只限制在无效区域。

  <2> BeginPaint函数会自动把无效区域变成有效的区域,而GetDC函数则不会将任何无效区域变得有效,必须强行调用ValidateRect函数,并把第二个参数设置为NULL来完成。

  最后我们给出一个可执行程序的例子,当应用程序执行的时候会有一个对话框出现,当你拉动这个对话框的时候又会出现同样的另一个对话框,这就证明了窗口的覆盖会造成无效矩形的出现,系统将会发送WM_PAINT消息。

转自()

转载于:https://www.cnblogs.com/Fightingbirds/archive/2013/01/16/2862140.html

转载地址:https://blog.csdn.net/weixin_34008933/article/details/93233323 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:面试系列之-----Java基础面试题
下一篇:向spider中传递参数

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年03月05日 02时07分27秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

python多线程实现kmeans,3种方式实现python多线程并发处理 2021-06-24
matlab 变量不存在,matlab程序运行时提示变量未定义 2021-06-24
php编码函数 base58,1. Base58可逆加密 2021-06-24
oracle 在需要下列之一,Oracle存储过程中PLS-00103:出现符号“/”在需要下列之一时:(... 2021-06-24
oracle10g dblink优化,Oracle10g通过dblink访问数据异常 2021-06-24
linux安装时的iso文件,直接用ISO文件在linux上安装新系统 2021-06-24
linux修改文件权限为所有人都可以访问,Linux 笔记分享八:文件权限的设定 2021-06-24
linux中卸载ambri-servle,Kerberos 命令使用 2021-06-24
linux二进制反编译,Xori:一款来自BlackHat 2018的二进制反汇编和静态分析工具 2021-06-24
linux两台主机添加信任,Linux两台机器间添加信任,实现不用密码问,互传文件... 2021-06-24
linux 自动获取ssl证书,linux生成自验证ssl证书的具体命令和步骤 2021-06-24
linux基础命令20个,20-linux中基础命令 2021-06-24
重置网络配置 android,重置Android移动网络信号? 2021-06-24
java约瑟夫环pta上_cdoj525-猴子选大王 (约瑟夫环) 2021-06-24
java++记录+运行_记录java+testng运行selenium(三)---xml、ini、excel、日志等配置 2021-06-24
mysql居左查询abcd_MySql速查手册 2021-06-24
loadrunner 错误: 无法找到 java.exe_LoadRunner错误及解决方法总结 2021-06-24
Java小魔女芭芭拉_沉迷蘑菇不可自拔,黏土人《小魔女学园》苏西·曼芭芭拉 图赏... 2021-06-24
php+mysql记事本_一个简单记事本php操作mysql辅助类创建 2021-06-24
300小时成为java程序员_直击面试现场: Java程序员3轮6小时面试, 成功拿到阿里offer!... 2021-06-24