?
?
?
o
o 《深入浅出mfc》学习笔记 来源:CSDN作者:CSDN 发布时间:2008-04-03 10:16:21 域名注册 域名惊喜价格 cn域名1元注册 com域名39.9元
虚拟主机
o
o 主机按月支付,低至19元/月 超大流量,可开子站点
o
o 特惠VPS168元/月,4-8M独享带宽保证 独立操作系统,无限开站点
《深入浅出MFC》是本人一直想深读的一本书,在刚开始学VC时虽然也曾化一些时间来看,但总觉得收获不大,经过一段时间的程式设计实践,目前回过头来看这些东西,觉得有了不少收获,或许这正是我喜欢这本书的原因所在,越读越有味道,越读越觉得书中的东西能够弥补自己的缺憾,这样的才算是真正的得到了阅读的乐趣吧。下面摘抄一些原文,并总结了一些学习心得,权当作一点小小的学习收获吧,也希望在写作和阅读的过程中获得更多的理解和体会。
文章结构如下,先引用一部分原文,然后是自己的学习心得,最后翻译了原文中引用的一段说明文件,对于要反复读取的重要书籍,我一贯采取这样的读法,先读框架结构,在细细研读,从中找出关键词句,写出自己的心得体会,然后反复用心体会,知道完全理解为止,只有这样,才能不辜负一本优秀的技术图书作者的良苦用心和自己所耗费的时间和精力吧。
原文:
凝聚性强、组织化强的类库就是Application Framework。一组合作无间的对象,彼此藉信息的流动而沟通,并且互相调用对方的函数以求完成任务,这就是Application Framework。
对于数据结构的安排,数据的处理,数据的显示,Application Framework所能提供的,无一不是单单一个空壳而已——在C++语言来讲就是个虚函数。软件研发人员必须想办法改造(override)这些虚函数,才能符合个人所需。
非常明显,Application Framework是一组终极的类库,能够被称为Framework者必须是其中的类性质紧密咬合,互相呼应。
19xx年微软公司成立Application Framework技术团队,名为AFX小组,用以研发C++面向对象工具给视窗系统应用程式研发人员使用。AFX的“X”其实没有什么意义,只是为了凑成一个响亮好念的名字。
学习心得:
Application Framework顾名思义是“应用程式框架”,说得抽象一点是个庞大的框架结构,该结构为程式研发提供了一个基本的实现平台,使我们能够在一群优秀工程师的工作基础上更加高效的工作。而具体一点说,实际上他是一套完整的类库,其中封装了一些实现各种功能的函数,用户只要了解这些类库的接口而不必了解其中复杂的实现过程就能设计出实用的程式。最常见的三套C++ Application Frameworks包括Microsoft的MFC,Borland的OWL,及IBM VisualAge的Open Class Library。所以说,如果把Application Frameworks当作一种以面向对象理论为基础的框架结构思想的话,上述三种类库则是其具体的实现。
原文:
MFC帮助我们把这些浩繁的APIS,利用面向对象的原理,逻辑地组织起来,使他们具有抽象化、封装化、继承性、多态性、模块化的性质。
为了让MFC尽可能的小、尽可能的快,AFX小组不得不舍弃高度的抽象,而引进他们自己发明的机制,尝试在面向对象领域中解决视窗系统消息的处理问题。即Message Mapping和Message routing机制。他们设计了一些令人拍案叫绝的宏,而这些宏背后隐藏着巨大的机制。
理解这些宏(及他们背后所代表的机制)的意义,及隐藏在MFC类之中的那些足以暴露原型机密的“麻烦事儿”,正是我认为掌控MFC这套Application Frameworks的重要手段。
MFC类主要可分为下列数大群组:
General Purpose classes:提供字符串类、数据处理类、异常处理类、文件类等等。
视窗系统 API classes:用来封装视窗系统 API,例如窗口类、对话框类、DC类等等。
Application framework classes:组成应用程式骨干者,即此组类,包括Document/View、消息泵、消息映射、消息传递、动态创建、文件读写等等。
High level abstrations:包括工具栏、状态栏、拆分窗口、滚动窗口等等。 Operation system extensions:包OLE、ODBC、DAO、MAPI、WinSock、ISAPI等等。
学习心得:
以前只知道使用,目前对MFC的概念才算有进一步了解,在程式设计过程中,应首先考虑自己实现的功能属于那一个MFC类的群组,然后再在相应的群组中选择适合自己的类进行研发,同时根据自己的需求进行扩展。
以下是对书中例子程式Scribble中readme.txt文件的翻译,个人以为虽然该文件是MFC框架中生成的最常见的文件,但从中却能了解一些MFC所生成的各种文件的基本用途。翻译的过程也是个非常好的学习过程。
========================================================================
MICROSOFT FOUNDATION CLASS LIBRARY : Scribble
========================================================================
AppWizard为你创建了该Scribble程式。该程式不仅演示了MFC的基本使用方法,而且是你书写应用程式的起点。
该文件对实现Scribble程式所用到的程式进行了总结说明。
Scribble.h
这是应用程式的头文件。包括其他特定的头文件(包括Resource.h)并声明了CscribbleApp应用程式类。
Scribble.cpp
这是包含应用类CscribbleApp的主应用程式源文件。
Scribble.rc
该文件给出了程式使用的所有Microsoft 视窗系统资源列表。包括存放在RES子路径下的图标,图片和光标。该文件可直接在Microsoft Developer Studio中编辑。
res\Scribble.ico
图标文件,用作应用程式图标,该图标包含在主资源文件Scribble.rc 中。
res\Scribble.rc2
该文件包含的资源无法用Microsoft Developer Studio编辑。故应把所有不可编辑的资源放入此文件。
Scribble.clw
该文件包含了ClassWizard要用到的信息,用于编辑存在的类和添加新类。ClassWizard也使用该文件存储用于创建和编辑消息映射、对话框数据映射及创建成员函数的信息。
/////////////////////////////////////////////////////////////////////////////
对于主框架窗口:
MainFrm.h, MainFrm.cpp
这些文件包含从CMDIFrameWnd派生的框架类CmainFrame,用于控制所有的MDI框架特性。
res\Toolbar.bmp
该图片用于创建工具条要用到的图片。CMainFrame 类创建了初始工具条和状态条。编辑MainFrm.cpp 和此工具条图片相关的数组能添加更多的工具条按钮。
/////////////////////////////////////////////////////////////////////////////
AppWizard创建一个文件类型和一个文件视图
ScribbleDoc.h, ScribbleDoc.cpp – 文件
这些文件包含CscribbleDoc类。能通过编辑这些文件添加特别的文件数据并实现文件的保存和装载(通过CScribbleDoc::Serialize).
ScribbleView.h, ScribbleView.cpp – 文件视图
这些文件包含CscribbleView类。CscribbleView对象用于查看CscribbleDoc对象。
res\ScribbleDoc.ico
图标文件,用作MDI子窗口图标。主资源文件Scribble.rc包含该图标。
/////////////////////////////////////////////////////////////////////////////
其他标准文件:
StdAfx.h, StdAfx.cpp
这些文件用于创建预编译头文件(PCH文件)及一个预编译类型的文件StdAfx.obj。
Resource.h
标准头文件,创建新的资源Ids。Microsoft Developer Studio读取和更新该文件。
通过上述内容能获得如下信息:
那个是应用程式的主文件,那些文件用于实现文件/视图结构,那些文件用于处理文件数据,那些是资源文件,分别用在什么地方,各个头文件的功能是什么,看了之后,是不是有些收获呢。
第二篇:MFC学习心得
AfxMessageBox与MessageBox的区别
AfxMessageBox的函数原型
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );
int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) –1 );
在第一种形式中,lpszText表示在消息框内部显示的文本,消息框的标题为应用程序的可执行文件名(如Hello)。在第二种形式中,nIDPrompt为要显示的文本字符串在字符串表中的ID。函数调用时会自动从字符串表中载入字符串并显示在消息框中。nType为消息框中显示的按钮风格和图标风格的组合,可以采用|(或)操作符组合各种风格。
按钮风格
MB_ABORTRETRYIGNORE 消息框中显示Abort、Retry、Ignore按钮
MB_OK 显示OK按钮
MB_OKCANCEL 显示OK、Cancel按钮
MB_RETRYCANCEL 显示Retry、Cancel按钮
MB_YESNO 显示Yes、No按钮
MB_YESNOCANCEL 示Yes、No、Cancel按钮
图标风格
MB_ICONINFORMATION 显示一个i图标,表示提示
MB_ICONEXCLAMATION 显示一个惊叹号,表示警告
MB_ICONSTOP 显示手形图标,表示警告或严重错误
MB_ICONQUESTION 显示问号图标,表示疑问
与AfxMessageBox类似的函数MessageBox,它是CWnd的类成员函数:
int MessageBox( LPCTSTR lpszText,LPCTSTR lpszCaption = NULL,UINT nType = MB_OK );
两个函数的区别:AfxMessageBox比 MessageBox简单一些,因为它是一个全局函数所以不需要对应的一个窗口类,但是不能控制消息框标题,常用于调试程序时的内部数据输出或警告;MessageBox比较正式,常用在要提交的应用程序版本中,可以控制标题内容而不必采用含义不明的可执行文件名为标题。
举例:
AfxMessageBox(“Are you sure?”,MB_YESNO|MB_ICONQUESTION);
int a = MessageBox(TEXT( "是否确认删除?" ), TEXT("Warning!!"),4);
if (a == 6)
AfxMessageBox("Yes");
else
AfxMessageBox("No");
(其中#define IDYES 6 #define IDNO 7)
VC中可调用的函数大致可分三类:
1.类自己的函数,只对类自己的数据成员有作用;
2.AFX小组在设计 Application Framworks 时设计的全局函数,多冠在Afx前缀,在包含了MFC库/框架的工程中可用;
3.Windows API的全局函数。对所有Windows平台下的程序设计都可以调用,如Vb,Vc,Dephi等等。你说的 MessageBox是属于 CWnd 类的成员函数,只能在 CWnd 和CWnd的派生类的对象中调用;AfxMessageBox则可在任何地方调用。另外对应的还有: ::MessageBox()这个windows API的全局函数。上述中1和3一般有一个区别,就是1要比3少一个参数,即窗口句柄。大家知道,这个句柄是通过 this 指针曲折转换得到的,不用程序员操心了。
WM_INITDIALOG
WM_INITDIALOG消息是对话框才能收到的消息,表明对话框及其所有子控件都创建完毕了。这个状态肯定是调用显示对话框的函数之前。
LRESULT CALLBACK WindowProc(
HWND hwnd, // handle to window
UINT uMsg, // WM_INITDIALOG
WPARAM wParam, // handle to control (HWND) L
PARAM lParam // initialization parameter);
wParam:是将要设置的获取键盘焦点的控件句柄
lParam:是初始化参数见(msdn)
WM_INITDIALOG与WM_CREATE的区别: WM_CREATE是所有窗口都能响应的消息,表明本窗口已经创建完毕.在响应WM_CREATE消息响应函数的时候,对话框及子控件还未创建完成,亦是说只是通知系统说要开始创建窗口啦,这个消息响应完之后,对话框和子控件才开始创建。因此在此消息响应函数中无法对控件进行修改和初始化。 而WM_INITDIALOG消息响应函数是在程序运行时,当其对话框和子控件全部创建完毕,将要显示内容的时候发送的消息。因此可以在WM_INITDIALOG消息响应函数中添加对编辑框控件的初始化和修改。
EnableWindow
函数功能:该函数允许或禁止指定的窗口或控制接受鼠标输入或键盘输入。当输入被禁止时窗口不能接收鼠标单击和按键等类输入;当输入允许时,窗口接受所有的输入。
函数原型:BOOL EnableWindow(HWND hWnd,BOOL bEndble);
参数:
hWnd:允许或禁止的窗口句柄。
bEnable:指定是允许还是禁止窗口。如果这个参数为TRUE,窗口允许;如果参数为FALSE,则窗口被禁止。
返回值:如果窗口此前曾被禁止,则返回值为非零;如果窗口此前未被禁止,则返回值为零。若想获得更多错误信息,请调用 GetLastError函数。
备注:如果窗口的使能状态正在改变,则在EnableWindow函数返回前发送一个WM_ENABLE消息。如果窗口己经被禁止,则它的所有子窗口都被禁止,即使未向它们发送WM_ENABLE消息。
在一个窗口被激活前必须是使能的。例如,如果应用程序正在显示一个无模式对话框并且禁止了它的主窗口,则应用程序在销毁对话框之前一定要使能该主窗口。否则,将有另外一个窗口接受键盘焦点并且被激活。如果一个子窗口被禁止,则在系统确定由哪一个窗口接受鼠标消息时该子窗口将被忽略。
当窗口被创建时缺省为使能状态。要创建一个初始被禁止的窗口,应用程序可以在CreateWindowh 函数和CreateWindowhEx中指定WS_DISABLED风格。在窗口被创建后,应用程序可以使用EnaoleWindow函数来使能和禁止窗口。
应用程序可以使用这个函数来使能或禁止在对话框内的控制。一个被禁止的控制不能接受键盘焦点用户也不能进入该控制。
它的子窗口控件 (如单选按钮、 复选框、 滚动条等) 之一就是要在屏幕上绘制每次 WM_CTLCOLOR 邮件是发送到一个窗口。此消息之前控件的绘制。 当需要更改控件的外观这可以通过处理 WM_CTLCOLOR 消息。
更多信息使用WM_CTLCOLOR消息
当发送 WM_CTLCOLOR 时,wParam 包含为子窗口(在本例中该控件)显示上下文的句柄。lParam 的 LOWORD 标识子窗口由其 ID 号并...
当发送 WM_CTLCOLOR 时,wParam 包含为子窗口 (在本例中该控件) 显示上下文的句柄。lParam 的 LOWORD 标识子窗口由其 ID 号并 lParam 的 HIWORD 包含为下列值之一指定要绘制的控件的类型:
CTLCOLOR_BTN button control
CTLCOLOR_DLG dialog box
CTLCOLOR_EDIT edit control
CTLCOLOR_LISTBOX list box
CTLCOLOR_MSGBOX message box
CTLCOLOR_SCROLLBAR scroll bar
CTLCOLOR_STATIC static text, frame, or rectangle
在处理时 WM_CTLCOLOR 画笔的句柄必须返回。 若要返回画笔的句柄失败将导致在调试版本的 Windows 中调试显示器上一个 Windows FatalExit。
DefWindowProc() 已为此邮件的响应中返回一个句柄 ; 但是,应用程序可能返回不同的句柄自定义控件的颜色。返回的句柄指定要用来绘制该控件画笔。例如对于 Windows 2.x 在下面的代码绘制的所有按钮浅灰色背景:
case WM_CTLCOLOR:
if (HIWORD(lParam) == CTLCOLOR_BTN)
return (GetStockObject(LTGRAY_BRUSH));
return (GetStockObject(WHITE_BRUSH));
在这种情况下,所有其他控件的背景绘制白色。 请注意 GetStockObject() 返回参数所指定的股票画笔的句柄。若要将在 Windows 3.0 和更高版本中的一个按钮控件的背景色就需要创建一个所有者绘制按钮。
返回画笔的句柄提供了一些有趣的可能性,因为画笔的句柄不是限于从 GetStockObject() 返回。可以从位图生成图案画笔。如果图案画笔的句柄返回响应 WM_CTLCOLOR 消息,该画笔将用于绘制控件的背景。
下面的代码的更改画图中找到的购物篮织物模式的滚动条的滚动块轨道区域绘制:
/* Add these global variables. The array of WORDs specifies the */
/* pattern for the brush */
HBRUSH hBrush;
HBITMAP hBitmap;
WORD wWeave[]={0x0F, 0x8B, 0xDD, 0xB8, 0x70, 0xE8, 0xDD, 0x8E};
...
/* Add these lines to WinMain */
hBitmap = CreateBitmap(8, 8, 1, 1, (LPSTR)wWeave);
hBrush = CreatePatternBrush(hBitmap);
...
/* Add this case to the Windows procedure or wherever the */
/* messages are processed. */
case WM_CTLCOLOR:
if (HIWORD(lParam) == CTLCOLOR_SCROLLBAR)
return (hBrush);
return (GetStockObject(WHITE_BRUSH));
的 WM_CTLCOLOR 消息也适用于控件的下列五类:
1. 复选框、 单选按钮和推按钮: 绘制矩形区域的控件位于用选定的画笔 ; 控制形状和文本绘制上绘制的图案。
2. 编辑控件: 绘制编辑区域。
3. 分组框: 绘制标题文本的背景矩形区域。
4. 滚动条: 绘制跟踪缩略图周围区域。
5. 列表框: 绘制列表区域。
静态文本、 框架,和矩形不受影响的 WM_CTLCOLOR。
注: 在 3.0 版及更高版本的 Windows,应用程序不能更改的按钮表面颜色。但是,用户可以使用控制面板来更改系统中的所有应用程序的按钮颜色。此外可以通过修改的 WIN.INI 文件,以添加 [颜色] 部分来完成这一"ButtonFace ="指定按钮表面颜色的 RGB 颜色值的行。
处理 WM_CTLCOLOR 消息只会更改由应用程序创建的子窗口的颜色。Windows 将 WM_CTLCOLOR 消息发送到每个这些控件的父窗口。滚动条的一部分包括由 Windows 的编辑控件或列表框不会受到影响。滚动块跟踪 WIN.INI 中或通过控制面板,只可以更改条形图的系统生成的滚动的区域。
也可能是将绘制一个对话框中的整个背景。 下面的代码可用于提供对话框框颜色:
long FAR PASCAL MainWindowProc(....);
...
case WM_CREATE:
hTempBrush = LoadBitmap(hInst, (LPSTR)"MyPatternBrush");
hBrush = CreatePatternBrush(hTempBrush);
DeleteObject(hTempBrush);
...
case WM_DESTROY:
DeleteObject(hBrush);
...
BOOL FAR PASCAL
MyDialogProc(....);
...
case WM_CTLCOLOR:
if (bMonoChrome)
return (FALSE); // Do nothing if on a monochrome monitor
// bMonoChrome is a global set during
// initialization.
if (CTLCOLOR_DLG == HIWORD(lParam))
UnrealizeObject(hBrush);
SelectObject((HDC)wParam, hBrush);
if (CTLCOLOR_DLG == HIWORD(lParam))
SetBrushOrg((HDC)wParam, 0, 0);
SetBkMode((HDC)wParam, TRANSPARENT);
SetTextColor((HDC)wParam, RGB(0, 0, 0));
return(hBrush);
...
此代码将确保的带图案的位图将对齐正确跨整个对话框。"MyPatternBrush"是使用 SDKPaint 创建位图的名称。该位图必须包含在.rc 文件。