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

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

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

第四天 资源和编译

  资源文件(就是以应用程序名和扩展名是.rc的文件)很大程度上决定了应用程序的用户界面。在VC++中资源文件包括以下内容:
Accelerator //模拟菜单和工具栏选择的键盘定义
Dialog //对话框的布局及内容
Icon //图标有两种一种是16X16一种是32X32。
Menu //应用程序的主菜单及所属的弹出式菜单
String table //一些字符串,不属于C++源代码部分
Toolbar //工具条。
Version //程序的描述、版本号、支持语言信息。
  除了以上信息,.rc文件还包含了以下语句: #include "afxres.h" #include "afxres.rc" 它们的作用是把适合于所有应用程序的一些通用MFC库资源包含进来,其中包括字符串、图形按钮以及打印所需的一些元素。
  关于资源编辑器的使用就不多说了,因为它的操作很简单,需要注意的是虽然resource.h是一个ASCII码文件可以用文本编辑器进行编辑,但如果使用文本编辑器进行编辑的话,下次再使用资源编辑器时所做的修改有可能丢失,所以我们应该在尽量在资源编辑器中编辑应用程序的资源,新增的资源内容回自动的添加在我们的程序相应位置,例如resource.h而不用我们操心。
  编译在VC++中有两种模式,一种是Release Build另一种是Debug Build。它们之间的区别在于,Release Build不对源代码进行调试,不考虑MFC的诊断宏,使用的是MFC Release库,编译十对应用程序的速度进行优化,而Debug Build则正好相反,它允许对源代码进行调试,可以定义和使用MFC的诊断宏,采用MFC Debug库,对速度没有优化。所以我们应该在Debug模式下开发应用程序,然后在Release模式下发布应用程序。在我们的工程文件夹下会有一个Debug文件夹和一个Release文件夹分别存放输出文件和中间文件。
  诊断宏是我们编译程序时检测程序状态的有利工具,例如上两篇用到的TRACE宏,可以在Debug窗口获得你需要的诊断信息,而不用设置对话框之类的方法,在发布时Release会自动滤掉此信息。
  为了更好的管理项目,最好理解系统是如何处理预编译头文件的。VC++有两个预编译系统:自动的和手工的。这一部分笔者就不多说了,建议读者好好看看。


Top of Page

第五天 基本事件处理

  用户在视窗中的任何一个操作,都会引起Windows自动发送一个消息给该视窗。我们以一个例子来说明:比如我们在视窗中按下鼠标左键,Windows就会发送ON_LBUTTONDOWN消息给视窗,那么在视窗类中就必须包含下面的成员函数:
Void CmyView::OnLButtonDown(UINT nFlags, Cpoint point)
{
//event processing code here
}
  在类头文件中也要包含相应的函数声明:
afx_msg void OnLButtonDown(UINT nFlags, Cpoint point)
在代码文件中还要有一个消息映射宏,用于将OnLButtonDown函数和应用程序框架联系在一起:
BEGIN_MESSAGE_MAP(CmyView, CView)
ON_WM_LBUTTONDOWN()
// other message map entries
END_MESSAGE_MAP
  最后,在类库头文件中包含如下语句:
DECLARE_MESSAGE_MAP()
  以上这些步骤,我们都可以借助于ClassWizard来完成。这就是消息映射的过程。

  MFC库对140种windows消息直接提供了消息控制函数,并且我们还可以自己定义自己的消息,下面列出的五种消息是我们应该特别注意的(MSDN上有更详细的内容)。
WM_CREATE
  该消息是Windows发给视图的第一个消息。当应用程序框架调用create函数时该消息便会被发送,此时窗口还未创建完成,不可见,因此在消息控制函数OnCreate内不能调用那些依赖窗口处于完全激活状态的Windows函数。如果需要可以在重载的OnInitialUpdate函数内调用。不过注意在SDI应用程序OnInitialUpdate函数可能被多次调用。
WM_CLOSE
  当用户关闭窗口时,系统会发送WM_CLOSE消息。如果派生类重新定义了OnClose函数,就可以完全控制关闭过程,可以将提醒用户存盘之类的工作放在这里完成。我们可以通过重载CDocument::SaveModified虚函数达到相同的目的。
WM_QUERYENDSESSION
  从字面的意思看就可以看出,当用户退出Windows时,或者调用了ExitWindows 函数时。Windows会发送WM_QUERYENDSESSION消息给所有的正在运行的应用程序,由OnQueryEndSession消息映射函数对消息进行处理。在它之后应该是WM_ENDSESSION 消息。
WM_DESTROY
  在Windows发送WM_CLOSE消息后,紧接着会发送WM_DESTROY消息,虽然窗口已经Close但实际上并没有完全清除,在任务管理器中还可以看见应用程序的进程(我想很多木马或病毒都是无窗口的程序,它们的做法是生成了已经活动状态的窗口但不显示出来),利用这个消息控制函数便可以对依赖于当前窗口存在的东西做清除工作,不过一定要注意,应该调用基类的OnDestroy函数,而不能在用户自己的视图的OnDestroy函数中终止窗口的析构过程,终止析构过程应该在OnClose函数中。
WM_NCDESTROY
  当窗口被取消所发送的最后一个消息就是这个消息。我们可以在OnNcDestroy函数中做一些不依赖该窗口是否处于活动状态的最后的处理工作,(我实在想不出还需要做什么?那位朋友能给个例子),注意一定要调用基类中的OnNcDestroy函数。

  MFC库中非静态数据成员的名字以m_为前缀。
  一个窗口具有一个矩形的"客户区域",CWnd中的GetClient成员函数可以给出客户区域的大小,只允许在客户区域内绘图。
  标准的windows应用程序会首先登记一个窗口类,这不同于C++类,同时在处理过程中,还需要对每个类指定窗口过程。每次应用程序调用CreateWindow建立一个窗口时,都要指定一个窗口类作为参数,这样就把新建立的窗口和窗口过程函数连接起来了,每次windows给窗口发送消息的时候,这个函数就会被调用,以检查用参数传进来的消息码。

Top of Page

第六天 映射模式

  所谓映射模式,说白了就是坐标系。在默认情况下,Windows所绘图像单位为像素,这是因为设备环境用了默认的映射模式MM_TEXT,所以如下语句所绘图形为长和宽都为200像素的方块:   pDC->Rectangle(CRect(0,0,200,200));
  那么我们要绘制一个长和宽都是4厘米的方块该怎么做呢?这就必须改变设备环境的默认映射模式为MM_HIMETRIC,它的图像单位为1/100mm,而不是像素了。它的y轴方向和MM_TEXT的相反,它的向下为递减的,因此用如下语句就可以绘出4×4cm的方块了:
pDC->SetMapMode( MM_HIMETRIC);
pDC->Rectangle(CRect(0,0,4000,-4000));
  下面我们再来了解一下Windows都提供了哪些映射模式。
1、MM_TEXT映射模式
  这种模式下,绘图单位为像素,x轴向右递增,y轴向下递增,我们可以用CDC的SetViewPortOrg和SetWindowOrg函数来改变坐标原点的位置,下面的代码就是把坐标原点设在了(100,100)处,画了一个200×200像素的方块,此时逻辑坐标点(100,100)被映射到了设备坐标点(0,0)处,下一篇的滚动窗口使用的就是这种变换。
Void CmyView::OnDraw( CDC *pDC ){
pDC->SetMapMode(MM_TEXT);
pDC->SetWindowOrg(Cpoint(100,100));
pDC->Rectangle(CRect(100,100,200,200));
}
2、固定比例映射模式
  Windows提供了一组非常重要的固定比例影视模式,所有这种模式都遵循x轴向右递减,y轴向下递减的规则,而且我们无法将其改变。固定比例模式之间唯一的差别就在于实际的比例因子。下表列出了影视模式和比例因子的对应情况:

映射模式 逻辑单位
MM_LOENGLISH 0.01英寸
MM_HIENGLISH 0.001英寸
MM_LOMETRIC 0.1mm
MM_HIMETRIC 0.01mm
MM_TWIPS 1/1440英寸

  MM_TWIPS模式常用于打印机。
3、可变比例映射模式
  Windows还提供了两种映射模式MM_ISOTROPIC和MM_ANISOTROPIC,这两种模式允许我们修改比例因子和坐标原点。在MM_ISOTROPIC模式下,纵横比总是1:1,就像改变图像时锁定比例一样,而MM_ANISOTROPIC模式则可以独立的改变x和y的比例因子,即圆可以变成扁圆。
  以上就是常见的映射模式,笔者建议:我们没必要死记住这些模式,只是到用的时候会用就可以了,哪怕查查MSDN,这个东东真好!
  在设置了映射模式和相应参数之后,我们可以用CDC的LPtoDP函数将逻辑坐标转换为设备坐标,用DptoLP函数将设备坐标转换为逻辑坐标。那么我们什么时候用什么样的坐标呢?有一些规则如下:
① 可以认为CDC的所有成员函数都以逻辑坐标为参数
② 可以认为CWnd的所有成员函数都以设备坐标为参数
③ 所有选中测试都应该选用设备坐标,区域的定义应采用设备坐标,某些像CRect::PtInRect之类的函数只有采用设备坐标才能有正确的结果
④ 将一些长期使用的值用逻辑坐标来保存,如果用设备坐标,那么只要用户对窗口进行一下滚动,坐标就不再有效了
  一般情况下,我们在CView的虚函数OnPrepareDC中设置映射模式,应用程序框架在调用OnDraw函数之前调用这个虚函数。


Top of Page

第七天 滚动视窗

  CView类并不直接支持窗口滚动,如要实现窗口滚动,就要用到CView的派生类CScrollView类,CScrollView的成员函数能够处理滚动条并发送给视图WM_HSCROLL和WM_VSCROLL消息,从而实现窗口的滚动。
  在文档-视图结构中,视图窗口建立以后,框架最先调用OnInitialUpdate虚函数,在框架第一次调用OnDraw函数前也是先调用OnInitialUpdate函数,因此在OnInitialUpdate函数中设置滚动视窗的初始化最合适。
  下面我们就来创建一个滚动示例程序a:
  1、 用AppWizard创建一个文档-视图程序a,注意在第六步时设置CAView的基类应为CScrollView而不是CView。
  2、 在CAView中加入数据成员m_rectEllipse和m_nColor。
  3、 修改OnInitialUpdate函数如下:
void CAView::OnInitialUpdate()
{
CScrollView::OnInitialUpdate(); (责任编辑:泉水)
顶一下
(17)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
特别推荐
推荐内容