`
wo_deqing
  • 浏览: 60677 次
文章分类
社区版块
存档分类
最新评论

VC GDI编程

 
阅读更多
正文
所谓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)。
分享到:
评论

相关推荐

    JavaScript_catvod的开放版本.zip

    JavaScript

    node-v10.4.1-headers.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v13.8.0-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v14.1.0-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    batik-svggen-1.7.jar

    Batik是为想使用svg格式图片来实现各种功能的应用程序和Applet提供的一个基于java的工具包

    逆波兰式的定义.rar

    逆波兰式

    ChatGPT 技术开发教程指南分享.zip

    ChatGPT 技术开发教程指南分享.zip

    高德导航刷机包winCE

    抓紧看看啊

    UE 剔除透视材质-材质函数(可编辑)

    在虚幻引擎中,当我们向透过外壳看到内部的材质,或者透过布料/盔甲等看到人体,即可通过将该材质函数连接到相应的材质节点图中,达到这样的效果。

    最小生成树的实现原理及java代码实现

    最小生成树的实现原理及java代码实现

    node-v12.22.4-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v12.18.3-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    STM32H562实现UCOS-III优先级翻转【支持STM32H系列单片机】.zip

    STM32H562实现UCOS-III操作系统功能。 项目代码可直接编译运行~

    node-v12.22.10-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    海信智能电视刷机数据 LED32K360J(0000)BOM1 生产用软件数据 务必确认机编一致 强制刷机 整机USB升级程序

    MT5505机芯升级方法: 1、下载数据,压缩包解压,升级软件文件夹名字为Hisense_5505,文件夹下包含“机型名.pkg”以及version.txt 2、将文件夹Hisense_5505,整个文件夹拷贝至U盘根目录下 3、电视关机,插入U盘(USB3或者靠近高频头的USB口),重新启动电视机,电视机自动检测到升级软件之后并进行升级 4、在升级过程中屏幕有相关提示,升级完成后能自动开机。(建议是升级完成之后拔下U盘设备以免下次开机进行重复性升级) 注意: 1、(U盘要求使用FAT32格式,建议4G-8G的品牌U盘,刷机成功率会高) 2、升级到结束,大约需要8-30分钟,中途绝对不能断电 3、升级重启第一次进入系统,请等完全正常进入开机桌面之后,才能拨下U盘 4、如无法升级,将Hisense 5505文件夹内“机型名.pkg”的文件重命名为“upgrade.pkg”,此时插上U盘开机,电视就会默认为强制升级模式

    c语言打字母游戏代码.zip

    c语言打字母游戏代码.zip

    JavaScript_关于世界各地的技术和精通技术的组织如何实践站点可靠性工程SRE的公共可用资源的策划集合.zip

    JavaScript

    node-v18.20.1-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    node-v14.18.0-headers.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    汇编语言实现三款数字电压表

    智能控制-AD0832数字电压表1602液晶程序(汇编语言).zip 智能控制-AD0832数字电压表LED灯实验程序(汇编语言).zip 智能控制-AD0832数字电压表数码管实验程序(汇编语言).zip

Global site tag (gtag.js) - Google Analytics