函数重载是指C++允许多个同名的函数存在,但同名的各个函数的形参必须有区别:形参的个数不同,或者形参的个数相同,但参数类型有所不同。例如:
[例Ex_OverLoad] 编程求两个或三个操作数之和
#include <iostream.h> int sum(int x, int y); int sum(int x, int y, int z); double sum(double x, double y); double sum(double x, double y, double z); void main() { cout<<sum(2, 5)<<endl;// 结果为7 cout<<sum(2, 5, 7)<<endl;// 结果为14 cout<<sum(1.2, 5.0, 7.5)<<endl;// 结果为13.7 } int sum(int x, int y) {return x+y;} int sum(int x, int y, int z) {return x+y+z;} double sum(double x, double y) {return x+y;} double sum(double x, double y, double z) {return x+y+z;}
从上面的例子可以看出:由于使用函数的重载,因而不仅方便函数名的记忆,而且更主要的是完善了同一个函数的代码功能,给调用带来了许多方便。程序中各种型式的sum函数都称为sum的“重载函数”。
需要说明的是:
(1) 重载函数必须具有不同的参数个数或不同的参数类型,若只有返回值的类型不同是不行的。
(2) 当函数的重载带有默认参数时,应该注意避免二义性。例如:
int fun(int a, int b = 0);
int fun(int a);
是错误的。因为如果有函数调用fun(2)时,编译器无法准确地确定应调用哪个函数。
一个结构体是由多种类型的数据(变量)组成的整体。组成结构的各个分量称为结构体的数据成员(简称为“成员”,或称为“成员变量”)。结构体是C++提供的构造复杂数据类型的手段之一。
1. 定义结构体
结构体定义的格式为:
struct [结构体名] { <成员定义1>; <成员定义2>; ... <成员定义n>; } [结构变量名表];
(1) 在定义结构体时,不要忘记最后一个花括号的结尾后面的分号“;”。
(2) 结构体的成员变量类型既可以是基本数据类型,也可以是其他合法的类型。
相同类型的成员变量也可用一行语句来定义,但定义的变量之间要用逗号隔开。
2. 结构体变量的初始化
结构体变量的初始化的一般形式是在变量后面加上:
= {<初值列表>};
例如:
struct POINT { int x; int y; } spot = { 20, 40 }; // 依次使spot中的x为20, y为40
(1) 当一个结构体变量定义之后,就可引用这个变量。使用时,遵循下列规则:
只能引用结构体变量中的成员变量,并使用下列格式:
<结构体变量名>.<成员变量名>
C++中有两个专门用于指针的运算符:
&(取地址运算符)、*(取值运算符)
运算符“&”只能对变量操作,作用是取该变量的地址。运算符“*”用是取指针或地址所指内存单元中存储的内容。例如:
int a = 3; //整型变量,初值为3 int *p = &a; //指向整型变量的指针,其值等于a的地址 int b = *p; //将指针所指的地址中的内容赋值给b,值为3。
上述赋值是在指针变量定义时进行的;当然,也可以在程序中进行赋值。例如:
int a = 3; // 整型变量,初值为3 int *pi; // 指向整型变量的指针 pi = p; // 将指针p的地址赋给指针pi,使得它们都是指向a的指针, // 它等价于pi = &a; 注意在pi前没有*。
C++中提供了一个与指针密切相关的特殊数据类型——“引用”。引用是一个变量的别名,定义引用类型变量,实质上是给一个已定义的变量起一个别名,系统不会为引用类型变量分配内存空间,只是使引用类型变量与其相关联的变量使用同一个内存空间。
定义引用类型变量的一般格式为:
<数据类型> &<引用名> = <变量名>
或
<数据类型> &<引用名> ( <变量名>)
其中,变量名必须是一个已定义过的变量。例如:
int a = 3;
int &ra = a;
这样,ra就是一个引用,它是变量a的别名。所有对这个引用ra的操作,实质上就是对被引用对象a的操作。例如:
ra = ra +2;
实质上是a加2,a的结果为5。但是如果给引用赋一个新值,结果会怎样的呢?
在传统的结构化程序设计方法中,数据和处理数据的程序是分离的。当对某段程序进行修改或删除时,整个程序中所有与其相关的部分都要进行相应的修改,从而程序代码的维护比较困难。为了避免这种情况的发生,C++引用了面向对象的设计方法,它是将数据及处理数据的相应函数“封装”到一个“类”中,类的实例称为“对象”。在一个对象内,只有属于该对象的函数才可以存取该对象的数据。这样,其他函数就不会无意中破坏它的内容,从而达到保护和隐藏数据的效果。
类的定义一般地分为声明部分和实现部分。声明部分是用来声明该类中的成员,
包含数据成员(或称“成员变量”)的声明和成员函数的声明。成员函数是用来对数据成员进行操作的,又称为“方法”。实现部分是用来对成员函数的定义。概括说来,声明部分将告诉使用者“干什么”,而实现部分是告诉使用者“怎么干”。
C++中定义类的一般格式如下:
class <类名> { private: [<私有数据和函数>] public: [<公有数据和函数>] }; <各个成员函数的实现>
其中,class是定义类的关键字,class的后面是用户定义的类名,通常用大写的C字母开始的标识符作为类名,C用来表示类(Class),以与对象、函数及其他数据类型相区别。类中的数据和函数是类的成员,分别称为数据成员和成员函数。
一个类定义后,就可以定义该类的对象,如下面的格式:
<类名> <对象名表>
其中,类名是用户已定义过的类的标识符,对象名可以有一个或多个,多个时要用逗号分隔。被定义的对象既可以是一个普通对象,也可以是一个数组对象或指针对象。例如:
CMeter myMeter, *Meter, Meters[2];
这时,myMeter是类CMeter的一个普通对象,Meter和Meters分别是该类的一个指针对象和对象数组。
一个对象的成员就是该对象的类所定义的数据成员(成员变量)和成员函数。访问对象的成员变量和成员函数和访问变量和函数的方法是一样的,只不过要在成员前面加上对象名和成员运算符“.”,其表示方式如下:
<对象名>.<成员变量>
<对象名>.<成员函数>(<参数表>)
1. 构造函数
前面已提及,在类的定义中是不能对数据成员进行初始化的。为了能给数据成员自动设置某些初始值,这时就要使用类的特殊成员函数——构造函数。构造函数的最大特点是在对象建立时它会被自动执行,因此用于变量、对象的初始化代码一般放在构造函数中。
C++规定:构造函数必须与相应的类同名,它可以带参数,也可以不带参数,与一般的成员函数定义相同,也可以重载。例如:
class CMeter { public: CMeter(intnPos)//带参数的构造函数 {m_nPos=nPos;} ... }
这样若有:
CMeter oMeter(10), oTick(20);
则会自动调用构造函数CMeter(int nPos ),从而使得对象oMeter中的私有成员m_nPos的值为10;使得对象oTick中的私有成员m_nPos的值为20。
2. 析构函数
与构造函数相对应的是析构函数。析构函数是另一个特殊的C++成员函数,它只是在类名称前面加上一个“~”符号。每一个类只有一个析构函数,没有任何参数,也不返回任何值。例如:
classCMeter { public: ... ~CMeter(){}//析构函数 ... }
析构函数只有在下列两种情况下才会被自动调用:
(1) 当对象定义在一个函数体中,该函数调用结束后,析构函数被自动调用。
(2) 用new为对象分配动态内存,当使用delete释放对象时,析构函数被自动调用。
4. 构造函数的重载
构造函数可以被重载,C++会根据对象定义中的参数选择合适的构造函数。例如:
[例Ex_ConOverLoad] 构造函数的重载
#include <iostream.h> class CDate { public: CDate(); CDate(int day); CDate(int month, int day); CDate(int year, int month, int day); // 其他公共成员 private: int nYear, nMonth, nDay; }; CDate::CDate() { nMonth = 7; nDay = 30; nYear = 2002; cout<<nYear<<"-"<<nMonth<<"-"<<nDay<<endl; } CDate::CDate(int day) { nMonth = 7; nDay = day; nYear = 2002; cout<<nYear<<"-"<<nMonth<<"-"<<nDay<<endl; } CDate::CDate(int month, int day) { nMonth = month; nDay = day; nYear = 2002; cout<<nYear<<"-"<<nMonth<<"-"<<nDay<<endl; } CDate::CDate(int year, int month, int day) { nYear = year; nMonth = month; nDay = day; cout<<nYear<<"-"<<nMonth<<"-"<<nDay<<endl; } void main() { CDate day1; CDate day2(28); CDate day3(8, 1); CDate day4(2003, 3, 10); }
编制一个功能强大和易操作的Windows应用程序所需要的代码肯定会比一般的C++程序要多得多,但并不是所有的代码都需要自己从头开始编写,因为Visual C++不仅提供了常用的Windows应用程序的基本框架,而且可以在框架程序中直接调用Win32 API(Application Programming
Interface, 应用程序接口)函数。这样,用户仅需要在相应的框架位置中添加自己的代码或修改部分代码就可实现Windows应用程序的许多功能。
窗口过程函数WndProc用来接收和处理各种不同的消息,而主函数WinMain通常要完成以下几步工作:
(1) 调用API函数RegisterClass注册应用程序的窗口类。
(2) 调用相关API函数创建和显示窗口,并进行其它必要的初始化处理。其中,函数CreateWindow用来创建已注册窗口类的窗口。Windows每一个窗口都有一些基本属性,如窗口标题、窗口位置和大小、应用程序图标、鼠标指针、菜单和背景颜色等。窗口类就是充当这些属性的模板。
(3) 创建和启动应用程序的消息循环。Windows应用程序接受各种不同的消息,包括键盘消息、鼠标以及窗口产生的各种消息。Windows系统首先将消息放入消息队列中,应用程序的消息循环就是从应用程序的消息队列中检取消息,并将消息发送相应的窗口过程函数中作进一步处理。API函数GetMessage 和DispatchMessage就是起到这样的作用。
(4) 如果接收到WM_QUIT消息,则退出应用程序。
一个完整的Windows应用程序除了WinMain函数外,还包含用于处理用户动作和窗口消息的窗口函数。这不同于一个C++的控制台应用程序,可以将整个程序包含在main函数中。事实上,它们的区别还远不止这些,不久还会发现一个Windows应用程序还常常具有这样的一些特性:
消息驱动机制
图形设备接口(GDI)
基于资源的程序设计
动态链接库
进程和线程
1. 消息驱动机制
在Windows操作环境中,无论是系统产生的动作或是用户运行应用程序产生的动作,都称为事件(Events)产生的消息(Message)。例如,在Windows 桌面(传统风格)上,双击应用程序的快捷图标,系统就会执行该应用程序。在Windows的应用程序中,也是通过接收消息、分发消息、处理消息来和用户进行交互的。
这种消息驱动的机制是Windows编程的最大特点。需要注意的是,许多Windows消息都经过了严格的定义,并且适用于所有的应用程序。例如,当用户按下鼠标的左键时系统就会发送WM_LBUTTONDOWN消息,而当用户敲了一个字符键时系统就会发送WM_CHAR消息,若用户进行菜单选择或工具按钮单击等操作时,系统又会相应地发送WM_COMMAND消息给相应的窗口等等。
2. 图形设备接口(GDI)
在传统的DOS环境中,想要在打印机上打印一幅图形是一件非常复杂的事情,因为用户必须根据打印机类型和指令规则向打印机输送数据。而Windows则提供了一个抽象的接口,称为图形设备接口(Graphical Device Interface,简称GDI),使得用户直接利用系统的GDI函数就能方便实现输入或输出,而不必关心与系统
相连的外部设备的类型。
3. 基于资源的程序设计
Windows应用程序常常包含众多图形元素,例如光标、菜单、工具栏、位图、对话框等,在Windows环境下,每一个这样的元素都作为一种可以装入应用程序的资源来存放。这些资源就像C++程序中的常量一样,可以被编辑、修改,也可以被其他应用程序所共享。Visual C++ 6.0中就提供这样的编辑器,可“所见即所得”地对这些不同类型的资源进行设计、编辑等。
4. 动态链接库
动态链接库提供了一些特定结构的函数,能被应用程序在运行过程中装入和连接,且多个程序可以共享同一个动态链接库,这样就可以大大节省内存和磁盘空间。从编程角度来说,动态链接库可以提高程序模块的灵活性,因为它本身是可以单独设计、编译和调试的。
Windows提供了应用程序可利用的丰富的函数调用,大多数用于实现其用户界面和在显示器上显示的文本和图形,都是通过动态链接库来实现的。这些动态链接库是一些具有.DLL扩展名或者有时是.EXE扩展名的文件。
在Windows操作系统中,最主要的DLL有KERNEL32.DLL、GDI32.DLL和USER32.DLL三个模块。其中,KERNEL32用来处理存储器低层功能、任务和资源管理等Windows核心服务; GDI32用来提供图形设备接口,管理用户界面和图形绘制,包括Windows元文件、位图、设备描述表和字体等;而USER32负责窗口的管理,包括消息、菜单、光标、计时器以及其它与控制窗口显示相关的一些功能。
5 . 进程和线程
在32位Windows多任务操作系统中,采用了进程和线程的管理模式。进程是装入内存中正在执行的应用程序。进程包括私有的虚拟地址空间、代码、数据及其它操作系统资源,如文件、管道以及对该进程可见的同步对象等。进程包括了一个或多个在进程上下文内运行的线程。线程是操作系统分配CPU时间的基本实体。线程可以执行应用程序代码的任何部分,包括当前正在被其它线程执行的那些部分。同一进程的所有线程共享同样的虚拟地址空间、全局变量和操作系统资源。在一个应用程序中,可以包括一个或多个进程,每个进程由一个或多个线程构成。
可以看到ClassWizard对话框包含了5个标签页面,它们各自含义如下:
● Message Maps(消息映射):用来添加、删除和编程处理消息的成员函数。
● Member Variables(成员变量):添加或删除与控件相关联的成员变量(或称数据成员),以便与控件进行数据交换。这些控件所在的类一般是从CDialog、CPropertyPage、CRecordView或CDaoRecordView中派生的类。
● Automation(自动化):为支持Automation的类(如ActiveX控件类)添加属性和方法。
● ActiveX Events(ActiveX事件):为ActiveX控件类添加触发事件的支持。
● Class Info(类信息):有关项目中类的其他信息。
一般来说,MFC ClassWizard对话框最前两项是用户最关心的,也是最经常使用的,因为几乎所有的代码编写都要利用这两个标签项。由于Member Variables功能以后还会详细讨论,因此这里仅讨论Message Maps(消息映射)与类的添加和删除方法。
1. 消息分类
Windows应用程序中的消息主要有三种类型。
(1)窗口消息(Windows message)。这类消息主要是指由WM_开头的消息(WM_ COMMAND除外),一般由窗口类和视图类对象来处理。窗口消息往往带有参数,以标志处理消息的方法。
(2)控件的通知消息(Control notifications)。当控件的状态发生改变(例如用户在控件中进行输入)时,控件就会向其父窗口发送WM_COMMAND通知消息。应用程序框架处理控件消息的方法和窗口消息相同,但按钮的BN_CLICKED通知消息除外,它的处理方法与命令消息相同。
(3)命令消息(Command message)。命令消息主要包括由用户交互对象(菜单、工具条的按钮、快捷键等)发送的WM_COMMAND通知消息。命令消息的处理方式与其他两种消息不同,它能够被多种对象接收、处理,这些对象包括文档类、文档模板类、应用程序本身以及窗口和视类等;而窗口消息和控件的通知消息是由窗口对象接收并处理的,这里的窗口对象是指从CWnd中派生的类的对象,它包括CFrameWnd、CMDIFrameWnd、CMDIChildWnd、CView、CDialog以及从这些类派生的对象等。
3. 消息映射代码查看CEx_SDIHelloView程序代码,可以发现:ClassWizard为WM_LBUTTOMDOWN的消息映射作了以下三个方面内容的安排:
(1) 在头文件Ex_SDIHelloView.h中声明消息处理函数OnLButtonDown:protected:
//{{AFX_MSG(CEx_SDIHelloView)
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
代码中的//{{AFX_MSG(CEx_SDIHelloView)和//}}AFX_MSG之间的部分是ClassWizard定义的专门用作消息映射函数声明的标记。表示该程序块中的消息映射声明是由ClassWizard来自动管理的,用户一般不需要去更改。需要说明的是,凡//{{和//}}之间的程序代码块均由ClassWizard自动管理。
(2) 在Ex_SDIHelloView.cpp源文件前面的消息映射入口处,添加了相应的映射宏:
BEGIN_MESSAGE_MAP(CEx_SDIHelloView, CView) // 消息映射开始
//{{AFX_MSG_MAP(CEx_SDIHelloView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
…
END_MESSAGE_MAP() // 消息映射结束
(3) 在Ex_SDIHelloView.cpp文件中写入一个空的消息处理函数的模板,以便用户填入具体代码,如下面的框架:
void CEx_SDIHelloView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default? CView::OnLButtonDown(nFlags, point); }
事实上,根据ClassWizard产生的上述消息映射过程,用户可以自己手动添加一些MFC ClassWizard不支持的消息映射函数,以完成特定的功能。例如,Ex_HelloMFC示例就是按照上述过程添加消息映射的。
对话框是Windows应用程序中最重要的用户界面元素之一,是与用户交互的重要手段。在程序运行过程中,对话框可用于捕捉用户的输入信息或数据。对话框是一个特殊类型的窗口,任何对窗口进行的操作(如移动、最大化、最小化等)也可在对话框中实施。一般来说,在对话框中通过各种控件(如按钮、编辑框、列表框、组合框等)来和用户进行交互,控件是在系统内部定义的用于和用户交互的基本单元。
4.1 对话框的使用
在Visual C++ 6.0应用程序中,使用一个对话框的一般过程是:①添加对话框资源;②设置对话框的属性;③添加和布局控件;④创建对话框类;⑤添加对话框代码;⑥在程序中调用对话框。
可以看出,一个单文档应用程序所使用的资源可分为下列几类:
(1) 快捷键列表(Accelerator)。一系列组合键的集合,被应用程序用来引发一个动作。该列表一般与菜单命令相关联,用来代替鼠标操作。
(2) 对话框(Dialog)。含有按钮、列表框、编辑框等各种控件的窗口。
(3) 图标(Icon)。代表应用程序显示在Windows桌面上的位图,它同时有32x32像素和16x16像素两种规格。
(4) 菜单(Menu)。用户通过菜单可以完成应用程序的大部分操作。
(5) 字串表(String Table)。应用程序使用的全局字符串或其他标识符。
(6) 工具栏按钮(Toolbar)。工具栏外观是以一系列具有相同尺寸的位图组成的,它通常与一些菜单命令相对应,用以提高用户的工作效率。
(7) 版本信息(Version)。包含应用程序的版本、用户注册码等相关信息。
除了上述常用资源类别外,Visual C++ 6.0应用程序中还可有鼠标指针、HTML等,也可以自己添加新的资源类别。由于OnInitDialog函数在对话框初始化时被调用,因此将对话框中的一些初始化
代码都添加在此函数中。代码中,Create用来创建一个按钮控件,该函数第一个参数用来指定该按钮的标题,第二个参数用来指定控件的风格,第三个参数用来指定它在父窗口中的位置和大小,第四个参数用来指定父窗口指针,最后一个参数是指定该控件的标识值。
添加的控件关联变量
ClassWizard对上述操作作了以下三方面的修改。
● 在Ex_DlgCtrlsDlg.h文件中,添加控件关联变量的声明,代码如下面的加粗部分:
//DialogData //{{AFX_DATA(CEx_DlgCtrlsDlg) enum{IDD=IDD_EX_DLGCTRLS_DIALOG};//枚举类型 CButton m_RelBtn; CString m_strEdit; //}}AFX_DATA
● 在Ex_DlgCtrlsDlg.cpp文件中的CEx_DlgCtrlsDlg构造函数实现代码处,添加了控件变量的一些初始代码:
CEx_DlgCtrlsDlg::CEx_DlgCtrlsDlg(CWnd* pParent /*=NULL*/):CDialog(CEx_DlgCtrlsDlg::IDD, pParent) { //{{AFX_DATA_INIT(CEx_DlgCtrlsDlg) m_strEdit = _T(""); //}}AFX_DATA_INIT … }
● 在Ex_DlgCtrlsDlg.cpp文件中的DoDataExchange函数体内,添加了控件的DDX/DDV代码,它们都是一些以DDV_或DDX_开头的函数调用。
void CEx_DlgCtrlsDlg::DoDataExchange(CDataExchange* pDX){ CDialog::DoDataExchange(pDX); // 调用此函数作为DDX的开始 //{{AFX_DATA_MAP(CEx_DlgCtrlsDlg) DDX_Control(pDX, IDC_BUTTON1, m_RelBtn); DDX_Text(pDX, IDC_EDIT1, m_strEdit); // 将IDC_EDIT1与m_strEdit进行数据交换 DDV_MaxChars(pDX, m_strEdit, 20); // 校验m_strEdit的最大字符个数不超过20 //}}AFX_DATA_MAP }
(5) 当为一个控件定义一个关联的数据变量后,就可以使用CWnd::UpdateData函数实现控件数据的输入和读取。例如,将CEx_DlgCtrlsDlg::OnButton1修改成下列代码:
void CEx_DlgCtrlsDlg::OnButton1() { UpdateData(); // 默认参数值是TRUE m_RelBtn.SetWindowText(m_strEdit); }
代码中,UpdateData函数只有一个为TRUE或FALSE的参数。当调用UpdateData(FALSE)时,数据由控件相关联的成员变量向控件传输,当调用UpdateData(TRUE)或不带参数的UpdateData时,数据从控件向相关联的成员变量复制。
(2) 编辑框的基本操作。由于编辑框的形式多样,用途各异,因此下面针对编辑框的不同用途,分别介绍一些常用操作,以实现一些基本功能。
① 口令设置。口令设置在编辑框中不同于一般的文本编辑框,用户输入的每个字符都被一个特殊的字符代替显示,这个特殊的字符称为口令字符。默认的口令字符是“*”,应用程序可以用成员函数CEdit::SetPasswordChar 来定义自己的口令字符,其函数原型如下: void SetPasswordChar( TCHAR ch ); 其中,参数ch表示设定的口令字符;当ch = 0时,编辑框内将显示实际字符。
② 选择文本。当在编辑框中编辑文本时,往往需要选定文本作为整体进行各种编辑操作。用户可以用鼠标或键盘来选择文本。用鼠标来选择文本的操作方法是:在要选择的文本的一端按下鼠标左键并拖动鼠标,到另一端释放鼠标键。用键盘来选择文本的方法是:在按光标方向移动键的同时,按住Shift键。
③ 设置编辑框的页面边距。设置编辑框的页面边距可以使文本在编辑框显示更具满意效果,这在多行编辑框中尤为重要,应用程序可通过调用成员函数CEdit::SetMargins来实现,这个函数的原型如下:
void SetMargins( UINT nLeft, UINT nRight );
其中,参数nLeft和nRight分别用来指定左、右边距的像素大小。
头文件位置: afxwin.h使用CEditView可以通过SetMargins()来设定左右两条空出来的边,而在CRichEditView中,虽然同样有着SetMargins函数,但是这个函数设定的只是打印相关的边距。为了达到设定边距的功能,您可以使用CRichEditView类的SetParaFormat函数,该函数原型如下:
BOOL SetParaFormat(
PARAFORMAT2& pf
);
④ 剪帖板操作。编辑框通过CEdit类的Copy、Paste和Cut成员函数来实现文本的复制、粘贴、剪切的操作,并还自动支持键盘快捷操作,其对应的快捷健分别为Ctrl+C、Ctrl+V和Ctrl+X。若应用程序调用CEdit::Undo函数时,则还可撤消当前的操作,再调用一次该函数,则恢复刚才的操作。例如下面的代码:
if (m_Edit.CanUndo()) m_Edit.Undo();
⑤ 获取多行编辑框文本。获取多行编辑框控件的文本可以有两种方法:一种是使用DDX/DDV,当将编辑框控件所关联的变量类型选定为CString(字符串类)后,则不管多行编辑框的文本有多少都可用此变量来保存,从而能简单地解决多行文本的读取。但这种方法不能单独获得多行编辑框中的某一行文本。
另一种方法是使用编辑框CEdit类的相关成员函数来获取文本。例如,下面的代码将显示编辑框中第二行的文本内容:
char str[100]; if (m_Edit.GetLineCount()>=2) // 判断多行编辑框的文本是否有两行以上 { int nChars; nChars = m_Edit.LineLength(m_Edit.LineIndex(1));// 获取第二行文本的字符个数 // 0表示第一行,1表示第二行,依次类推。LineIndex用于将文本行转换成 // 能被LineLength识别的索引 m_Edit.GetLine(1,str,nChars); // 获取第二行文本 str[nChars] = '\0'; MessageBox(str); }
代码中,由于调用GetLine获得某行文本内容时,并不能自动在文本后添加文本的结束符‘\0’,因此需要首先获得某行文本的字符数,然后设置文本的结束符。
列表框的风格和消息
按性质来分,列表框有单选、多选、扩展多选以及非选四种类型作为用户输入的接口,前面的列表框和编辑框各有其优点。例如,列表框中可列出用户所需的各种可能的选项,这样一来,用户不需要记住这些项,只需进行选择操作即可,但用户却不能输入列表框中列表项之外的内容。虽然编辑框能够允许用户输入内容,但却没有列表框的选择操作。于是很自然地产生这样的想法:
把常用的项列在列表框中以供选择,而同时提供编辑框,允许用户输入列表框中所没有的新项。组合框正是这样的一种控件,它结合列表框和编辑框的特点,取二者之长,从而完成较为复杂的输入功能。
按照组合框的主要风格特征,可把组合框分为3类:简单组合框、下拉式组合框、下拉式列表框。
为了使Windows程序更容易操作,菜单的显示都遵循下列一些规则:
●若单击某菜单项后,将弹出一个对话框,那么在该菜单项文本后有“…”。
●若某项菜单有子菜单,那么在该菜单项文本后有“4”。
●若菜单项需要助记符,则用括号将带下划线的字母括起来。助记符与Alt构成一个组合键,当按住“Alt”键不放,再敲击该字母时,对应的菜单项就会被选中。
●若某项菜单需要快捷键的支持,则一般将其列在相应菜单项文本之后。所谓“快捷键”是一个组合键,如Ctrl+N,使用时是先按下“Ctrl”健不放,然后再按“N”键。任何时候按下快捷键,相应的菜单命令都会被执行。
添加工具栏
(1) 在项目工作区切的ResourceView页面中,展开Toolbar(工具栏)资源,用鼠标单击IDR_MAINFRAME不松开,然后按下Ctrl键,移动鼠标将IDR_MAINFRAME拖到Toolbar资源名称上,这样就复制了工具栏默认资源IDR_MAINFRAME,复制后的资源标识系统自动设为IDR_MAINFRAME1。
(2) 右击工具栏资源IDR_MAINFRAME1,从弹出的快捷菜单中选择Properties命令,如图5.22所示,将ID设为IDR_TOOLBAR1。
(3) 双击IDR_TOOLBAR1,打开工具栏资源,按图5.23删除不要的工具按钮。
(4)在CMainFrame类中添加一个成员变量m_wndTestBar,变量类型为CToolBar。CToolBar类封装了工具栏的操作。
文档窗口对于单文档应用程序来说,它和主框架窗口是一致的,即主框架窗口就是文档窗口;而对于多文档应用程序,文档窗口是主框架窗口的子窗口.
用户处理的数据往往需要存盘作永久备份。将文档类中的数据成员变量的值保存在磁盘文件中,或者将存储的文档文件中的数据读取到相应的成员变量中。这个过程称为序列化(Serialize)。