CSize sizeTotal( 20000, 30000 ); //逻辑窗口大小20×30cm }
第八天 设备环境类 任何程序在画图时都需要调用图形设备接口( GDI )函数, GDI 包含了一些绘制点、线、矩形、椭圆、位图以及文本的函数。 Windows 的设备环境是 GDI 的关键元素,它代表了物理设备,每一个 C++ 设备环境对象都有与之对应的 Windows 设备环境,并通过一个 32 位的 HDC 句柄来标识。 MFC 中的基类 CDC 包含了绘图所需要的所有成员函数,并且除了 CMetaFileDC 类外,所有的派生类都只有构造函数和析构函数不同。对于显示器来说,常用的派生类有 CClientDC 和 CWindowDC 。 显示设备环境的类 CClientDC 和 CWindowDC , CClientDC 类绘图只局限于客户区域内,即不包含边框、菜单栏和标题栏,而 CWindowDC 类可以。简单来说,如果创建 CclientDC 对象,点( 0,0 )指客户区域的左上角,如果创建的是 CWindowDC 对象,则点( 0,0 )指整个屏幕的左上角。 在创建 CDC 对象的时候,不要忘记在合适的时候将它删除,不然程序在退出之前有小部分内存就会丢失。要保证设备环境对象能够被适时的删除,可以有两种方法: 一种是在堆栈中构造对象,比如在 OnLButtonDown 函数中,它的析构函数在函数返回时自动被调用。 void CMyView::OnLButtonDown(UINT nFlags,CPoint point){ CRect rect; CClientDC dc(this); //constructs dc on the stack … } //dc automatically destroyed 另一种是通过调用 CWnd 的成员函数 GetDC 来获得设备环境指针,但此时必须要调用 RleaseDC 来释放设备环境。 void CMyView::OnLButtonDown(UINT nFlags,CPoint point){ CRect rect; CDC *pDC=GetDC(); pDC->GetClipBox(rect); ReleaseDC(pDC); // 不要忘了这句 } 注意:千万不要删除作为参数以指针形式传递给 OnDraw 函数的 CDC 对象,应用程序框架会自动控制它的删除。 在绘图时我们离不开设备环境,那么在绘图时我们就要依赖于设备环境的当前状态,这种状态包括: • 被选中的 GDI 绘图对象,如笔、刷子和字体等 • 绘图时的缩放尺寸的映射模式 • 其他各种细节,如文本的对齐方式,多边形的填充状态 创建设备环境对象时,通常会有些默认的特性,而其他特性都是通过 CDC 类的成员函数来设定的,可以通过重载 SelectObject 函数来将 GDI 对象选进设备环境中。 如果我们要重新编写 OnPaint 函数,就需要使用 CPaintDC 类,这个类是比较特殊的,它的构造函数和析构函数所完成的工作都是针对显示用的,当我们一旦获得一个 CDC 指针,就可以把它当成任何设备环境指针来用。
第九天 GDI对象 所有 GDI 对象类都是由抽象基类 CGdiObject 派生出来的。下面是 GDI 派生类列表: CBitmap - 位图是一种位矩阵,每一个显示像素都对应一个或多个位,我们可以用位图来表示图像,也可以用它来创建刷子。 CBrush - 刷子定义了一种位图形式的像素,用它可以对区域内部填充颜色。 CFont - 字体是一种具有某种风格和尺寸的所有字符的集合。 CPalette - 调色板是一种颜色映射接口。 CPen - 笔是一种画线和有形边框的工具,可以指定画线的宽度,以及画虚线,实线等。 CRgn - 区域是一种范围,可以用它来填充、裁剪以及鼠标点中测试。 我们只需要构造 CGdiObject 类的派生类对象,而无需构造它的对象,有些 GDI 派生类允许构造函数一步完成创建对象的任务,如 CPen 和 CBrush 。而有些派生类的对象要两步,如 CFont 和 CRgn ,首先要调用默认的构造函数,然后还要调用相应的创建函数,如 CreateFont 、 CreatePolygonRgn 等。 CGdiObject 类有一个虚析构函数,如果构造了一个它的派生类的对象,则在程序退出之前要将其删除,为了删除它,要先将其从设备环境中分离出来。那么如何分离呢?其实, CDC 类的 SelectObject 成员函数在将 GDI 对象选进设备环境的同时,它已经从设备环境中分离出来了,但在未选中新的对象前,还不能将旧的对象分离。所以在选进自己的 GDI 对象时,将原来的 GDI 对象也保存起来,任务完成后,再将其恢复,这样就可以将自己的 GDI 对象分离并删除了。下面看一个例子: void CMyView::OnDraw( CDC *pDC ){ CPen newPen( PS_DASHDOTDOT, 2, (COLORREF)0); //black 2 pixels wide CPen * pOldPen = pDC->SelectObject( &newPen ); pDC->MoveTo( 10, 10 ); pDC->LineTo( 110, 10 ); pDC->SelectObject( pOldPen ); //newPen 被分离 } //newPen 在函数退出时自动删除 对于一些库存的 GDI 对象,由于它们是 windows 系统的一部分,因此我没有必要删除它们。 MFC 库函数 SelectStockObject 可以将一个库存对象选进设备环境中,并返回原先被选中对象的指针,同时使该对象被分离。在上例中,我们就可以用库存对象代替“旧”对象: void CMyView::OnDraw( CDC *pDC ){ CPen newPen( PS_DASHDOTDOT, 2, (COLORREF)0); //black 2 pixels wide pDC->MoveTo( 10, 10 ); pDC->LineTo( 110, 10 ); pDC->SelectStockObject( BLACK_PEN ); //newPen 被分离 } //newPen 在函数退出时自动删除 对于显示设备环境来说,在每个消息控制函数的入口处,设备环境都是未被初始化的,因此每次都必须从头开始设置设备环境,由于 SelectObject 返回的 GDI 对象指针的临时性,而应用程序框架在函数返回时会删除 C++ 临时对象指针,所以不能简单地将设备环境指针保存在类的数据成员中,而要借助于 GetSafeHandle 成员函数来将它转换为 windows 句柄(唯一能够持久存在的 GDI 标识)。 注意,当删除由 SelectObject 返回的指针所指向的对象时,一定要当心,如果该对象是我们自己申请的,可以删除,如果是临时的,则不能随便删除。 (责任编辑:泉水) |