我们热爱生命科学!-生物行

『VC++技术内幕』(第四版)读书笔记(3)

时间:2005-10-02 17:32来源:本站原创 作者:yuyan2333 点击: 1557次

CSize sizeTotal( 20000, 30000 ); //逻辑窗口大小20×30cm
CSize sizePage( sizeTotal.cx/2, sizeTotal.cy/2 );
CSize sizeLine( sizeTotal.cx/50, sizeTotal.cy/50 );
SetScrollSizes( MM_HIMETRIC, sizeTotal, sizePage, sizeLine );

}
4、 用ClassWizard产生对消息WM_KEYDOW控制的onKeyDown函数,并编辑代码如下:
void CAView::onKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default

switch( cChar ){
case VK_HOME:
OnVScroll( SB_TOP, 0, NULL );
OnHScroll( SB_LEFT, 0, NULL );
break;
case VK_END:
OnVScroll( SB_BOTTOM, 0, NULL );
OnHScroll( SB_RIGHT, 0, NULL );
break;
case VK_UP:
OnVScroll( SB_LINEUP, 0, NULL );
break;
case VK_DOWN:
OnVScroll( SB_LINEDOWN, 0, NULL );
break;
case VK_PRIOR:
OnVScroll( SB_PAGEUP, 0, NULL );
break;
case VK_NEXT:
OnVScroll( SB_PAGEDOWN, 0, NULL );
break;
case VK_LEFT:
OnHScroll( SB_LINELEFT, 0, NULL );
break;
case VK_RIGHT( SB_LINERIGHT, 0, NULL );
break;
default:
break;
}

5、 编辑构造函数和OnDraw函数如下:
CAView::CAView():m_rectEllipse( 0, 0, 4000, -4000 )
{
// TODO: add construction code here
m_nColor = GRAY_BRUSH;
}

void CAView::OnDraw(CDC* pDC)
{
pDC->SelectStockObject( m_nColor );
pDC->Ellipse( m_rectEllipse );
}
6、 映射WM_LBUTTONDOWN消息并编辑消息处理函数OnLButtonDown如下:
void CAView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default

CClientDC dc( this );
OnPrepareDC( &dc );
CRect rectDevice = m_rectEllipse;
dc.LPtoDP( rectDevice );
if( rectDevice.PtInRect( point ) ){
if( m_nColor = GRAY_BRUSH )
m_nColor = WHITE_BRUSH;
else
m_nColor = GRAY_BRUSH;
}
InvalidateRect( rectDevice );
}
编译并运行看看结果吧。
另外,我们要特别注意下面五种比较特殊的windows消息:
1、 WM_CREATE消息
该消息是windows发给视图的第一个消息,由于应用程序框架调用Create函数时该消息就会被发送,而此时窗口创建还未完成,因此在Create函数内不能调用那些依赖于窗口处于完全激活状态的windows函数。不过对于SDI应用程序,在视图生存期间,OnInitialUpdate函数可以被调用多次。
2、 WM_CLOSE消息
当用户从系统菜单中关闭窗口或者父窗口被关闭时,windows会发送WM_CLOSE消息。
3、 WM_QUERYENDSESSION消息
当用户退出windows时,windows就会发送WM_QUERYENDSESSION消息给正在运行的程序,处理这个消息的映射函数为OnQueryEndSession。
4、 WM_DESTROY消息
Windows在发送完WM_CLOSE消息后,紧接着就发送WM_DESTROY消息,消息映射函数为OnDestroy。当程序接收到该消息时,它将假定此时视窗已经消失,但仍处于活动状态。利用这个消息控制函数,就可以对依赖于当前窗口的所有东西作清除工作,不过一定要记住,应该用基类的OnDestroy而不能在自己视图中的OnDestroy中"终止"窗口的析构过程,终止析构的处理应该在OnClose函数中。
5、 WM_NCDESTROY消息
当窗口被取消时发送的最后一个消息就是这个消息,由于此时所有的窗口都被关闭,所以我们可以在OnNcDestroy函数中做一些不依赖于窗口是否处于激活状态的最后处理工作,不过一定要调用基类的OnNcDestroy函数。不要在OnNcDestroy中取消动态申请的窗口对象,这一工作是由CWnd的一个特殊虚函数PostNcDestroy来完成的,它是由基类的OnNcDestroy来调用的。何时取消窗口对象最为合适呢,去看MFC的联机文档吧!

Top of Page

第八天 设备环境类

  任何程序在画图时都需要调用图形设备接口( 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 指针,就可以把它当成任何设备环境指针来用。

Top of Page

第九天 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 返回的指针所指向的对象时,一定要当心,如果该对象是我们自己申请的,可以删除,如果是临时的,则不能随便删除。 (责任编辑:泉水)
顶一下
(17)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
特别推荐
推荐内容