MFC入门

来源:互联网 发布:哪种编程语言好 编辑:程序博客网 时间:2024/05/22 00:33

原文http://sakura006.blog.hexun.com/31435400_d.html

写下这篇小结,最主要的目的,是让自己复习一下这两日的所学,并方便以后记忆;另外,也希望跟一些曾经跟我一样经历弯路,对MFC有兴趣的人分享一下(按着我的思路,我自己倒是挺明白的,不知道别人能否看得懂。下面的心得部分可以跳过的!)。

这两日的心得

这两天没什么事儿可做,从上头儿也得不到任务,总不能够别人天天儿的晾着你,你就不争气的也得过且过,自己晾着自己吧!碰巧昨天早上拎起来一本书(忘了是出于什么样的目的了),然后拿到手里之后,就没再搁下。

其实一直想入门MFC的,常常听人说“VC只是一个开发环境,MFC才是它的精华”。可是自从开学以来,近一个月内,尝试了很多途径,看书,边看边自己动手编,电子的和书面的都看过,只是还是觉得书本上的代码,在自己真正去尝试的时候,也是晦涩难懂,不易操作的。印象较深刻的几本书是孙鑫的《VC++深入浅出》、《MFC深入浅出》、《windows程序设计》,这些都是口碑不错的书,只能说自己的根基太差,所以也不得领悟吧。也在网上看一些“过来人”的blog,看相关的日志,连载就是十几篇,一般都是开始的时候,兴致还不错,越到后边,遇到的错误也越来越多,还无人能给以解答,直到最终难以继续往下,不得不搁浅。可惜,通过这一切都没能走上所谓的“正途”(正确的途径啦)!没想到偶然间瞥见的那一眼,却给我带来了不小的帮助,让我从一个彻彻底底的门外汉踏进了MFC的大门(也许还是有些片面吧,说到底,还是只学了两天呀)。

有一些体会,也许到现在才体会出来,有些晚了,但是至少还是明白了,也不错,就这么一点一点的坚持到底,也是好的!

切身体会,首先值得明确的是,C++和VC++是不同的。我用了两个星期的时间把C++的书翻了一遍,对C++的基本内容有了一个整体上的了解,如类、继承、封装、多态、模板等,但是当自己刚刚编程序的时候,还是不能领悟“面向对象编程”的真谛。甚至还曾误认为自己编出来的第一个程序就面向对象的程序,后来我承认那不过是一种最简单的面向过程的编程方法。我为自己曾经萌生的那么一点点小骄傲的情感,实感到惭愧。C++只是一门语言,VC++则是C++语言的一个编译环境,软件开发工具。而MFC则是VC++的本质和精华所在。所以学习VC,必须得掌握MFC。

曾经看到过这样一些经验的话,大概是这样说的:学习VC,不要像我们学英语那样的方法,而要像婴儿学说话一样。想象确实有道理,我们在最初学C的那种模式(详细的弄懂每个细节,在课本上纠错,记下所有的语法规则,却很少上机实践,不着重于解决实际问题,最终以考试成绩来断定学习成果)。这种模式的后果是很可怕的,考试完了,能有几人能够上机实现一个简单的程序?就像我们学了十几年的英语,虽然单词背了几千个,我们会做题,会写作文,但是真正接触外国人的时候,却只能当个哑巴和聋子。而像婴儿一样学习,则是在使用中学会语法和词汇,一开始可能很糟糕,但是学习效率却是高的。学习VC就应该从最简单的应用程序开始,由简单向复杂迈进,就像滚雪球一般,越滚越大。而不应该着重于那些语法、句法的细节之上。所以迈进MFC的大门,也从最简单的开始

也正是现在的我,当我再次想起这些话的时候,才颇有些感触,因为似乎这一个多月以来,一直在走弯路,而此刻却有一种走上正途的感觉,虽然前面的路是未知的,也许存在艰难,但是艰难却阻挡不了前路的一片光明。

 

下面总结一下这两天来,入门的一些历程和知识——

编写visual C++程序首先要创建一个良好的可视化界面,而每个程序界面是由对话框(Dialog)和一些必要的控件(Control)构成的。界面设计的一般步骤:在对话框上布置控件;设置各控件属性;设置对话框属性。

Example:设计如下图所示的计算器:

查看更多精彩图片

下面来创建一个对话框应用程序,步骤如下:

第1步:创建新项目new project

1.       在IDE环境中,选择File->New,弹出 New对话框。

2.       在对话框的左侧列表框中选择MFC AppWizard (exe)。

3.       在Project Name文本框中输入项目名称:Example ;在Location文本框中输入项目存盘路径,或单击右边的按钮选择相应的路径 ;选中Create new workspace单选按钮 ;在Platforms列表中选中Win32选项 ;点击OK按钮。弹出MFC AppWizard对话框。

如图1所示:

查看更多精彩图片

第2步: MFC AppWizard向导

在MFC AppWizard对话框中:

1.       step1 of 4选择程序的文档支持类型:选择Dialog based 、语言支持选择简体中文、单击Next按钮,如图2示;

2.       step2 of 4中,选择程序的界面选项:取消对About box的选择,单击Next按钮,如图3示。

3.       step3 of 4,选择程序的其他选项:一般选择As a statically linked library,如图4示。

4.       step4 of 4,确认文件和类名:这里选择默认即可,点击Finish按钮,如图5示。

本对话框中,显示了AppWizard为用户所产生的类,及该类的基类和存储该类的头文件和源代码文件。

5.       弹出New project information对话框:显示用户在前面的选择,如图6示。

6.       点击OK按钮,AppWizard将按设定的选项为用户产生代码。此时开发环境中会显示当前应用程序。创建对话框应用程序成功,如图7示。

查看更多精彩图片

图2

查看更多精彩图片

图3

查看更多精彩图片

图4

查看更多精彩图片

图5

查看更多精彩图片

图6

查看更多精彩图片

图7



图7

第3步:定制对话框

新建一个基于对话框的应用程序,删除向导自动添加的控件。定制对话框一般需要的步骤如下:设置对话框本身的属性;向对话框放置控件;通过控件属性对话框设置各个控件的属性。

1.       设置对话框本身的属性(右键->Properities)

属性对话框中,默认caption为EXAMPLE更改为“简易计算器”

Font选项,更改字体风格和大小,默认为宋体、小五,如图8所示:

查看更多精彩图片

查看更多精彩图片

查看更多精彩图片

图8

2.       添加控件

添加控件,借助于控件工具箱,如图9所示,具体按钮的功能,见后。

查看更多精彩图片

图9

选取适当的控件,改变控件位置,调整控件大小

注意1:想要删除控件时:选中控件,选择菜单Edit|Delete即可!!或者直接使用键盘上的【delete】键。

注意2:在对话框上显示网格,这些网格可以方便用户调整控件的位置和大小,且控件总是自动对齐网格:layout->Guide Settings,默认设置为Rulers and guides,更改为Grid就会在对话框的设计阶段显示网格。另外,通过layout菜单中的命令,可以对控件进行快速布局,如对齐、统一大小、调整控件之间的水平间距和垂直间距等操作。注意控制布局的基准控件的选择秘密就在控件的选择顺序上,使用【shift】+鼠标单击选择多个控件时,最后一个被选中的控件为基准控件。

网格只在程序的设计阶段出现,运行时不显示。如图10所示:

查看更多精彩图片

图10

 

本例中,需要添加2个Buttton控件、1个Group Box控件、4个Radio Button控件、3个Edit Box控件、2个Static Text控件。如图11所示.

查看更多精彩图片

图11

3.       设置控件属性

使用属性窗口,对于对话框窗口及各种控件,单击鼠标右键选择Properties,

四种属性设置的类型:ID为按钮的ID,Caption为按钮在界面上显示的内容,Font属性,改变命令按钮的字体名称、字体样式,如图8所示。

设置完毕后各控件的属性如下:

控件类型

ID属性

Caption属性

附加

Button

IDCANCEL

退出

 

Button

IDC_BUTTON_CAL

计算

 

Group Box

IDC_STATIC

选择运算类型

 

Radio Button

IDC_RADIO_ADD

选择Group属性复选框

Radio Button

IDC_RADIO_SUB

 

Radio Button

IDC_RADIO_MULTI

 

Radio Button

IDC_RADIO_DIV

 

Edit Box

IDC_EDIT_VALUE1

 

 

Edit Box

IDC_EDIT_VALUE2

 

 

Edit Box

IDC_EDIT_RESULT

 

 

Static Text

IDC_STATIC_FLAG

+

 

Static Text

IDC_STATIC

=

 

Check Box

IDC_CHECK

立即显示运算结果

 

 

设置完成后如图12所示:

查看更多精彩图片

图12

定制完毕后,可以通过layout->Test菜单预览对话框,按【ESC】退出预览,如图13所示。

 

 查看更多精彩图片

图13

第4步:定义成员变量

 

“增加了这么多的控件,那么如何在程序中协调和控制这些控件呢?如何建立控件之间的联系?程序如何得知用户对控件的操作并做出响应呢?

解决这个问题的方法是:定义一些与控件相联系的变量,在程序中,通过这些变量来完成对控件的控制;为控件添加事件处理函数,将用户对控件的操作(如单击按钮、改变单选按钮的选择等)作为一个事件通知给程序,由程序的事件处理函数完成对用户操作的处理。”

为控件定义变量的简单方法是:通过ClassWizard。即选择菜单View|ClassWizard,弹出MFC ClassWizard对话框,选择其Member Variables窗口。选中Control ID中的一行,双击鼠标或单击Add Variable…按钮,在弹出的对话框中为对话框增加与控件相联系的成员变量。如图14所示。

选择变量的类别category为value表示所定义的变量为与控件相联系的一个值,这个值的含义随不同类型的控件而不同 变量类型、变量名(如编辑框,变量表示在编辑框所输入的内容;复选框,表示该复选框是否被选择);选择category为control,则表示所定义的变量是控件类的一个对象(如编辑框,control变量的类型为CEdit)。

 查看更多精彩图片

图14

注意1:对于一个控件,可以同时定义它的value变量和control变量,但是不能为一个控件定义两个value变量或两个control变量。

注意2:没有必要为按钮增加关联变量。

注意3:对于value类型的数值,可以设定数值的范围;对于CString类型可以设定最大字符的长度,如图。。所示,如密码操作时可以使用;而编辑框,则可以设置为隐藏。

本例中,需要增加的变量如下图15中所示:

 查看更多精彩图片

图15

注意Class name选择 CExampleDlg

 

第5步:增加事件处理函数

 

可以在ClassWizard的Message Maps选项卡为控件添加事件处理函数,也可以通过专门的事件处理对话框。

如选中“计算”按钮,单击鼠标右键,在弹出的快捷菜单上选择Events,弹出的对话框,用于添加、删除窗口的消息和事件处理函数。如图所示,本程序需要在鼠标单击“计算”按钮时计算运算结果,故需要为此按钮增加单击事件处理函数,方法是双击左边列表框中的BN_CLICKED一行,这时弹出一个对话框可修改事件处理函数的名字,如图所示。保持默认名字,直接单击OK按钮即可。

增加了处理函数的事件名移动到了右边的列表框中,单击Edit Existing按钮(直接双击“计算”按钮)可以直接进入到对话框的源文件中,为事件响应函数增加代码。如下图16、17所示

查看更多精彩图片

图16

查看更多精彩图片

图17

增加了处理函数的事件名移动到了右边的列表框中,单击Edit Existing按钮(直接双击“计算”按钮)可以直接进入到对话框的源文件中,为事件响应函数增加代码。

同样的方法为下列的事件增加处理函数:

IDC_EDIT_VALUE1的EN_CHANGE

IDC_EDIT_VALUE2的EN_CHANGE

IDC_RADIO_ADD的BN_CLICKED

IDC_RADIO_SUB的BN_CLICKED

IDC_RADIO_MULTI的BN_CLICKED

IDC_RADIO_DIV的BN_CLICKED

BN_CLICKED事件当鼠标单击按钮类控件(单选按钮、复选框都属于此类)时触发;而当用户双击按钮类控件时,BN_DOUBLECLICKED事件被触发;EN_CHANGE指编辑框的内容被用户改变了;EN_KILLFOCUS指控件即将失去输入焦点;EN_HSCROLL指用户单击了控件的水平滚动条。 

第6步:增加程序代码

为对话框增加了控件事件处理函数后,这些函数的函数体都是空的,需要手工添加代码来实现用户想要的功能。

打开ExampleDlg.cpp文件,为对话框添加的所有事件处理函数都在这个文件中实现(在ExampleDlg.h中声明),

各关联变量的初值在函数ExampleDlg::ExampleDlg(它是本程序主对话框类Example的构造函数)中初始化,我们需要在这儿修改某些变量的初值。把m_dOpr的初值由-1改为0(-1表示没有单选按钮被选中,n表示第n-1个单选按钮被选中);把m_strOpr的初值变为“+”,以便在程序开始显示“+”号而不是别的运算符。

双击“计算”按钮,在相应的代码块添加代码:

void CExampleDlg::OnButtonCal()

{

       // TODO: Add your control notification handler code here

       UpdateData(true);

       switch(m_dOpr)

       {

       case 0:  //加

              m_fResult=m_fValue1 + m_fValue2;

              break;

       case 1:  //减

              m_fResult=m_fValue1 - m_fValue2;

              break;

       case 2:  //乘

              m_fResult=m_fValue1 * m_fValue2;

              break;

       case 3:  //除

              m_fResult=m_fValue1 / m_fValue2;

              break;

       }

       UpdateData(false); 

}

同理,点击edit1、edit2、加、减、乘、除,在相应的代码部分,增加以下代码

void CExampleDlg::OnChangeEditValue1()

{

       // TODO: If this is a RICHEDIT control, the control will not

       // send this notification unless you override the CDialog::OnInitDialog()

       // function and call CRichEditCtrl().SetEventMask()

       // with the ENM_CHANGE flag ORed into the mask.

// TODO: Add your control notification handler code here

       UpdateData();

       if(m_bAtOnce)

       {

              OnButtonCal();

       }    

}

 

void CExampleDlg::OnChangeEditValue2()

{

       // TODO: If this is a RICHEDIT control, the control will not

       // send this notification unless you override the CDialog::OnInitDialog()

       // function and call CRichEditCtrl().SetEventMask()

       // with the ENM_CHANGE flag ORed into the mask.

      

       // TODO: Add your control notification handler code here

       UpdateData();

       if(m_bAtOnce)

       {

              OnButtonCal();

       }    

}

 

void CExampleDlg::OnRadioAdd()

{

       // TODO: Add your control notification handler code here

       UpdateData(true);

       m_strOpr="+";

       UpdateData(false); 

}

 

void CExampleDlg::OnRadioDiv()

{

       // TODO: Add your control notification handler code here

       UpdateData(true);

       m_strOpr="÷";

       UpdateData(false); 

}

 

void CExampleDlg::OnRadioMulti()

{

       // TODO: Add your control notification handler code here

       UpdateData(true);

       m_strOpr="*";

       UpdateData(false); 

}

 

void CExampleDlg::OnRadioSub()

{

       // TODO: Add your control notification handler code here

       UpdateData(true);

       m_strOpr="-";

       UpdateData(false); 

}

 

OnButtonCal()用于当用户单击“计算”按钮时计算两个数的运算结果,并显示到结果编辑框中;OnRadioAdd()、OnRadioDiv()、OnRadioMulti()、OnRadioSub()4个事件处理函数用于当用户通过单选按钮改变所要进行的运算类型时(如由加变为除),程序控制IDC_STATIC_FLAG静态文本框中显示的运算符也做相应的改变(如由“+”变为“÷”);OnChangeEditValue1()、OnChangeEditValue2()用在当“立即显示运算结果”复制框被选择时,这是每当左边的两个编辑框中的内容有所改变(表示参与运算的两个数之一已经改变)程序就应该立刻重新计算运算结果。

以上代码频繁的使用函数UpdateData(),格式如下:

BOOL UpdateData(BOOL bSaveAndValidate=TRUE);

UpdateData是MFC类CWnd的成员函数,CWnd类是重要的MFC类,所有窗口类都直接或间接的继承于它,例如视类CView、工具栏类CToolBar、对话框类CDialog、按钮类CButton及编辑框类CEdit等。

本程序的CExampleDlg继承了CDialog、而CDialog又继承了CWnd,故可以在程序中使用函数UpdateData。

以参数TRUE来调用函数UpdateData()的作用是更新所有与对话框控件相关联的变量值;而以参数FALSE调用此函数则更新与变量相关的控件的显示状态,使之与变量一致。即以TRUE和FALSE为参数分别实现空间关联变量的“里传”和“外传”,默认参数为TRUE。

各关联变量的初值在函数CExampleDlg::CExampleDlg(本程序主对话框类CExampleDlg的构造函数)中初始化,需要在此修改某些变量的初值。如下代码:

CExampleDlg::CExampleDlg(CWnd* pParent /*=NULL*/)

       : CDialog(CExampleDlg::IDD, pParent)

{

       //{{AFX_DATA_INIT(CExampleDlg)

       m_fValue1 = 0.0;

       m_fValue2 = 0.0;

       m_fResult = 0.0;

       m_bAtOnce = FALSE;

       m_dOpr = 0;

       m_strOpr = _T("+");

       //}}AFX_DATA_INIT

       // Note that LoadIcon does not require a subsequent DestroyIcon in Win32

       m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

}

  

这里m_dOpr初值由-1改为0,-1表示没有单选按钮被选中,n表示第n-1个单选按钮被选中;把m_strOpr初值变为“+”,以便在程序开始时显示“+”号而不是别的运算符。

 

第7步:运行程序

程序编写完成,按[F5]观察运行结果。

程序运行的初始画面如图所示。选择“除”,计算“100÷11”,点击“计算”按钮,记得结果,如图18;若选中“立即显示运算结果”,则在修改文本框中的数字

后,程序会自动运算并将结果显示出来,如图19。

查看更多精彩图片

图18

查看更多精彩图片

图19 


原创粉丝点击