📄 vc++note.txt
字号:
仔细研究一下myapp01View.cpp和myapp01View.h文件,程序核心CMyAppView类在这两个文件中定义,就是我们今天要学的视图类。要想看到CMyAppView类的全貌,应该用Source Browser查看,选择CMyApp01View,按Alt+F12,选择Base Class and Members 选项。我们会看到CMyAppView类的层次关系(从哪来得),以及所有成员函数,包括从基类继承的(在Class View中不能显示父类的成员函数)。我们发现实际上你什么也不用做就拥有了一个有着强大功能的类。
下面我们看一下CMyAppView类的OnDraw成员函数,它是虚函数作用是每当窗口需重绘时应用程序框架会调用它。它的原型是这样的(在myapp01View.h可以找到)
virtual void OnDraw(CDC* pDC); // overridden to draw this view
参数是CDC类的指针,WINDOWS是通过和窗口相关联的设备环境(CDC类的对象就是设备环境)和显示硬件进行通讯。有了这个指针我们便可以调用CDC类的成员函数来完成各种绘制工作,如上一篇用到的textout()还有一些Ellipse()、Polygon()、BitBlt()等等在MSDN中有好长的一篇,它是直接从CObject派生的,好了我们开始在OnDraw()里添加一些绘图工作。
3、在Class View选择CMyApp01View类的OnDraw()成员函数双击会在C++编译器看到以下内容
void CMyApp01View::OnDraw(CDC* pDC)
{
CMyApp01Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
}
在 // TODO: add draw code for native data here的位置增加一行代码
void CMyApp01View::OnDraw(CDC* pDC)
{
CMyApp01Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
pDC->TextOut(10,10,"雷神愿意和所有学VC的朋友共同进步!");
pDC->SelectStockObject (DKGRAY_BRUSH); //选择刷子
pDC->Ellipse (CRect(20,40,120,140)); //画圆,CRect是MFC库提供的一个表示WINDOWS矩形类
pDC->Rectangle (CRect(220,240,120,140)); //画矩形
// TODO: add draw code for native data here
}
编译运行,成功了吧。先到这吧。另外以后的文章将同时贴在写作区。
第四篇:资源和编译
资源文件(就是以应用程序名和扩展名是.rc的文件)很大程度上决定了应用程序的用户界面。在VC++中资源文件包括以下内容:
Accelerator //模拟菜单和工具栏的选择内容
Dialog //对话框的布局及内容
Icon //图标有两种一种是16X16一种是32X32。
Menu //应用程序的主菜单及所属的弹出式菜单
String table //字符串不属于C++源代码部分
Toolbar //工具条。
Version //程序的描述、版本号、支持语言信息。
以上信息都在.rc文件中包含,同时.rc文件还包含了以下语句:
#i nclude "afxres.h"
#i nclude "afxres.rc"
它们的作用是把适合于所有应用程序的一些通用MFC库资源包含进来。
关于资源编辑器的使用就不多说了,因为它的操作很简单,需要注意的是虽然resource.h是一个ASCII码文件可以用文本编辑器进行编辑,单如果使用文本编辑器进行编辑的话,下次再使用资源编辑器时所做的修改有可能丢失,所以我们应该在尽量在资源编辑器中编辑应用程序的资源,新增的资源内容回自动的添加在我们的程序相应位置,例如resource.h而不用我们操心。这便是为什么称为Visual (可视)的原因之一。
编译在VC++中有两种模式,一种是Release Build另一种是Debug Build。它们之间的区别在于,Release Build不对源代码进行调试,不考虑MFC的诊断宏,使用的是MFC Release库,编译十对应用程序的速度进行优化,而Debug Build则正好相反,它允许对源代码进行调试,可以定义和使用MFC的诊断宏,采用MFC Debug库,对速度没有优化。所以我们应该在Debug模式下开发应用程序,然后在Release模式下发布应用程序。在我们的工程文件夹下会有一个Debug文件夹和一个Release文件夹分别存放输出文件和中间文件。
诊断宏是我们编译程序时检测程序状态的有利工具,例如上两篇用到的TRACE宏,可以在Debug窗口获得你需要的诊断信息,而不用设置对话框之类的方法,在发布时Release会自动滤掉此信息。
实际上对一个应用程序的调式是一件很具挑战的工作,我相信我们都有类似的经历,从网上或书本上找来了一段代码或源程序,当我们一点点将他们敲进 Deleloper Studio后进行编译时一下子出现了无数的错误和警告,(有些书的源代码就是错误的)这是需要的耐心和经验,有了VC++提供的调试工具如诊断宏、设断点、单步执行等等,会让我们省不少力气。至于编译的话题其实应该有很多可以说,但由于雷神本身的经验不足只能把书上所讲的作一个总结,大家应该熟练的掌握VC++为我们提供的的各种调试工具,象SPY之类的工具在MSDN中也有很详细的使用帮助说明,到现在我体会到了高手们所说的MSDN是最好的最全的也是最权威的。
第五篇:基本事件处理
我们已经知道MFC库应用程序框架调用CView视图类的虚函数OnDraw来完成屏幕显示。其实CView和CWnd类包含了几百个成员函数,在MSDN中可以看到这些成员函数,其中有许多On开头的,例如第二篇的例子就有一个OnLButtonDown,它们都是应用程序框架响应各种事件所需调用的函数。
OnDraw便是当窗口发生变化是被调用的,OnLButtonDown是鼠标左键被按下时调用,还有OnKeyDown是键盘被按下时调用等等。
当用户在视窗中按下鼠标左键时,Windows会自动发送WM_LBUTTONDOWN消息给该视窗,当然你可以什么都不做象我们第3篇的例子一样,如果你想要让程序对此消息做出反应就必须在视图类给出相应的函数,类似下面这样:
void CMyView::OnLButtonDown(UINT nFlags,CPoint point)
{
//做些事情的代码
}
还需要在类头文件包含相应的函数原型说明
afx_msg void OnLButtonDown(UINT nFlags,CPoint point);
afx_msg只是说明该函数原型是针对消息映射函数。下一步在代码文件中还需要有一个消息映射宏,作用是把OnLButtonDown函数和应用程序框架联系在一起。
BEGIN_MESSAGE_MAP(CMyView,CView)
ON_WM_LBUTTONDOWN
END_MESSAGE_MAP()
最后在类库的头文件还需包含:
DECLARE_MESSAGE_MAP()
函数和Windows消息的对应关系可以从MSDN中找到在MSDN中索引输入(WM_ Messages)便会列出所有的Windows消息和消息控制函数原型。在实际的编程过程中我们不可能全部都用手工的添加或编制消息控制函数。除了一些特殊的,我们一般是借助Class Wizard来自动编制消息映射函数。这又是MFC应用程序框架比起SDK来的有一个便捷的地方。
第六篇:映射模式
在此篇之前我们已经学会了在窗口显示图形,更准确的说是在窗口指定位置显示图形或文字,我们使用的坐标单位是象素,称之为设备坐标。看下面语句:
pDC->Rectangle(CRect(0,0,200,200));
画一个高和宽均为200个象素的方块,因为采用的是默认的MM_TEXT映射模式,所以在设备环境不一样时,画的方块大小也不一样,在1024*768的显示器上看到的方块会比640*480的显示器上的小(在不同分辨率下的屏幕象素,在WINDOWS程序设计一书中有示例程序可以获得,或者可以用GetClientRect函数获得客户区的矩形大小。在这里就不说了,大家只要知道就行了),在输出到打印机时也会有类似的情况发生。如何做才能保证在不同设备上得到大小一致的方块或者图形、文字呢?就需要我们进行选择模式映射,来转换设备坐标和逻辑坐标。
Windows提供了以下几种映射模式:
MM_TEXT
MM_LOENGLISH
MM_HIENGLISH
MM_LOMETRIC
MM_HIMETRIC
MM_TWIPS
MM_ISOTROPIC
MM_ANISOTROPIC
下面分别讲讲这几种映射模式:
MM_TEXT:
默认的映射模式,把设备坐标被映射到象素。x值向右方向递增;y值向下方向递增。坐标原点是屏幕左上角(0,0)。但我们可以通过调用CDC的SetViewprotOrg和SetWindowOrg函数来改变坐标原点的位置看下面两个例子:
//************************************************
// 例子6-1
void CMyView::OnDraw(CDC * pDC)
{
pDC->Rectangle(CRect(0,0,200,200));//全部采用默认画一个宽和高为200象素的方块
}
//**************************************************
// 例子6-2
void CMyView::OnDraw(CDC * pDC)
{
pDC->SetMapMode(MM_TEXT);//设定映射模式为MM_TEXT
pDC->SetWindowOrg(CPoint(100,100));//设定逻辑坐标原点为(100,100)
pDC->Rectangle(CRect(100,100,300,300));//画一个宽和高为200象素的方块
}
这两个例子显示出来的图形是一样的,都是从屏幕左上角开始的宽和高为200象素的方块,可以看出例子2将逻辑坐标(100,100)映射到了设备坐标(0,0)处,这样做有什么用?滚动窗口使用的就是这种变换。
固定比例映射模式:
MM_LOENGLISH、MM_HIENGLISH、MM_LOMETRIC、MM_HIMETRIC、MM_TWIPS这一组是Windows提供的重要的固定比例映射模式。
它们都是x值向右方向递增,y值向下递减,并且无法改变。它们之间的区别在于比例因子见下:(我想书上P53页肯定是印错了,因为通过程序实验x值向右方向也是递增的)
MM_LOENGLISH 0.01英寸
MM_HIENGLISH 0.001英寸
MM_LOMETRIC 0.1mm
MM_HIMETRIC 0.01mm
MM_TWIPS 1/1440英寸 //应用于打印机,一个twip相当于1/20磅,一磅又相当于1/72英寸。
看例3
//**************************************************
// 例子6-3
void CMyView::OnDraw(CDC * pDC)
{
pDC->SetMapMode(MM_HIMETRIC);//设定映射模式为MM_HIMETRIC
pDC->Rectangle(CRect(0,0,4000,-4000));//画一个宽和高为4厘米的方块
}
还有一种是可变比例映射模式,MM_ISOTROPIC、MM_ANISOTROPIC。用这种映射模式可以做到当窗口大小发生变化时图形的大小也会相应的发生改变,同样当翻转某个轴的伸展方向时图象也会以另外一个轴为轴心进行翻转,并且我们还可以定义任意的比例因子,怎么样很有用吧。
MM_ISOTROPIC、MM_ANISOTROPIC两种映射模式的区别在于MM_ISOTROPIC模式下无论比例因子如何变化纵横比是1:1而M_ANISOTROPIC模式则可以纵横比独立变化。
让我们看例子4
//**************************************************
// 例子6-4
void CMy002View::OnDraw(CDC* pDC)
{
CRect rectClient; //
GetClientRect(rectClient);//返回客户区矩形的大小
pDC->SetMapMode(MM_ANISOTROPIC);//设定映射模式为MM_ANISOTROPIC
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt (rectClient.right ,-rectClient.bottom );
//用SetWindowExt和SetViewportExt函数设定窗口为1000逻辑单位高和1000逻辑单位宽
pDC->SetViewportOrg(rectClient.right/2,rectClient.bottom/2 );//设定逻辑坐标原点为窗口中心
pDC->Ellipse(CRect(-500,-500,500,500));//画一个撑满窗口的椭圆。
// TODO: add draw code for native data here
}
怎么样,屏幕上有一个能跟随窗口大小改变而改变的椭圆。把 pDC->SetMapMode(MM_ANISOTROPIC);这句改为pDC->SetMapMode(MM_ISOTROPIC)会怎样?大家可以试试。那还有一个问题就是上例的比例因子是多少呢?看下面公式(注意是以例子4为例的)
x比例因子=rectClient.right/1000 //视窗的宽除以窗口范围
y比例因子=-rectClient.bottom/1000 //视窗的高除以窗口范围
从Windows的鼠标消息可以获得鼠标指针的当前坐标值(point.x和point.y)此坐标值是设备坐标。
很多MFC库函数尤其是CRect的成员函数只能工作在设备坐标下。
还有我们有时需要利用物理坐标,物理坐标的概念就是现实世界的实际尺寸。
设备坐标-逻辑坐标-物理坐标之间如何进行转换便成为我们要考虑的一个问题,物理坐标和逻辑坐标是完全要我们自己来做的,但WINDOWS提供了函数来帮助我们转换逻辑坐标和设备坐标。
CDC的LPtoDP函数可以将逻辑坐标转换成设备坐标
CDC的DPtoLP函数可以将设备坐标转换成逻辑坐标
下面列出我们应该在什么时候使用什么样的坐标系一定要记住:
◎CDC的所有成员函数都以逻辑坐标为参数
◎CWnd的所有成员函数都以设备坐标为参数
◎区域的定义采用设备坐标
◎所有的选中测试操作应考虑使用设备坐标。
◎需要长时间使用的值用逻辑坐标或物理坐标来保存。因设备坐标会因窗口的滚动变化而改变。
用书上的例子作为以前几篇的复习,如果你能够独立完成它说明前面的内容已经掌握。另外有些东西是新的,我会比较详细的做出说明,例如客户区、滚动窗口等。
下面我们来一步步完成例子6-5:
■第徊剑河肁ppWizard创建MyApp6。除了Setp 1 选择单文档视图和Setp 6 选择基类为CScrollView外其余均为确省。
■第二步:在CMyApp6View类中增加m_rectEllipse和m_nColor两个私有数据成员。你可以手工在myapp6View.h添加,不过雷神建议这样做,在ClassView中选中CMyApp6View类,击右键选择Add Member Variable插入它们。
//**************************
// myapp6View.h
private:
int m_nColor; //存放椭圆颜色值
CRect m_rectEllipse; //存放椭圆外接矩形
//***************************************************
问题1:CRect是什么?
CRect是类,是从RECT结构派生的,和它类似的还有从POINT结构派生的CPoint、从SIZE派生的CSize。因此它们继承了结构中定义的公有整数数据成员,并且由于三个类的一些操作符被重载所以可以直接在三个类之间进行类的运算。
//重载operator +
CRect operator +( POINT point ) const;
CRect operator +( LPCRECT lpRect ) const;
CRect operator +( SIZE size ) const;
//重载operator -
CRect operator -( POINT point ) const;
CRect operator -( SIZE size ) const;
CRect operator -( LPCRECT lpRect ) const;
......
更多的请在MSDN中查看
■第三步:修改由AppWizard生成的OnIntitalUpdate函数
void CMyApp6View::OnInitialUpdate()
{
CScrollView::OnInitialUpdate();
CSize sizeTotal(20000,30000);
CSize sizePage(sizeTotal.cx /2,sizeTotal.cy /2);
CSize sizeLine(sizeTotal.cx /50,sizeTotal.cy/50);
SetScrollSizes(MM_HIMETRIC,sizeTotal,sizePage,sizeLine);//设置滚动视图的逻辑尺寸和映射模式
}
问题2:关于void CMyApp6View::OnInitialUpdate()
函数OnInitialUpdate()是一个非常重要的虚函数,在视图窗口完全建立后框架用的第一个函数,框架在第一次调用OnDraw前会调用它。因此这个函数是设置滚动视图的逻辑尺寸和映射模式的最佳地点。
■第四步:编辑CMyApp6View构造函数和OnDraw函数
//*********************************************
// CMyApp6View构造函数
//
CMyApp6View::CMyApp6View():m_rectEllipse(0,0,4000,-4000)//椭圆矩形为4*4厘米。
{
m_nColor=GRAY_BRUSH;//设定刷子颜色
}
//*********************************************
// CMyApp6View的OnDraw函数
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -