写在前面:
站长所看的『VC++技术内幕』版本为--潘爱民和王国印译清华大学出版的第四版,因有时工作忙碌,不能及时更新,请大家见谅!
第一天 Windows的编程模式
Windows程序中必须要有WinMain函数,因为该函数最重要的任务是创建该应用程序的主窗口。Windows程序与基于MS-DOS程序的最大差别就在于:MS-DOS程序是通过调用操作系统的功能来获得用户输入的,而Windows程序是通过操作系统发送的消息来处理用户输入的。Windows消息都是经过严格定义的,并且适用于所有的程序。 WINDOWS提供通用的图形设备接口(GUI),我们通过调用(GDI)函数和硬件打交道,不必理会设备环境,WINDOWS会自动将设备环境结构映射到相应的物理设备。 Windows程序设计中所需要的数据是存储在资源文件中的,这样,连接器就可以把编译好的二进制代码和二进制资源文件结合起来生成可执行程序。资源文件可以包括位图、图标、菜单定义、对话框设计,甚至可以包含用户自己定义的格式。 Windows程序允许动态的连接目标模块,并且多个应用程序可以共享同一个动态连接库。 VC++的源程序浏览器能够使我们从类或函数的角度来了解或编辑程序,而不是直接从文件入手。在看别人的源代码时如果能熟练的使用源代码浏览器将会事半功倍。源程序浏览器主要的查看状态有以下几种: Definitions and References--选择任何函数、变量、类型、宏定义可以看到它在项目中的定义,并且在何处和什么地方用到它。 Call Graph/Caller Graph--对于所选择的函数,给出它的调用与被调用函数的图示。 Derived Class Graph/Base Class Graph--给出类层次关系的图形表示,可以看到所选择的类的派生类和基类以及成员。 File Outline--对于所选的文件,列出文件中的类、函数和数据成员,同时还显示它们定义的位置和使用位置。 可见Source Brower比起Class View来功能多了很多也更加好用。 对于本章学习loose_went建议大家在VC++6中用AppWizard生成一个空的程序,然后试着看看都有哪些文件,和他们的类层次、函数、宏、结构的定义,我就是这样干的,学编程不动手是不行的。
第二天 MFC应用程序框架
?MFC是C++的Microsoft Windows API ?MFC产生的应用程序使用了标准化的结构。 ?MFC产生的应用程序短而运行速度快。 ?VC++工具降低了编码的复杂性,这当然了,很多代码都由它代劳了,呵呵。 ?MFC库应用程序框架的功能非常丰富。 以上说的都是MFC库的优点,虽然说MFC有着这样多的优点,但我个人认为不能盲目的学习它,要想学好,那么您必须先掌握C++,这是毋庸置疑的。可能刚开始的时候,您觉得收获很大,也很有趣,但要进一步提高,没有C++基础是很难的。所以站长建议大家学习的时候要有先有后,这样才能学好! 应用程序框架是一种类库的超集。 我们现在先来看一个例子,看看MFC有多么强大!您只需加一行代码,甚至一行都不用加只需要点几下鼠标就可以创建一个windows 程序,不信,试一下: 1、打开VC++6从菜单选择NEW,给项目命名为"MyApp "。 2、选择MFC AppWizard[exe] 选项,除STEP 1选择单文档外其他STEP缺省。 3、在Class View选择CMyAppView类的OnDraw()成员函数双击会在C++编译器看到以下内容
void CMyAppView::OnDraw(CDC* pDC) { CMyAppDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here } 在 // TODO: add draw code for native data here的位置增加一行代码 void CMyAppView::OnDraw(CDC* pDC) { CMyAppDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); pDC->TextOut(10,10,"愿vc在线能成为您学习vc最好的朋友!"); //增加的一行 // TODO: add draw code for native data here } 完了,就这么简单。编译运行。看到了吗?这个程序具备WINDOWS程序的所有特性,例如有菜单、工具条、状态栏、最大化、关闭、甚至还有关于对话框、打印预览.....全了,这就是AppWizard通过MFC动态创建的一个应用程序。从这个小例子可以看出用VC/MFC设计WINDOWS程序多么方便。
下面我们看看书上的例子,以便更进一步了解应用程序框架。 1、先建立一个Win32 Application的应用程序。 2、选择Project->Add to project->Files,分别创建一个名为MyApp.h和一个名为MyApp.cpp的文件。 3、添加代码:(最好照敲一下代码到编译器,别用Ctrl+C/Ctrl+V) //*********************************************** // MyApp.h //
class CMyApp:public CWinApp { public: virtual BOOL InitInstance(); };
class CMyFrame:public CFrameWnd { public: CMyFrame(); protected: afx_msg void OnLButtonDown(UINT nFlags,CPoint point); afx_msg void OnPaint(); DECLARE_MESSAGE_MAP() };
//***************************************************** // MyApp.cpp //
#include "afxwin.h" #include "myapp.h" CMyApp theApp;//建立一个CMyAPP对象 BOOL CMyApp::InitInstance () { m_pMainWnd=new CMyFrame(); m_pMainWnd->ShowWindow (m_nCmdShow); m_pMainWnd->UpdateWindow (); return TRUE; }
BEGIN_MESSAGE_MAP(CMyFrame,CFrameWnd) ON_WM_LBUTTONDOWN() ON_WM_PAINT() END_MESSAGE_MAP()
CMyFrame::CMyFrame(){ Create(NULL,"MYAPP Application"); } void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point) { TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d\n", (long)nFlags,point.x ,point.y); }
void CMyFrame::OnPaint () { CPaintDC dc(this); dc.TextOut (0,0,"Hello World!"); }
4、编译运行,报错。为什么呢?原来还没有添加MFC的支持,在Project Setting选项General属性页选择"Use MFC in a Static Library" 5、再按Ctrl+F5,怎么样,简单吧? 让我们看看这个程序中的一些元素。 ①WinMain函数:Windows总是要求每个应用程序都要有WinMain函数的,您之所以看不见,是因为它已经隐藏在应用程序框架内部了。 ②CMyApp类:CMyApp类的对象代表一个应用程序,CWinApp基类决定它的大部分行为。 ③应用程序的启动:当开始运行应用程序时WINDOWS会调用WinMain函数,WinMain会查找该应用程序的全局对象theApp。 ④CMyApp::InitInstance成员函数:发现theApp后自动调用重载的虚函数InitInstance来完成主窗口的构造和显示工作。 ⑤CWinApp::Run成员函数:WinMain在调用InitInstance之后紧接着调用Run函数,它被隐藏在基类中负责传递应用程序的消息给相映的窗口。 ⑥CMyFrame类:此类的对象代表着应用程序的主窗口。它的构造函数调用基类CFrameWnd的Create函数创建具体的窗口结构。 ⑦CMyFrame::OnLButtonDown函数:演示消息处理机制,当鼠标坐键被按下这一事件被映射到CMyFrame的OnLButtonDown函数上,如果你选择F5进行编译运行的话可以在调试窗口看到TRACE宏显示的类似下面的信息 Entering CMyFrame::OnLButtonDown - 1,309,119 Entering CMyFrame::OnLButtonDown - 1,408,221 ⑧CMyFrame::OnPaint函数:应用程序每次重新绘制窗口都需要调用此函数,将显示"Hello World!"放在这里是因为每次窗口发生变化时保证"Hello World!"被显示,你可以试着将语句: CPaintDC dc(this); dc.TextOut (0,0,"Hello World!"); 写在别出,例如写在 void CMyFrame::OnLButtonDown (UINT nFlags,CPoint point) { TRACE("Entering CMyFrame::OnLButtonDown - %lx,%d,%d\n", (long)nFlags,point.x ,point.y); CPaintDC dc(this); dc.TextOut (0,0,"Hello World!"); } 运行后当点击左键时显示"Hello World!",但当窗口最小化再最大化时"Hello World!"不见了。 ⑧关闭应用程序:用户关闭应用程序时会有一系列事件发生。首先CMyFrame对象被删除,然后退出Run,进而退出WinMain,最后删除CMyApp对象。 通过上面的示例我们看见程序的大部分功能包含在基类CWinApp和CFrameWnd中,我们只写了很少的函数,便可以完成很复杂的功能。所以应用程序框架不仅仅是一种类库,它还定义了应用程序的结构,除了基类外还包括WinMain函数,以及用来支持消息处理、诊断、DLL、等都包含在应用程序框架中。
第三天 消息映射和视图类
MFC库应用程序框架没有采用虚函数来处理windows消息,而是通过宏将消息映射到派生类相应的成员函数上。文档-视图结构是应用程序框架的核心,它把数据从用户对数据的观察中分离出来,这样做最大的好处就是同一个数据可以对应多个视图。比如同一个股票报价数据,既可以有报表观察窗口,也可以有图形观察窗口,明白了否? 视图简单来说就是一个普通的窗口,对于程序员来说就是一个从MFC库中Cview类派生出来的类的一个对象。视图类分为两个源文件模块:头文件(H)和源代码文件(CPP)。 用Appwizard创建一个SDI应用程序,产生了如下文件(假设工程名为Exc01): Exc01.dsp 项目文件,Visual Studio用它来创建应用程序 Exc01.dsw 工作空间文件,包含一个项目Exc01.dsp Exc01.rc ASCII码资源描述文件 Exc01View.cpp 包含CExc01View类成员函数和视图类文件 Exc01View.h 包含CExc01View类定义的视图类头文件 Exc01.opt 二进制文件,告诉Developer Studio本项目的哪些文件是打开的,又是如何排序的 Readme.txt 用来解释所产生的所有文件的文本文件 Resource.h 包含#define常量定义的头文件 从Exc01View.cpp和Exc01View.h的代码中可以看出,这两个文件已经完全定义了CExc01View类,而该类正是此应用程序的核心。CExc01View类的对象与应用程序的视窗相关联,应用程序的所有"动作"都会在这个视窗中显示出来。 CExc01View类的两个最重要的基类是CWnd和CView类。CWnd类提供了CExc01View的窗口属性,而CView类则提供了它和应用程序框架的其它部分之间的联系,特别是和文档以及框架窗口之间的联系。这一点一定要记住。 下面我们来看一下如何在视窗内绘图。最重要的一个函数是OnDraw()函数,它是一个虚函数,每次窗口被重画时,应用程序都要先调用这个函数。注意:尽管可以随时对窗口绘制,但最好还是等变化内容积累到一定程度后再教给OnDraw()函数处理,这样效率会高一些。 在MFC中,设备环境是由C++的CDC类对象来表示的,该对象被作为参数传给Ondraw()函数,这样,我们就可以调用CDC的许多成员函数来完成各种绘制了。 找到OnDraw()函数,用以下语句替换函数原来的内容: pDC->TextOut( 0, 0, "Hello World!" ); pDC->Ellipse(CRect(0,20,100,120)); 再编译运行,看到了什么? TextOut和Ellipse都是设备环境类CDC的成员函数,MFC库提供了一个用来表示windows矩形的类CRect,在这里CRect的一个临时对象被作为参数传递给 了Ellipse函数,当外接矩形的宽和高相等时,Ellipse函数就画出个圆。
(责任编辑:泉水)
|