正文
所谓GDI(Graphics Device Interface,图形设备接口)其实就是API函数中专门针对于图形开发的函数集合这些函数都是Microsoft公司编写好的,为了能让开发人员快速地开发图形程序,开发人员只需要调用就行
在谈GDI函数之前,一定要先讲一下数据,因为图形开发,肯定离不开数据以简单的二维图形为例,你想在窗口中显示一个正弦曲线,就必须有这个正弦曲线的数据,然后用GDI提供的画图函数,讲数据显示成图形
二维图形其实就是以点线面三种元素组成
点
图形中最基本的元素就是点,C++中对于点的结构定义是
typedef struct tagPOINT
{
LONG x;
LONG y;
} POINT;
就是由横坐标x和纵坐标y组成的一个点(这个中学生就懂,呵呵,那也不能省)
GDI中将点画到窗口中的函数是SetPixel
线
线就是有序的点集合,可以用一个点数组表示一条线,也可以用链表来表示一条线,两者的区别就在于添加和删除线中一点的方便程度数组的优点在于存取方便,但添加和删除确比较麻烦,链表优点在于添加和删除方便,但系统开销比数组大具体大家在开发中是利用数组还是链表,需要根据具体需求来决定GDI中使用MoveToLineTo和PolyLine函数来绘制线
面
面也是由一组有序点组成的,它和线的唯一区别在于绘制的时候需要用不同的函数来实现而且绘制面的时候,需要将数据以数组方式存储,因为GDI函数绘制面的函数Polygon和PolyPolygon不支持链表
GDI函数
纯API开发C++程序,开发效率有限,而利用MFC对于VC开发效率有很大的提高,所以我们这以MFC开发为例说明GDI开发
GDI开发中第一个概念就是DC(Device Context),大部分的书都翻译成设备上下文,这其实是一种直译,很多新手(我当初就是其中之一,呵呵)看到设备上下文的时候,都不知道是什么东西可以简单理解为画布,或当前窗口中绘图控制的一个接口它是一个抽象集合或抽象概念,用它可以有效地管理画笔刷子字体图片和区域
CDC就是MFC中,对应DC的类
以CDC来绘制窗口内图形的步骤
1. 获取当前窗口的DC,获取窗口DC可以用CDC* CWnd::GetDC()函数得到一个CDC指针,
2. 得到DC指针后,先调用CDC::SelectObject 函数来设定画笔刷子字体图片和区域等绘图设置工作
3. 调用绘图函数SetPixel绘制点,MoveToLineTo和PolyLine绘制线,Polygon和PolyPolygon绘制面
4. 调用CDC::SelectObject恢复绘图前的设定
5. 释放资源,其中就有DC的释放,CWnd::ReleaseDC(CDC* pDC),将最开始获取的DC指针释放
2.CDC与HDC的区别
CDC是MFC的DC的一个类<wbr></wbr>
HDC是DC的句柄,API中的一个类似指针的数据类型.<wbr></wbr>
MFC类的前缀都是C开头的<wbr></wbr>
H开头的大多数是句柄
<wbr><div>CDC是所有MFC中的DC的基类.常用的CClientDC dc(this);就是CDC的子类(或称派生类).<wbr></wbr>
</div>
<div>CDC等设备上下分类,都含有一个类的成员变量:m_nHdc;即HDC类型的句柄.</div>
<div></div>
<div>3.CDC对象提供处理显示器或打印机等设备上下文的成员函数,以及处理与窗口客户区对应的显示上下文的成员。 </div>
<div></div>
<div>4.<span class="headline-content">有关CDC类的继承</span> </div>
<div> 父类:从 CObject 直接<a href="http://baike.baidu.com/view/125322.htm" target="_blank">继承</a>而来。继承了CObject类的各种特性,如动态创建等等。</div>
<div> 子类:CClientDC-------代表操作窗口的DC ,是比较常用的一个子类 </div>
<div> CMetaFileDC ------响应Meta File的DC ,Meta File是一些GDI消息。 </div>
<div> CPaintDC-------响应<a href="http://baike.baidu.com/view/1988590.htm" target="_blank">WM_PAINT消息</a>的DC。</div>
<div> CWindowDC ------代表整个屏幕的DC</div>
<div></div>
<div>5.内存DC</div>
<div>在windows下搞图形界面的设计难免要使用到内存DC,将所有的绘制工作先绘制在内存DC上,然活一次性拷贝到屏幕DC上,就是这样了。可以消除一些图形的闪烁问题,当然还有其他的用处,比如简单游戏中的象素碰撞检测等等</div>
<div>5.1创建内存DC</div>
<div> HDC hdc = ::GetDC(NULL); <br>
CDC *pDC = CDC::FromHandle(hdc); //创建兼容DC(屏幕)<br>
CDC imageMemDC;<br>
imageMemDC.CreateCompatibleDC(pDC);</div>
<div></div>
<div>6.OnPaint与OnEraseBkgnd() </div>
<div>在MFC中 任何一個window元件的繪圖 都是放在這兩個member function中<br><span style="color:#ff0000">在設定上 OnEraseBkgnd()是用來畫底圖的 而OnPaint()是用來畫主要物件的</span><br><span style="color:#ff0000">舉例說明 一個按鈕是灰色的 上面還有文字</span><br><span style="color:#ff0000">則OnEraseBkgnd()所做的事就是把按鈕畫成灰色</span><br><span style="color:#ff0000">而OnPaint()所做的事 就是畫上文字</span><br><br><br>
既然這兩個member function都是用來畫出元件的<br>
那為何還要分OnPaint() 與 OnEraseBkgnd() 呢<br>
其實<span style="color:#ff0000">OnPaint() 與 OnEraseBkgnd() 特性是有差的</span><br>
1. <span style="color:#ff0000">OnEraseBkgnd()的要求是快速在裡面的繪圖程式最好是不要太耗時間</span><br><span style="color:#ff0000">因為每當window元件有任何小變動都會馬上呼叫OnEraseBkgnd()</span><br>
2. <span style="color:#ff0000">OnPaint() 是只有在程式有空閒的時候才會被呼叫</span><br>
3. <span style="color:#ff0000">OnEraseBkgnd() 是在 OnPaint() 之前呼叫的</span><br>
所以 <span style="color:#ff0000">OnPaint()被呼叫一次之前 可能會呼叫OnEraseBkgnd()好幾次</span>
</div>
<div>
<span style="color:#ff0000"></span>
</div>
<span style="color:#ff0000"></span></wbr>
7.Onpanit与OnEraseBkgnd()
1. 系统的Onpaint中调用了OnDraw,但如果我们自己继承了一个OnPaint函数又没有显式调用OnDraw,则OnDraw就不会被调用
2.OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。OnDraw()是CVIEW的成员函数,没有响应消息的功能.当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数.OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。
3.
8.OnCtlColor 返回HBRUSH句柄,用该句柄来绘制窗口背景色,
例如
HBRUSH CtestOnPaintDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
//m_brBk.CreateSolidBrush(RGB(113 , 111 , 100)); //创建刷子,在初始化或者其他函数中调用
return (HBRUSH)m_brBk.GetSafeHandle();
return hbr;
}
9.资源释放
在windows系列上做编程,gdi是一个很重要的技术点,有很多程序在运行多次后出现异常,除了众所周知的内存泄露以外,gdi资源泄露也是一个很直接的原因.今天就把我自己在编程中总结的一些经验给大家分享,欢迎高手补充.
1.Create出来的gdi对象,一定要用DeleteObject来释放,释放顺序是先Create的后释放,后Create的先释放.
这里的Create指的是以它为开头的gdi函数,比如,CreateDIBitmap,CreateFont等等,最后都要调用DeleteObject来释放.
2.Create出来的dc要用DeleteDC来释放,Get到的要用ReleaseDC释放.
3.确保释放DC的时候DC中的各gdi对象都不是你自己创建的;确保个gdi对象在释放的时候不被任何dc选中使用.
假如我们要使用gdi函数画图,正确的步骤应该如下:
a.创建一个内存兼容dc(CreateCompatibleDC)
b.创建一个内存兼容bitmap(CreateCompatibleBitmap)
c.关联创建的内存兼容dc和bitmap(SelectObject)
d.画图
e.BitBlt到目的dc上
f.断开内存兼容dc和bitmap关联(SelectObject)
g.销毁内存兼容bitmap
h.销毁内存兼容dc
由于SelectObject在选入一个新的gdi对象的时候会返回一个原来的gdi对象(假如成功的话),所以需要在步骤c的时候保存返回值,在步骤f的时候当作入口参数使用.还有,步骤g和步骤h实际上顺序可以随意,因为他们两个此刻已经没有关系了,但是为了结构清晰,我建议按照"先Create的后释放,后Create的先释放"的原则进行.
关于步骤f,可能会有争议,因为即使省略这一步,步骤g和步骤h看起来照样可以返回一个成功的值.但实际上可能并没有执行成功,至少boundschecker会报告有错,错误信息大致是说,在释放dc的时候还包含有非默认的gdi对象,在释放gdi对象的时候又说这个gdi对象还被一个dc在使用.所以,我建议保留步骤f.
案例:
HWND playWnd = GetPlayWnd();
HDC hdc = ::GetDC(playWnd);
CDC *playDC = CDC::FromHandle(hdc);
::ReleaseDC(playwnd,hDC); //释放
CDC *playDC = CDC::FromHandle(hdc); 要不要释放呢? 不是 "可以不释放 ",而是 "不可以释放 ". FromHandle 是通过 HDC 来创建了一个 CDC 对象,以方便操作,释放 DC 的操作应该针对于 HDC 而非此 CDC , 如果释放了它 pDC-> ReleaseDC ,就会造成隐患. 只能释放一次.
8. HBITMAP使用心得
HBITMAP m_hBitmap = (HBITMAP)::LoadImage(NULL, "D:\\fdf.bmp", IMAGE_BITMAP, 0, 0,
LR_DEFAULTSIZE | LR_CREATEDIBSECTION | LR_LOADFROMFILE);
HBITMAP在初始化后就 保留图片数据,即便图片被删除,m_hBitmap里的数据也不会丢失,指导它被删除前.
9.关于CDialog::OnPaint。
如果自己的OnPaint代码什么也没做的话(至少没有声明过CPaintDC类型的变量),还必须调用一下CDialog::OnPaint,否则BeginPaint和EndPaint就没有办法被调用了。
总之,在响应WM_PAINT消息的时候,必须调用一遍BeginPaint和EndPaint。调用的方法有三种:
1、声明一个CPaintDC类型的变量(即使你什么也不画),CPaintDC的构造函数就是调用BeginPaint,析构函数就是调用EndPaint。
2、调用基类的OnPaint(实际上就是调用API的DefWindowProc,它会自动调用BeginPaint和EndPaint)。
3、自己直接调用BeginPaint和EndPaint。
上述三种方法,
必须选择其一,而且也只能选择其一(因为在一个WM_PAINT消息内不能调用两次BeginPaint和EndPaint)。
分享到:
相关推荐
**VC GDI编程源码实例集** VC++(Visual C++)是Microsoft开发的一个集成开发环境,它提供了对Windows API的全面支持,其中GDI(Graphics Device Interface)是Windows操作系统的核心图形库,用于处理图形输出任务...
本文将详细介绍VC GDI编程环境下字体和文本的处理方法,旨在帮助开发者更好地理解和应用这些技术。 #### 二、字体概述 **1. 字体定义** 字体是文字显示和打印的外观形式,包含了字样、风格和尺寸等属性。合理运用...
本文将深入探讨VC中精通GDI+编程的关键知识点。 1. **GDI+基础概念**:GDI+是Windows编程中用于图形输出的一种API,它包括了线条、曲线、形状、图像、文本等元素的绘制和操作。与传统的GDI相比,GDI+引入了对象模型...
**GDI编程基础** 主要包括以下几个方面: 1. **设备上下文(Device Context, DC)**:DC是GDI的核心概念,它是一个接口,用于与特定设备(如显示器或打印机)进行通信。通过DC,开发者可以控制绘图操作,如选择字体...
精通gdi 编程 VC pdf版本 学习GDI+编程的方法技巧
VC图形编程是基于Microsoft Visual C++ (VC++) ...总结起来,VC图形编程涉及GDI、设备环境DC及其在MFC中的实现,通过这些工具,开发者可以构建丰富的图形用户界面,并在Windows平台上实现高效且灵活的图形绘制功能。
总的来说,通过熟练掌握GDI+编程,我们可以创建出具有独特视觉效果和实用功能的桌面挂件。这个过程涉及到Windows编程基础、图形绘制技巧以及对时间处理的理解。通过实践,你不仅可以制作出这个时钟挂件,还能进一步...
精通GDI+编程 本书详细介绍了GDI+的所有技术细节和操作技巧,并配之以详尽的程序源代码,使读者更快,更好的掌握GDI+编程。
GDI+是微软开发的一个图形设备接口,它在Windows编程中提供了一套强大...通过以上知识点,你应该能理解在VC6环境下如何配置和使用GDI+进行图形编程。请确保正确引用和链接所需的文件,以便充分利用GDI+提供的强大功能。
在VC环境下,GDI编程通常涉及创建设备上下文(Device Context, DC),定义图形对象(如画笔、刷子和字体),并利用这些对象在窗口或内存设备上下文中绘制。压缩包中的源码实例可能包括了创建自定义控件、绘制动态...
在本文中,我们将深入探讨如何在VC6中有效地利用GDI+进行编程。 首先,让我们了解GDI+的基本概念。GDI+(Graphics Device Interface Plus)是微软推出的一种面向对象的图形库,它在原有的GDI(Graphics Device ...
标签"vc_gdi 古诗"进一步强调了这个项目的核心内容:VC++编程与GDI技术的结合,以及古诗的展示。文件列表中提到的"3-1"可能是源代码文件或者资源文件,但具体的细节需要解压缩后查看。 总的来说,这个项目是学习和...
在Windows编程领域,GDI+(Graphics Device Interface Plus)是一种强大的图形绘制库,它扩展了传统的GDI功能,提供了更多的图形处理能力。然而,在进行动态图形更新时,尤其是在VC6环境下,用户界面可能会出现闪烁...
在Windows编程领域,GDI(Graphics Device Interface)是微软提供的一种图形设备接口,它允许程序员创建和控制应用程序的图形输出。而GDI++是GDI的扩展,它引入了C++类库,使得图形操作更加面向对象,更易于理解和...
综上所述,这个GDI_VC示例项目为初学者提供了直观的GDI应用实践,通过实际操作理解GDI的基本绘图原理和方法,从而掌握Windows编程中的图形界面设计。通过运行程序并观察不同按钮触发的图形效果,可以深入学习和体会...
本资源“GDIP.rar_vc GDI”主要涵盖了如何在VC++中利用GDI+进行编程,以及解决与配置相关的问题。 GDI+的主要优势在于其支持矢量图形、高级文本渲染、图像处理等功能,使得开发者可以创建出更加美观且动态的用户...
对于使用Visual C++ 6.0(简称VC6.0)的老版本开发环境的程序员来说,尽管VC6.0本身并不直接支持GDI+,但通过特定的配置和安装步骤,我们仍然可以在VC6.0中使用GDI+进行图形编程。下面将详细介绍如何在VC6.0中搭建...
学习VC图形图像编程,你需要理解GDI/GDI+的基本概念,掌握如何创建设备上下文(DC)、画笔、画刷、字体以及如何绘制基本形状和文本。 其次,DirectX是微软推出的一套用于游戏开发和多媒体应用的API,它包括了图形、...
第二章 GDI+编程基础 第三章 画笔和画刷 第四章 文本和字体 第五章 路径和区域 第六章 在GDI+中使用变换 第七章 GDI+的色彩变换 第八章 图像的基本处理 第九章 调整图像的色彩信息 第十章 图形的编码与解码 第十一章...