戏说 Windows GDI (3)
继续讨论之前的问题,包括GDI对象的删除问题,窗口注册与销毁问题,最后用标尺的小例子说明问题
1.GDI对象的删除
由CGDIObject派生类创建的画笔、画刷和其他对象都要占用内存资源,因此在使用完毕之后我们必须要删除他们。当然,如果我们在栈上创建CPen、CBrush、CFont或其他CGDIObject,那么在CGDIObject超出范围时,相关的GDI对象就会自动地删除。如果用new在堆上创建了一个CGDIObject,那么我们就必须要手动的进行销毁,以便调用它的析构函数。可以多了解一下,与CGDIObject相关联的GDI对象可以通过调用CGDIObject::DeleteObject被显示地消除。
在之前的16位Windows中,GDI对象经常会引发资源泄漏的问题,这时候因为某些程序不能删除他们创建的GDI对象,因此Program Manager报告的可用系统资源的数量会随着应用程序的不断打开与终止渐渐减少。但是,在32位程序中,这个问题有所改善,Windows会跟踪所分配的资源,并在程序结束的时候释放他们。如果大量的画笔画刷没有被释放,他们就会占据Windows GDI的系统内存空间。很快,创建的画笔画刷的调用就会失败,应用程序的OnPaint处理程序也会莫名其妙的停止工作。
删除由用户创建的GDI对象是重要的,而不能删除已经选入设备描述表的GDI对象也同样不容忽视。试图用已删除的对象画图的程序代码是错误的。
下面的示例程序允许删除选入设备的画刷,我们可以分析一下其中的原因:
void CMainWindow::OnPain(){ CpaintDC dc(this); CBrush brush(RGB(255,0,0)); dc.SelectObject(&brush); dc.Ellipse(0,0,200,100); }
事情是这样的,CPaintDC对象和CBrush对象都是在栈上创建的。由于CBrush是第二个被创建的,所以特的析构函数会首先被调用,相关的GDI画刷在dc超出范围之前就被删除了。但是要强调一点,如果代码的健壮性依赖于栈变量的特定顺序来创建,那么你的程序就是相当糟糕的。就代码的维护性而言,这种程序简直太可怕了!
最好的解决办法就是:在CPaintDC对象超出范围之前将CBrush从设备描述表中提出。示例如下:
CPen pen ( PS_SOLID,1,RGB(255,0,0)); CPen* pOldPen = dc.SelectObject( &pen); CBrush brush(RGB(0,0,255)); CBrush* pOldBrush = dc.SelectObject( &brush); .... dc.SelectObject(pOldPen); dc.SelectObject(pOldBrush);
2.窗口是如何消除的
我们研究的MFC程序很多都是在InitInstance中用下面的语句创建了一个窗口:
m_pMainWnd = new CMainWindow;
应该注意到,这个对象也是用new创建的,所以InitInstance结束之后,对象应该还存在内存之中。实际上,知道delete语句执行后,对象才会被清除。然而,在源程序中,我们似乎没有发现这条语句。这是因为MFC类库可以自己删除对象。更确切地说就是对象自己删除了自己。这个技巧的关键在于:窗口在消除之前接收到的最后一条消息是WM_NCDESTROY。在源代码的CWnd::OnNcDestroy中,我们会发现,程序里面调用了一个虚函数PostNcDestroy.CFrameWnd覆盖PostNcDestroy并执行了语句:
delete this;
因此在框架窗口被清除时,与窗口有关的对象也自动被删除了。框架窗口在用户关闭应用程序时被清除。
这里必须值得注意的是:CWnd自己实现的PostNcDestroy并没有删除相关的窗口对象,因此,如果我们程序中的窗口是直接从CWnd中派生而来的,我们必须对虚函数PostNcDestroy进行覆盖,也就是添加delete this语句。
3.标尺应用程序
效果图:
源代码:CRuler.h
class CMyApp : public CWinApp { public:virtual BOOL InitInstance (); };class CMainWindow : public CFrameWnd { public:CMainWindow ();protected:afx_msg void OnPaint ();DECLARE_MESSAGE_MAP () };
CRuler.c
#include <afxwin.h> #include "Ruler.h"CMyApp myApp;/ // CMyApp member functionsBOOL CMyApp::InitInstance () {m_pMainWnd = new CMainWindow;m_pMainWnd->ShowWindow (m_nCmdShow);m_pMainWnd->UpdateWindow ();return TRUE; }/ // CMainWindow message map and member functionsBEGIN_MESSAGE_MAP (CMainWindow, CFrameWnd)ON_WM_PAINT () END_MESSAGE_MAP ()CMainWindow::CMainWindow () {Create (NULL, _T ("Ruler")); }void CMainWindow::OnPaint () {CPaintDC dc (this);//// Initialize the device context.//dc.SetMapMode (MM_LOENGLISH);dc.SetTextAlign (TA_CENTER | TA_BOTTOM);dc.SetBkMode (TRANSPARENT);//// Draw the body of the ruler.//CBrush brush (RGB (255, 255, 0));CBrush* pOldBrush = dc.SelectObject (&brush);dc.Rectangle (100, -100, 1300, -200);dc.SelectObject (pOldBrush);//// Draw the tick marks and labels.//for (int i=125; i<1300; i+=25) {dc.MoveTo (i, -192);dc.LineTo (i, -200);}for (int i=150; i<1300; i+=50) {dc.MoveTo (i, -184);dc.LineTo (i, -200);}for (int i=200; i<1300; i+=100) {dc.MoveTo (i, -175);dc.LineTo (i, -200);CString string;string.Format (_T ("%d"), (i / 100) - 1);dc.TextOut (i, -175, string);} }
戏说 Windows GDI (3)相关推荐
- 戏说 Windows GDI (2)
1. GDI画笔和CPen类 Windows用当前选入设备描述表的画笔绘制直线和曲线,并给用Rectangle.Ellipse以及其他图像生成函数画出的图形镶嵌边框.在系统默认的情况下,画笔是指一个像 ...
- 戏说 Windows GDI (1)
0.题记: 作为QT开发的支持者和践行者,明知道MFC已经过时,但是还不得不用:老板要求,项目组师兄弟代码兼容Balabala~也许这就是中国式项目研发. 好啦,聊点正经事...... 1.设备描述表 ...
- MFC和Win32之三___CGdiObject类和windows Gdi对象
小结: 前面讲到的windows窗口对象,在windows下用句柄来代表之,并且用了一个数据结构WNDCLASS(窗口类)来描述之.同理,windows的Gdi对象也有一些句柄来代表之(比如hPen等 ...
- Windows GDI和GDI+编程实例剖析(1)
Windows GDI和GDI+编程实例剖析(1) 作者:宋宝华 e-mail:21cnbao@21cn.com 1.基本概念 GDI在Windows中定义为Graphics Device Inte ...
- 原创]Windows Gdi入门初级应用(VC SDK)
原创]Windows Gdi入门初级应用(VC SDK) 好久没发贴了,今天手痒痒,发一个. GDI的绘图函数基本上都是有状态的,所有的函数都要求一个HDC类型的句柄. 这个HDC的获得有几个途径Be ...
- GetBitmapBits和GetDIBits的区别(Windows GDI)
Windows GDI中有两个用来得到位图图像数据的API,分别是GetBitmapBits和GetDIBits; 按照MSDN的解释,前者是用来得到设备独立位图的BITS, 后者是得到兼容位图的BI ...
- windows GDI+ 绘图的简单封装
由于用mfc经常需要在界面上进行一些绘制输出,所以用windows GDI比较多,但是用windowsGDI 绘图比较麻烦,刚开始学的时候还经常弄不清一堆DC, Object, HANDLE到底是干啥 ...
- Windows GDI
Windows GDI 在单任务环境如 MS-DOS 中,运行中的应用程序随时可自由地做它想做的事情,无论是在屏幕上画一条线,重新编写适配器的调色板,还是转换到另一种图像模式.而在窗口化多任务环境如 ...
- Windows GDI 窗口与 Direct3D 屏幕截图
前言 Windows 上,屏幕截图一般是调用 win32 api 完成的,如果 C# 想实现截图功能,就需要封装相关 api.在 Windows 上,主要图形接口有 GDI 和 DirectX.GDI ...
最新文章
- 最大限度地减少块输出中间结果的计算和存储
- java枚举变量带括号_Java~如何使用Enum(枚举)和Lambda表达式
- sql update 多个字段_SQL学习之路-20190707
- 【转】探索c#之Async、Await剖析
- LeetCode 1609. 奇偶树(层序遍历)
- php mysql关键技术_中高级PHP开发者应该掌握哪些技术?
- 删除的时候提示“该项目不在C:\User\桌面 中
- NetBEUI协议巧安装
- java实现将word转换pdf
- 零基础学Python课后实战第五章
- AT32F437基于LVGL的仪表显示案例
- Neuronink是医学奇迹的噩梦
- 读《灵魂只能独行》乱摘
- 记录一次浏览器HTTPS“你的连接不是私密连接”错误NET::ERR_CERT_REVOKED
- java互联网架构,大数据学习笔记1--------Python入门个人笔记,仅记录个人觉得需要记得东西)
- 通百艺即无一长——蒂姆 · 哈福德
- Vue + D3 动态可视化图实现之一:折线图
- 柯布-道格拉斯效用函数下的pcr抽卡策略
- 如何通过数据分析,提升游戏次日留存
- coding平台简易操作
热门文章
- Xcode7 beta 网络请求报错:The resource could not be loade
- java new java.text.SimpleDateFormat(yyyyMM01).format(date)
- Oracle 10g中对resumable session的增强
- Unix/Linux下文件基本操作[zt]
- OpenCV 自动调取摄像头并显示屏幕
- java版DVD影碟片出租赁系统C/S模式 java电影购票系统课程设计
- Mapreduce基本工作流程
- Arduino LiquidCrystal库函数中文对照
- Python基础知识4--数据结构(树)
- WebService 的创建,部署和使用