能不能剔除当前被selectobject函数选进的对象

编程入门网-『VC++技术内幕』学习笔记(7)
您的位置:&&
『VC++技术内幕』学习笔记(7)
文章来源:互联网
作者:雷神
转载请联系作者
第七篇:图形设备接口(GDI)
  我想大家和我一样通过前几天的学习,对VC++MFC应用程序框架的神奇功能有了一些了解,但是还是感觉不能驾御这个强的开发工具,不过别担心,我170多斤体重不是一口吃出来的,是经过了30年不懈的努力才吃成了如此“魁梧”的体形,呵呵开个玩笑。所以学习也一样。学VC尤其如此。还有我发现很多好的技术类书籍有一个共同的特点,就是在前几章学到了一些东西在你正在疑惑或者苦苦领会的时候,接下来的章节便给你解除疑惑。雷神经验:遇到实在想不明白的地方先放下,继续向下读,也许读着读着前面的问题就明白了。『VC++技术内幕』当然属于好的技术书籍一类,所以在本书第五章开始仔细的给我们讲解设备环境类和图形设备接口(GDI),使得我们能守得云开见月明。
设备环境类CDC:
  CDC是设备环境类的基类直接由CObject派生。是GDI的关键元素,它代表了物理设备。每一个C++设备环境对象都有相对应Windows设备环境,并通过一个32位类型的HDC句柄来标识。CDC类的虚拟性使我们可以很容易的做到编写同时适用于多种设备的代码。例如OnDraw函数的pDC-&TextOut(0,0,"Hello");既可以适用于显示器、还可以适用于打印预览和打印,只需要在CView::OnDraw函数的pDC参数指向不同的对象类。
CClientDC和CWindowDC是显示设备环境类,都是由CDC派生而来,区别在于CClientDC是窗口的客户区不包括边框、标题栏和菜单栏,(0,0)指客户区域的左上角。CWindowDC的(0,0)指整个屏幕的左上角,这意味着我们可以在显示器的任意地方绘图,包括窗口边框、标题栏和菜单栏等等。CWindowDC一般应用在框架窗口,而不是视图窗口。
CDC对象被创建后一定要在合适的时候将它删除掉,如果忘记了删除设备环境对象则会造成内存丢失。如何做才能避免出现这个问题呢,我们应该在堆栈中构造对象。
//***************************
// 例子7-1
void CMyView::OnLButtonDown(UINT nFlags,CPoint point)
CClientDC dc(this); //在堆栈中构造设备环境对象,用一个窗口指针this作参数。
dc.GetClipBox(rect); //GetClipBox函数是一个虚函数,作用是可以获得选定区域的尺寸
//析构函数在函数返回时自动调用,也就完成对设备环境对象的删除。
书上还给出了另一种写法:
void CMyView::OnLButtonDown(UINT nFlags,CPoint point)
CDC * pDC=GetDC(); //通过调用CWnd的GetDC()函数获得设备环境指针
pDC-&GetClipBox(rect); //可以获得选定区域的尺寸
ReleaseDC(pDC); //一定不能忘记,释放设备环境。(书上又写错了)
  创建的设备环境对象具有一些默认的特性,通过CDC类的成员函数可以设定这些特性。例如前一篇笔记用到的刷子、映射模式等等。我们还可以通过重载SelectObject函数将GDI对象选进设备环境中。
GDI对象是通过CGdiObject派生类的C++对象来表示的。读着怎么这么别扭?举例说一下。
CBrush是一个GDI的派生类,它在MFC中的层次结构是这样的:CObject派生CGdiObject派生CBrush,明白了吧。CGdiObject是所有GDI对象的抽象基类。下面列出的是GDI派生类的列表:
CBitmap:位图是一种位矩阵,每一个显示象素都对应于其中的一个或多个位,可以用来表示图象,也可以用来创建刷子
CBrush:刷子定义了一种位图形式的象素,可以用来对区域内部填充颜色。
CFont:字体是一种具有某种风格和尺寸的所有字符的完整集合,常常被作为资源,其中一些依赖某种设备。
CPalette:调色板是一种颜色映射接口,它允许应用程序在不影响其他应用程序的前提下,可以充分利用输出设备的颜色描绘能力。
CPen:笔是一种用来画线及绘制有形边框的工具,可以指定它的颜色及宽度,并可以指定画虚线、点线还是实线。
CRgn:区域是由多边形、椭圆二者组合形成的一种范围,可以用来进行填充、裁剪、鼠标点中测试等等。
以上很容易理解,可以用WINDOWS的画图帮助我们理解。
CGdiObject类很眼生,看过很多代码就没有看到过它,原因是由于CGdiObject类是所有GDI对象类的虚拟基类,所以我们不必创建CGdiObject类的对象,可以直接构造它的派生类的对象,例如这样
CPen newPen(PS_DASHDOTDOT,2,(COLORREF) 0); //黑色的笔宽度为2
但需要注意的是CFont和CRgn的对象建立需要先调用默认的构造函数来构造C++对象,然后再调用相应的创建函数如:
CreateFont或CreatePolygonRgn等。
CGdiObject类有一个虚拟的析构函数,它派生类的析构函数需要将与C++对象相关联的GDI对象删除掉,一定要在退出程序之前把构造的CGdiObject派生类对象干掉。因为一个没有释放的GDI对象会占用很多的内存。
让我们用一个例子跟踪一下GDI对象
//*************************************
// 例子7-2
void CMy10View::OnDraw(CDC* pDC)
pDC-&MoveTo (10,10);
pDC-&LineTo (110,10);
CPen newPen(PS_DASHDOTDOT,10,(COLORREF) 192); //红色的笔宽度为10
CPen * pOldPen=pDC-&SelectObject (&newPen);
//在将新对象选进设备环境的同时返回指向前一次被选对象的指针。作用保存原来的对象,以便完成任务时恢复它。
pDC-&MoveTo (10,20);
pDC-&LineTo (110,20);
pDC-&SelectObject (pOldPen);//把原来的对象恢复
pDC-&MoveTo (10,30);
pDC-&LineTo (110,30);
  屏幕上应该显示三条线,第一条和第三条一样颜色和粗细因为他们都是用的设备环境默认的CPen对象,第二条是一条用我们自己设定的CPen对象。我们可以看出在将新对象选进设备环境的同时返回指向前一次被选对象的指针。作用保存原来的对象,以便完成任务时恢复它。
  Windows还包含有一些可以利用的库存对象,它们不会被删除,因为Windows对企图删除它们的动作不予理睬。我们可以用SelectStockObject函数将它们选进设备环境。下面列出的是所有的有关刷子、笔、字体和调色板的库存对象。
//***************************************************************************
// MSDN中的内容
BLACK_BRUSH //Black brush.
DKGRAY_BRUSH //Dark gray brush.
GRAY_BRUSH //Gray brush.
HOLLOW_BRUSH //Hollow brush.
LTGRAY_BRUSH //Light gray brush.
NULL_BRUSH //Null brush.
WHITE_BRUSH //White brush.
BLACK_PEN //Black pen.
NULL_PEN //Null pen.
WHITE_PEN //White pen.
ANSI_FIXED_FONT //ANSI fixed system font.
ANSI_VAR_FONT // ANSI variable system font.
DEVICE_DEFAULT_FONT //Device-dependent font.
OEM_FIXED_FONT //OEM-dependent fixed font.
SYSTEM_FONT //The system font. By default, Windows uses the system font
to draw menus, dialog-box controls, and other text. In Windows versions
3.0 and later, the system font i earlier versions
of Windows use a fixed-width system font.
SYSTEM_FIXED_FONT //The fixed-width system font used in Windows prior
to version 3.0. This object is available for compatibility with earlier
versions of Windows.
DEFAULT_PALETTE //Default color palette. This palette consists of the
20 static colors in the system palette.
//*******************************************************************************
一个问题:
  由于SelectObject函数返回的GDI C++对象指针具有临时性,当程序的空闲处理阶段或者控制函数返回时应用程序框架会将临时的C++对象删除,我们不能简单的把这一指针保存在类的数据成员中,而应该借助GetSafeHdc函数将它转化为Windows的句柄,以便持久的保存GDI的标识。
我们将例子7-2做些改动。
//**************************************************
// 例子7-3
void CMy10View::OnDraw(CDC* pDC)
HPEN m_hP //一个指向CPen对象的指针
pDC-&MoveTo (10,10);
pDC-&LineTo (110,10);
CPen newPen(PS_DASHDOTDOT,10,(COLORREF) 192); //红色的笔宽度为10
CPen * pOldPen=pDC-&SelectObject (&newPen); //在将新对象选进设备环境的同时返回指向前一次被选对象的指针。作用保存原来的对象,以便完成任务时恢复它。
m_hPen=(HPEN)pOldPen-&GetSafeHandle ();//获得并保存原来对象的句柄
pDC-&MoveTo (10,20);
pDC-&LineTo (110,20);
pDC-&SelectObject (CPen::FromHandle (m_hPen));//把原来的对象恢复,和例子7-2不同的是通过句柄
pDC-&MoveTo (10,30);
pDC-&LineTo (110,30);
补充一下IGDI派生类的Windows handle type列表
CBrush HBRUSH
CFont HFONT
CBitmap HBITMAP
CPalette HPALETTE
  好了我们已经对GDI有了一些了解,下一篇我们将说说颜色和字体,雷神希望大家对我的学习笔记提些建议,因为很多东西也许不必说的这么罗嗦,可我知道初学VC的痛苦,太多的东西看不明白,所以尽量写的详细。文章记录了我学习时的心得,很多东西是从MSDN查来的,不知道合不合大家(初学者)的口味。
Copyright&
Powered by 编程入门网 All Rights Reserved. |二次元同好交流新大陆
扫码下载App
汇聚2000万达人的兴趣社区下载即送20张免费照片冲印
扫码下载App
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!&&|&&
LOFTER精选
网易考拉推荐
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
阅读(1202)|
用微信&&“扫一扫”
将文章分享到朋友圈。
用易信&&“扫一扫”
将文章分享到朋友圈。
历史上的今天
loftPermalink:'',
id:'fks_',
blogTitle:'SelectObject和DeleteObject 函数',
blogAbstract:'
Windows显示设备的属性,共有下面几种:位图、画刷、字体、画笔、区域。如果要设置它们到当前设备里,就需要使用SelectObject函数,比如上面介绍的字体设置,就会用到这个函数。当你创建一个位图时,这时Windows就会在内存里分配一块内存空间,用来保存位图的数据。当你创建字体时,也会分配一块内存空间保存字体。如果程序只是分配,而不去删除,就会造成内存使用越来越多,最后导到Windows这幢大楼倒下来。如果你忘记删除它,就造成了内存泄漏。因此,当你创建显示设备资源时,一定要记得删除它们啊,否则运行你的程序越长,就导致系统不稳定。记得使用DeleteObject函数去删除它们,把占用的内存释放回去给系统。
blogTag:'',
blogUrl:'blog/static/',
isPublished:1,
istop:false,
modifyTime:0,
publishTime:7,
permalink:'blog/static/',
commentCount:0,
mainCommentCount:0,
recommendCount:0,
bsrk:-100,
publisherId:0,
recomBlogHome:false,
currentRecomBlog:false,
attachmentsFileIds:[],
groupInfo:{},
friendstatus:'none',
followstatus:'unFollow',
pubSucc:'',
visitorProvince:'',
visitorCity:'',
visitorNewUser:false,
postAddInfo:{},
mset:'000',
remindgoodnightblog:false,
isBlackVisitor:false,
isShowYodaoAd:false,
hostIntro:'',
hmcon:'-1',
selfRecomBlogCount:'0',
lofter_single:''
{list a as x}
{if x.moveFrom=='wap'}
{elseif x.moveFrom=='iphone'}
{elseif x.moveFrom=='android'}
{elseif x.moveFrom=='mobile'}
${a.selfIntro|escape}{if great260}${suplement}{/if}
{list a as x}
推荐过这篇日志的人:
{list a as x}
{if !!b&&b.length>0}
他们还推荐了:
{list b as y}
转载记录:
{list d as x}
{list a as x}
{list a as x}
{list a as x}
{list a as x}
{if x_index>4}{break}{/if}
${fn2(x.publishTime,'yyyy-MM-dd HH:mm:ss')}
{list a as x}
{if !!(blogDetail.preBlogPermalink)}
{if !!(blogDetail.nextBlogPermalink)}
{list a as x}
{if defined('newslist')&&newslist.length>0}
{list newslist as x}
{if x_index>7}{break}{/if}
{list a as x}
{var first_option =}
{list x.voteDetailList as voteToOption}
{if voteToOption==1}
{if first_option==false},{/if}&&“${b[voteToOption_index]}”&&
{if (x.role!="-1") },“我是${c[x.role]}”&&{/if}
&&&&&&&&${fn1(x.voteTime)}
{if x.userName==''}{/if}
网易公司版权所有&&
{list x.l as y}
{if defined('wl')}
{list wl as x}{/list}Posts - 652,
Articles - 4,
Comments - 1738
享受技术乐趣
12:06 by Clingingboy, ... 阅读,
GetStockObject在图形编程中是常用API之一,对于GetStockObject,我一直认为它获得的&对象&是一个句柄(因为GetStockObject的API参考下面有DeleteObject函数的链接,一般只有图形对象函数的链接中才会有它的),并且认为它是从当前程序本身拥的&对象&中返回的,后来我无意的发现了问题,请大家看看API参考手册中对函数GetStockObject的注意项:    ......    It is not necessary (but it is not harmful) to delete stock objects by calling DeleteObject.    它说Stock&对象&没有必要删除,可是说如果不删除可能有害,如果是程序本身的&对象&,程序在退出时会自己清除的,那么我想我以前的理解是错误的。    我开始仍把GetStockObject的返回值当成一个对象,进行了一下测试,我写了一个循环,不停的获得Stock&对象&而不删除,足足运行了50000次(Windows规定一个程序最多只能同时拥有36000个对象),可是程序照样正常运行,系统也没有因此而变慢,我在想,GetStockObject返回的可能是一个长指针,指向系统提供的共享对象的句柄,无论获得多少次,它只有一份,返回的值也是一样的,于是,我写了一个显示句柄值的过程,结果的确是获得同一Stock类型的返回值都是相同的,可是,我看到返回的值竟是148(SYSTEM_FONT),这个怎么会是长指针?不可能,我马上又仔细的从头看了GetStockObject的API参考,看到下面一段:    ...    If the function succeeds, the return value identifies the logical object requested    我靠!它的返回值根本不是一个句柄,只是一个标识ID(真是的,这也是我的大意,总认为操作图形的函数成功返回的是句柄,这类API我只看注意事项的,以后不会了),那么GetStockObject终于有结果了,总结如下:    GetStockObject的返回的对象完全不需要删除,因为GetStockObject返回的根本不是句柄,也就是说根本不是一个对象,甚至GetStockObject本身都不需要,因为它的返回值只是一个标识系统对象的ID值,只不过是为了让SelectObject方便选择系统对象,那么,你在使用SelectObject时直接提供ID值就OK,如SYSTEM_FONT的ID值是148,那么就可直接使用Invoke SelectObject,hdc,148就行,只要你记住了常用Stock对象的ID或把它定义成常数,GetStockObject完全可以丢掉!    (关于SelectObject,它返回的才是一个对象,不过是前一对象的句柄,所以,如果要删除对象,只有选择新的同类型的对象到hdc中,前一对象才返回,就可以删除了,如果中间有交错,记住SelectObject返回的总是前一次选择的同一类型(是同一类型)的对象,如果一个过程很复杂,可以把经常使用的对象在程序启动时创建好,然后把句柄保存起来,使用起来就方便多了,甚至不需要删除,因为程序在退出时所占用的对象Windows会自动清除。)}

我要回帖

更多关于 cdc selectobject 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信