15单元控件 第15单元控件 本单元教学目标 介绍各种常用控件的使用方法及基于对话框的应用程序 学习要求 掌握常用控件的使用方法以及基于对话框的应用程序开发。 授课內容 对话框与控件是密不可分的。 Windows提供了一批基本控件,如静态控件( Static Text)、 编辑控件( Edit box)、组框、等,可解决大部分用户输入界面设计的需求。另外,使用sual C艹编程还可使用一批通用控件,包括动画控件( Animate)、标题控件( Header)、复合文 本编辑控件( Rich edit)、标签控件(Tab)和树状列表控件( Tree List)等,可大大提高应 用程序界面的表现力 15.1常用控件 控件( Control)是 Windows提供的独立小部件,在对话框与用户的交互过程担任主要 角色,如显示文本、图片和图标、命令按钮、编辑文字或数据和滚动条等 控件的外观和功能是由其属性( Property)决定的。在编辑对话框模板资源时,对准某 个控件按下鼠标右键可调出其属性设置对话框。不同的控件属性也不完全相同。属性对话框 中有若干选项卡,如 General选项卡、 Styles选项卡和 Extend Styles选项卡等,控件的属性 就分布在各选项卡上(参看147:“对话框模板资源的编辑” 控件看似简单,但实际上也是一个窗口,对应一个CWnd派生类的对象。例如,编辑 控件对应 Cedit类的对象,静态文本控件对应 CStatic类的对象。每个控件均有自己的标识 符,在程序中可使用对话框类的成员函数 GetDlgltem()取得指向具体控件对象的指针,然 后对其进行编程。本节介绍几个常用的控件的使用方法。 1.静态文本( Static Text)控件:用于显示字符串,不接受输入信息。多用于显示其他 控件的标题。使用静态文本控件一般均可使用缺省属性 2.图片( Picture)控件,用于显示位图、图标、方框等,不接受输入信息。在图片控 件的属性中,最重要的是其Type(在控件属性对话框的 General选项卡中设置),可选类型 有 Frame(矩形框)、 Rectangle(矩形块)、lcon(图标)和 Bitmap(位图)等。如果类型
第 15 单元 控件 303 第 15 单元 控件 本单元教学目标 介绍各种常用控件的使用方法及基于对话框的应用程序。 学习要求 掌握常用控件的使用方法以及基于对话框的应用程序开发。 授课内容 对话框与控件是密不可分的。Windows 提供了一批基本控件,如静态控件(Static Text)、 编辑控件(Edit Box)、组框、等,可解决大部分用户输入界面设计的需求。另外,使用 Visual C++编程还可使用一批通用控件,包括动画控件(Animate)、标题控件(Header)、复合文 本编辑控件(Rich Edit)、标签控件(Tab)和树状列表控件(Tree List)等,可大大提高应 用程序界面的表现力。 15.1 常用控件 控件(Control)是 Windows 提供的独立小部件,在对话框与用户的交互过程担任主要 角色,如显示文本、图片和图标、命令按钮、编辑文字或数据和滚动条等。 控件的外观和功能是由其属性(Property)决定的。在编辑对话框模板资源时,对准某 个控件按下鼠标右键可调出其属性设置对话框。不同的控件属性也不完全相同。属性对话框 中有若干选项卡,如 General 选项卡、Styles 选项卡和 Extend Styles 选项卡等,控件的属性 就分布在各选项卡上(参看 14.7:“对话框模板资源的编辑”)。 控件看似简单,但实际上也是一个窗口,对应一个 CWnd 派生类的对象。例如,编辑 控件对应 Cedit 类的对象,静态文本控件对应 CStatic 类的对象。每个控件均有自己的标识 符,在程序中可使用对话框类的成员函数 GetDlgItem()取得指向具体控件对象的指针,然 后对其进行编程。本节介绍几个常用的控件的使用方法。 1.静态文本(Static Text)控件:用于显示字符串,不接受输入信息。多用于显示其他 控件的标题。使用静态文本控件一般均可使用缺省属性。 2.图片(Picture)控件,用于显示位图、图标、方框等,不接受输入信息。在图片控 件的属性中,最重要的是其 Type(在控件属性对话框的 General 选项卡中设置),可选类型 有 Frame(矩形框)、Rectangle(矩形块)、Icon(图标)和 Bitmap(位图)等。如果类型
15单元控件 选择 Frame和 Rectangle,可通过olor选项选择其颜色;如果选择lcon和 Bitmap,可通过 选项选择相应的资源 3.组框( Group Box)控件:显示一个文本字符串和一个方框,通常用于组合一组相关 控件。 以上三个控件均对应 CStatic类型的对象。应该说明的是,如果无需对静态控件编程 则也不要求其标识符唯一,通常可选用对话框模板编辑器自动提供的缺省标识符 CIDC STATIC 4.编辑( Edit Bαx)控件。编辑控件是最常用的控件,可用于单行或多行文本编辑 其功能十分强大,相当于一个小型文本编辑器。编辑控件亦可用来输入数值数据和日期、时 间数据。主要属性有 Align Text(文本对齐方式)、 Multiline(多行编辑)、 AutohScroll(输 入到窗口右边界后自动横滚)等(均在控件属性对话框的 Styles选项卡中设置)。编辑控件 对应CEdt类的对象 5.按钮( Button)控件,用于响应用户的鼠标按键等操作,触发相应的事件。编程时 按钮的处理与菜单选项类似,可为其添加命令响应函数(通常借助 ClassWizard完成) 6.检査框( Check box)控件,用作选择标记,有选中、不选中和不确定等状态。 7.单选按钮( Radio button)控件,用来作多项选择。单选按钮总是成组使用的。在 组单选按钮中,第一个按钮最为重要,其ID可用于在对话框类中建立对应的数据成员( 定要设置其 Group属性为选中)。按钮、检査框和单选按钮三种控件均对应 CButton类的对 象 8.列表框( List box)控件,显示一个文字列表,用户可从表中选择一项或多项。主要 属性为 Selection(位于 Styles选项卡中)。可选择“ Single”(单选)、“ Multiple”(多选) 等。属性Sort表示是否将列表框的内容排序。列表框中的文字列表需在编程时确定,通常 是在对话框类的 InitDialog()成员函数中给出。列表框控件对应 CListBox类对象。 9.组合框( Combo box)是编辑控件和列表框的组合,可分为简易式( Simple)、下 拉式( Dropdown)和下拉列表式( Drop List)。组合框中列表的内容可在设置时用Data选 项卡输入。注意输入各列表项时要使用Ctrl+ Enter开始新的一项。组合框控件对应 COmbo 类的对象。 为了在程序中对控件进行査询和控制,可以利用Cwnd类提供的一组管理对话框控件 的成员函数。这类函数很多,以下仅举几例: 对话框控件管理函数说明 GetChecked Radio Button()返回指定单选按钮组中被选择的单选按钮的ID: GetDlgltem ( 返回一个指向一给定控件的指针 GetDlgltem Text ( 获得在一个控件内显示的正文; SetDlgltem Text ( 设置一个控件显示的正文 例15-1为某公司设计一个人事管理系统,其基本功能为输入、编辑、查看和保存公 司的人事档案。职工人事档案包括姓名、性别、出生日期、婚姻状况、所在部门、职务和工
第 15 单元 控件 304 选择 Frame 和 Rectangle,可通过 Color 选项选择其颜色;如果选择 Icon 和 Bitmap,可通过 Image 选项选择相应的资源。 3.组框(Group Box)控件:显示一个文本字符串和一个方框,通常用于组合一组相关 控件。 以上三个控件均对应 CStatic 类型的对象。应该说明的是,如果无需对静态控件编程, 则也不要求其标识符唯一,通常可选用对话框模板编辑器自动提供的缺省标识符 (IDC_STATIC)。 4.编辑(Edit Box)控件。编辑控件是最常用的控件,可用于单行或多行文本编辑, 其功能十分强大,相当于一个小型文本编辑器。编辑控件亦可用来输入数值数据和日期、时 间数据。主要属性有 Align Text(文本对齐方式)、Multiline(多行编辑)、AutoHScroll(输 入到窗口右边界后自动横滚)等(均在控件属性对话框的 Styles 选项卡中设置)。编辑控件 对应 CEdit 类的对象。 5.按钮(Button)控件,用于响应用户的鼠标按键等操作,触发相应的事件。编程时 按钮的处理与菜单选项类似,可为其添加命令响应函数(通常借助 ClassWizard 完成)。 6.检查框(Check Box)控件,用作选择标记,有选中、不选中和不确定等状态。 7.单选按钮(Radio Button)控件,用来作多项选择。单选按钮总是成组使用的。在一 组单选按钮中,第一个按钮最为重要,其 ID 可用于在对话框类中建立对应的数据成员(一 定要设置其 Group 属性为选中)。按钮、检查框和单选按钮三种控件均对应 CButton 类的对 象。 8.列表框(List Box)控件,显示一个文字列表,用户可从表中选择一项或多项。主要 属性为 Selection(位于 Styles 选项卡中)。可选择“Single”(单选)、“Multiple”(多选) 等。属性 Sort 表示是否将列表框的内容排序。列表框中的文字列表需在编程时确定,通常 是在对话框类的 InitDialog()成员函数中给出。列表框控件对应 CListBox 类对象。 9.组合框(Combo Box)是编辑控件和列表框的组合,可分为简易式(Simple)、下 拉式(Dropdown)和下拉列表式(Drop List)。组合框中列表的内容可在设置时用 Data 选 项卡输入。注意输入各列表项时要使用 Ctrl+Enter 开始新的一项。组合框控件对应 CCombo 类的对象。 为了在程序中对控件进行查询和控制,可以利用 CWnd 类提供的一组管理对话框控件 的成员函数。这类函数很多,以下仅举几例: 对话框控件管理函数 说明 GetCheckedRadioButton() 返回指定单选按钮组中被选择的单选按钮的 ID; GetDlgItem() 返回一个指向一给定控件的指针; GetDlgItemText() 获得在一个控件内显示的正文; SetDlgItemText() 设置一个控件显示的正文。 [例 15-1] 为某公司设计一个人事管理系统,其基本功能为输入、编辑、查看和保存公 司的人事档案。职工人事档案包括姓名、性别、出生日期、婚姻状况、所在部门、职务和工 资
15单元控件 说明:为了管理和保存档案,选用SDI(单文档/视图界面)程序结构。首先用 AppWizard生成一个名为EMP的SD程序框架,在第4步中时按下“ Advanced.”按钮调 出 Advanced Options对话框,在 Document Template Strings选项卡中将 File extension(文件 名后缀)项设置为“dat”,在 Window Styles选项卡中设置 Maximized检查框为“选中”状 态。其他选项均可用缺省设置。 使用 Developer Studio菜单的 Insert/Resource…选项调出 Insert Source对话框,为项目添 加一个对话框模板资源,并将其标识符改为 IDD EMPLOYEE。适当调整其大小,并在其上 添加如下控件,使其看上去与图15-1类似 静态文本控件:姓名、出生日期、部门、职务、工资 图片控件:类型为lcon,使用项目自带的 IDR MAINFRAME图标,也可自己为项目添 加一个图标资源并编辑成自己喜欢的样式 编辑控件三个,其ID分别改为 IDC NAME、 IDC BIRTHDATE和 IDC SALARY; 单选按钮两个,其ID和 Caption分别改为 IDC MALE,“男”和 IDC FEMALE,“女” 为 IDC MALE设置属性 Group; 检查框一个,其ID和 Caption分别改为 IDC MARRIED和“婚否”; 列表框一个,其ID改为 IDC DEPT,保证 Styles选项卡中的 Selection项为 Single,并 将Sort检查框设置为非选中状态 组合框一个,其D改为 IDC POSITION,并在 Style选项卡中将Type设置为 Drop List, 并将Sort检查框设置为非选中状态。然后在Data选项卡中输入各种职务的名称 总经理 副总经理 个人资料 姓名富责 部门会 部门经理 男 项目经理 业务经理 出生日期1970320职务总经理 注意使用Ctrl+ Enter键回车换行。 卩婚否 工资99 组框一个,将其 Caption改为“个人资 料”,调整其大小和位置,使之可以框住姓图15-1人事档案管理系统的输入、编辑对话框 名、性别、出生日期和婚姻状况等控件。 然后为各控件设置 Tab Order。所谓 Tab Order,是指在对话框中用Tab键选择控件的顺 序使用Tab键选择控件在鼠标发生故障,或大量键盘输入时特别有用。选择 Developer Studio 菜单的 Layout/Tab Order选项,然后按最方便的顺序用鼠标逐一点击对话框模板上的各控件 即可 设计好对话框模板后,利用 Classwizard自动建立对话框类。用Ctrl+W键可直接调出 lass wizard,也可以通过 Developer Studio菜单的 View/Classwizard.选项调出。进入 Class Wizard后,它会发现已建立的对话框模板资源,并弹出一个对话框询问是否要为该对 话框模板建立类。按下“OK”按钮,会弹出 New Class对话框,填写类名( CEmpDlg)后 按“OK”按钮即可为对话框建立一个类 利用 Classwizard为对话框类添加与各控件对应的数据成员。选择 Member variables选
第 15 单元 控件 305 说 明:为了管理和保存档案,选用 SDI(单文档/视图界面)程序结构。首先用 AppWizard 生成一个名为 EMP 的 SDI 程序框架,在第 4 步中时按下“Advanced…”按钮调 出 Advanced Options 对话框,在 Document Template Strings 选项卡中将 File extension(文件 名后缀)项设置为“dat”,在 Window Styles 选项卡中设置 Maximized 检查框为“选中”状 态。其他选项均可用缺省设置。 使用 Developer Studio 菜单的 Insert/Resource…选项调出 Insert Source 对话框,为项目添 加一个对话框模板资源,并将其标识符改为 IDD_EMPLOYEE。适当调整其大小,并在其上 添加如下控件,使其看上去与图 15-1 类似。 静态文本控件:姓名、出生日期、部门、职务、工资; 图片控件:类型为 Icon,使用项目自带的 IDR_MAINFRAME 图标,也可自己为项目添 加一个图标资源并编辑成自己喜欢的样式; 编辑控件三个,其 ID 分别改为 IDC_NAME、IDC_BIRTHDATE 和 IDC_SALARY; 单选按钮两个,其 ID 和 Caption 分别改为 IDC_MALE,“男”和 IDC_FEMALE,“女”。 为 IDC_MALE 设置属性 Group; 检查框一个,其 ID 和 Caption 分别改为 IDC_MARRIED 和“婚否”; 列表框一个,其 ID 改为 IDC_DEPT,保证 Styles 选项卡中的 Selection 项为 Single,并 将 Sort 检查框设置为非选中状态; 组合框一个,其 ID 改为 IDC_POSITION,并在 Style 选项卡中将 Type 设置为 Drop List, 并将 Sort 检查框设置为非选中状态。然后在 Data 选项卡中输入各种职务的名称: 总经理 副总经理 部门经理 项目经理 业务经理 注意使用 Ctrl+Enter 键回车换行。 组框一个,将其 Caption 改为“个人资 料”,调整其大小和位置,使之可以框住姓 名、性别、出生日期和婚姻状况等控件。 然后为各控件设置 Tab Order。所谓 Tab Order,是指在对话框中用 Tab 键选择控件的顺 序。使用Tab键选择控件在鼠标发生故障,或大量键盘输入时特别有用。选择Developer Studio 菜单的 Layout/Tab Order 选项,然后按最方便的顺序用鼠标逐一点击对话框模板上的各控件 即可。 设计好对话框模板后,利用 ClassWizard 自动建立对话框类。用 Ctrl+W 键可直接调出 ClassWizard,也可以通过 Developer Studio 菜单的 View/ClassWizard…选项调出。进入 ClassWizard 后,它会发现已建立的对话框模板资源,并弹出一个对话框询问是否要为该对 话框模板建立类。按下“OK”按钮,会弹出 New Class 对话框,填写类名(CEmpDlg)后 按“OK”按钮即可为对话框建立一个类。 利用 ClassWizard 为对话框类添加与各控件对应的数据成员。选择 Member Variables 选 图 15-1 人事档案管理系统的输入、编辑对话框
15单元控件 项卡,确保 Class Name项为新的对话框类,然后在选项卡下方的窗口中选择各控件的ID并 按下“ Add Variable”按钮为其添加对应成员变量: Control ids Variable Type Member variable name IDC BIRTHDAtE COle Date Time m bIrthdate IDC DEPT CString m strDept IDC MALE IDC MARRIED BOOL m mArried IDC NAME CString IDC POSITION CString m str Position IDC SALARY m fSalary 注意在添加成员变量对话框中的 Category项均选择 Value(值)并在 Variable type组合框中 选择相应的数据类型。注意编辑控件 IDC BIRTHDATE对应了一个 COleDate Time类的数据 成员。 COleDate Time类是用于表示一个时间时间,包括日期和时刻。 ColeDate Time类的成 员函数很多,主要有: COle DateTime( int n Year, int nMonth, int nDay, int nHour, int nMin, int nSec ) ∥根据给定值构造时间对象 static COleDateTime Get Current Time() ∥用当前系统时间填写对象 int Get Year()const ∥取对象中的年值 ∥取对象中的月值 int Get Day ()const ∥取对象中的日值 int Get Hour()const ∥取对象中的小时值 int Get Minute()const ∥取对象中的分钟值 int GetSecond ()const ∥取对象中的秒值 ∥取对象中的星球值 int Get DayofYear()const ∥取日相对上年末的天数 int SetDate Time( int n Year, int nMonth, int n Day, int nHour, int nMin, int nSec ∥用给定值填写对象 int Set Date( int nYear, int n Month, int nDay),∥用给定日期填写对象 nt settime( int hour, int nmin, int n Sec),∥用给定时间填写对象 CString format( LPCTSTR lpszFormat) const;∥将对象值按指定格式写入字符串 其中大部分的含义很明显,也可通过查询MSDN明确其用法。下面介绍最后一个函数,即 将 COle Date Time对象的值写入字符串函数的用法。该函数的参数 lpszFormat是输出格式字 符串,其中除了一般的字符信息外,还可加入形如“%A”的格式说明。常用的格式说明有 格式说明说明 星期几的缩写 星期几的全称
第 15 单元 控件 306 项卡,确保 Class Name 项为新的对话框类,然后在选项卡下方的窗口中选择各控件的 ID 并 按下“Add Variable…”按钮为其添加对应成员变量: Control IDs Variable Type Member variable name IDC_BIRTHDATE COleDateTime m_tBirthdate IDC_DEPT CString m_strDept IDC_MALE int m_nSex IDC_MARRIED BOOL m_bMarried IDC_NAME CString m_strName IDC_POSITION CString m_strPosition IDC_SALARY float m_fSalary 注意在添加成员变量对话框中的 Category 项均选择 Value(值)并在 Variable type 组合框中 选择相应的数据类型。注意编辑控件 IDC_BIRTHDATE 对应了一个 COleDateTime 类的数据 成员。COleDateTime 类是用于表示一个时间时间,包括日期和时刻。ColeDateTime 类的成 员函数很多,主要有: COleDateTime ( int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec ); // 根据给定值构造时间对象 static COleDateTime GetCurrentTime ( ); // 用当前系统时间填写对象 int GetYear ( ) const; // 取对象中的年值 int GetMonth ( ) const; // 取对象中的月值 int GetDay ( ) const; // 取对象中的日值 int GetHour ( ) const; // 取对象中的小时值 int GetMinute ( ) const; // 取对象中的分钟值 int GetSecond ( ) const; // 取对象中的秒值 int GetDayOfWeek ( ) const; // 取对象中的星球值 int GetDayOfYear ( ) const; // 取日相对上年末的天数 int SetDateTime ( int nYear, int nMonth, int nDay, int nHour, int nMin, int nSec ); // 用给定值填写对象 int SetDate ( int nYear, int nMonth, int nDay ); // 用给定日期填写对象 int SetTime ( int nHour, int nMin, int nSec ); // 用给定时间填写对象 CString Format ( LPCTSTR lpszFormat ) const; // 将对象值按指定格式写入字符串 其中大部分的含义很明显,也可通过查询 MSDN 明确其用法。下面介绍最后一个函数,即 将 COleDateTime 对象的值写入字符串函数的用法。该函数的参数 lpszFormat 是输出格式字 符串,其中除了一般的字符信息外,还可加入形如“%A”的格式说明。常用的格式说明有: 格式说明 说明 %a 星期几的缩写 %A 星期几的全称
15单元控件 月份名的缩写 %B 月份名的全称 日期和时间的习惯表示 日期(01-31) %H 24时制的小时(00-23) 12时制的小时(01-12) 当前日期与上年年底之间的天数(01-366) 数字表示的月份(01-12) 分钟(00 12时制的时间(带AM/PM表示) 秒( 一年中的第几个星期(00-53) 星期几(0-6;星期日为0) 一年中的第几个星期,以星期一作为星期的开始(00-53) % 日期 %X 时间 年份(00-99) %Y 年份(全4位) %z,%Z时区名或其简称 百分号 例如: Cole Tate Time tm(2000, 3, 16, 10, 30,0) Cstring S; s=tm Format(%Y%m %d(%A),%H: %M: %S"); 则字符串s中的内容为“20000316( Thursday),10:30:00 使用 COleDate Time类要在头文件中添加文件包含命令: #include <afxdisp. h 如果添加的是对应编辑控件的成员变量,可在选项卡左下方输入数据检验信息。对于字 符串变量,可输入最大字符个数:对于日期和数值变量,可分别输入上限值和下限值 以上工作完成后,可检查一下由 ClassWizard生成的 CEmpDlg类的代码。 CEmpDlg类 的定义为: class CempDlg public CDialog public CEmpDlg(CWnd* pParent NULL: // standard constructor
第 15 单元 控件 307 %b 月份名的缩写 %B 月份名的全称 %c 日期和时间的习惯表示 %d 日期 (01 – 31) %H 24 时制的小时 (00 – 23) %I 12 时制的小时 (01 – 12) %j 当前日期与上年年底之间的天数 (001 – 366) %m 数字表示的月份 (01 – 12) %M 分钟 (00 – 59) %p 12 时制的时间(带 A.M./P.M. 表示) %S 秒 (00 – 59) %U 一年中的第几个星期 (00 – 53) %w 星期几 (0 – 6; 星期日为 0) %W 一年中的第几个星期, 以星期一作为星期的开始 (00 – 53) %x 日期 %X 时间 %y 年份 (00 – 99) %Y 年份(全 4 位) %z, %Z 时区名或其简称 %% 百分号 例如: ColeTateTime tm (2000,3,16,10,30,0); Cstring s; s = tm.Format (“%Y.%m.%d (%A), %H: %M: %S”); 则字符串 s 中的内容为“2000.03.16 (Thursday), 10: 30: 00”。 使用 COleDateTime 类要在头文件中添加文件包含命令: #include 如果添加的是对应编辑控件的成员变量,可在选项卡左下方输入数据检验信息。对于字 符串变量,可输入最大字符个数;对于日期和数值变量,可分别输入上限值和下限值。 以上工作完成后,可检查一下由 ClassWizard 生成的 CEmpDlg 类的代码。CEmpDlg 类 的定义为: class CEmpDlg : public CDialog { public: CEmpDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data
//AFX DATA(CEmpDlg) enum I IDD= IDD EMPLOYEE ColeDateTime m bIrthdate EStrin m strDept BOOL m mArried float m fSalary Cstring m strName t EStrin m strPosition //)AFX DATA // ClassWizard generated virtual function overrides //AFX VIRTUAL(CEmpDlg) rotected: virtual void DoDataExchange(CDataExchange* pDX):// DDX/DDV support //)AFX VIRTUAL 7/ Implementation protected 7/ Generated message map functions //AFX MSG(CEmpDlg) virtual BOOL OnInitDialog o //)AFX MSG DECLARE MESSAGE MAP O 对话框类的构造函数和 DoDataExchange()成员函数也是由 ClassWizard自动维护的: CEmpDlg: CEmpDlg(CWnd* pArent /==NULL*/) CDialog(CempDlg: IDD, pArent) //AFX DATA INIT(CEmpDlg) m bIrthdate= COle Time:: Get Current Time o m strDept m fSalary =0. of //)AFX DATA INIT
第 15 单元 控件 308 //{{AFX_DATA(CEmpDlg) enum { IDD = IDD_EMPLOYEE }; ColeDateTime m_tBirthdate; CString m_strDept; BOOL m_bMarried; float m_fSalary; Cstring m_strName; int m_nSex; CString m_strPosition; //}}AFX_DATA // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CEmpDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: // Generated message map functions //{{AFX_MSG(CEmpDlg) virtual BOOL OnInitDialog(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; 对话框类的构造函数和 DoDataExchange()成员函数也是由 ClassWizard 自动维护的: CEmpDlg::CEmpDlg(CWnd* pParent /*=NULL*/) : CDialog(CEmpDlg::IDD, pParent) { //{{AFX_DATA_INIT(CEmpDlg) m_tBirthdate = COleDateTime::GetCurrentTime(); m_strDept = _T(""); m_bMarried = FALSE; m_fSalary = 0.0f; m_strName = _T(""); m_nSex = -1; m_strPosition = _T(""); //}}AFX_DATA_INIT }
15单元控件 void CEmpDlg: DoData Exchange( CDataExchange* pDX) CDialog: DoDataExchange(pDX) //HAFX DATA MAP(CEmpDlg) DDX Text(pDX, IDC BIRTHDATE, m tBirthdate) DDX LBString(pDX, IDC DEPT, m strDept) DDX Check(pDX, IDC MARRIED, m bMarried) DDX Text(pDX, IDC SALARY, m fSalary DDV MinMax Float(pDX, m fSalary, 0.f, 10000. f) DDX Text(pDX, IDC NAME, m strName) DDV Max Chars (pDX, m strName, 20) DDX Radio(pDX, IDC MALE, m nSex) DDX CBString(pDX, IDC POSiTioN, m strPosition) DDV MaxChars(p //)AFX DATA MAP 其中构造函数中有 CEmpDlg类各数据成员的初始化代码, DoDataExchange()函数中为这 些数据成员与控件之间的数据交换和数据检验代码 接着,还应编辑项目的菜单资源,在框架窗口的主菜单( IDR MAINFRAME)中添加 两个菜单选项,并为下拉菜单“编辑”添加三个菜单选项 Prompt ID NEXI下一记录 下一职工档案n下一记录 ID PREV上一记录 上一职工档案Ⅶn上一记录” ID APPEND输入(&I)Cr+l输入新职工档案ln输入 ID EDIT编辑(&E)crH+E编辑职工档案n编辑 ID DELETE删除(&D)\CtH+D删除职工档案Ⅶn删除 然后利用 ClassWizard为视图类添加与这些菜单选项对应的成员函数。进入在 Classwizard 的 Message Maps选项卡,选择 Class Name项为 CMy View,在 Object IDs列表框中分别选 择新添加的菜单选项的ID,在 Messages列表框中选择 COMMAND,按下 Add function按 钮添加成员函数。 Class wizard会为这些菜单选项添加相应的消息响应函数(目前尚没有具 体内容,需要程序员自行加入有关的处理代码),并将其声明加入 CMy View类定义,在消 息映射宏中加入相应的消息映射 完成以上工作后,即可修改程序框架,添加必要的代码。 程序:由于列表框尚未初始化,所以为 CEmpDlg类重载 OnInitDialog()成员函 数(可使用 ClassWizard完成),并添加相应代码 BOOL CEmpDlg:: OnInitDialogo
第 15 单元 控件 309 void CEmpDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CEmpDlg) DDX_Text(pDX, IDC_BIRTHDATE, m_tBirthdate); DDX_LBString(pDX, IDC_DEPT, m_strDept); DDX_Check(pDX, IDC_MARRIED, m_bMarried); DDX_Text(pDX, IDC_SALARY, m_fSalary); DDV_MinMaxFloat(pDX, m_fSalary, 0.f, 10000.f); DDX_Text(pDX, IDC_NAME, m_strName); DDV_MaxChars(pDX, m_strName, 20); DDX_Radio(pDX, IDC_MALE, m_nSex); DDX_CBString(pDX, IDC_POSITION, m_strPosition); DDV_MaxChars(pDX, m_strPosition, 20); //}}AFX_DATA_MAP } 其中构造函数中有 CEmpDlg 类各数据成员的初始化代码,DoDataExchange()函数中为这 些数据成员与控件之间的数据交换和数据检验代码。 接着,还应编辑项目的菜单资源,在框架窗口的主菜单(IDR_MAINFRAME)中添加 两个菜单选项,并为下拉菜单“编辑”添加三个菜单选项: ID Caption Prompt ID_NEXT 下一记录 下一职工档案\n 下一记录 ID_PREV 上一记录 上一职工档案\n 上一记录” ID_APPEND 输入(&I)\tCtrl+I 输入新职工档案\n 输入 ID_EDIT 编辑(&E)\tCtrl+E 编辑职工档案\n 编辑 ID_DELETE 删除(&D)\tCtrl+D 删除职工档案\n 删除 然后利用 ClassWizard 为视图类添加与这些菜单选项对应的成员函数。进入在 ClassWizard 的 Message Maps 选项卡,选择 Class Name 项为 CMyView,在 Object IDs 列表框中分别选 择新添加的菜单选项的 ID,在 Messages 列表框中选择 COMMAND,按下 Add Function 按 钮添加成员函数。ClassWizard 会为这些菜单选项添加相应的消息响应函数(目前尚没有具 体内容,需要程序员自行加入有关的处理代码),并将其声明加入 CMyView 类定义,在消 息映射宏中加入相应的消息映射。 完成以上工作后,即可修改程序框架,添加必要的代码。 程 序:由于列表框尚未初始化,所以为 CEmpDlg 类重载 OnInitDialog()成员函 数(可使用 ClassWizard 完成),并添加相应代码: BOOL CEmpDlg::OnInitDialog() {
CListBox *pLB =(CListBox *)GetDlgItem (IDC DEPT) pLB- Insertstring(-1,"办公室") LB-> InsertString(-1,"开发部"); pLB-> InsertString(-1,“生产部") pLB-> Insertstring(-1,"销售部"); pLB-> Insertstring(-1,"人事部"); return CDialog: OnInitDialogo 其中 GetDlgltem()为对话框类的成员函数,用于取对话框控件的指针。 为项日添加有关自定义的职工类 EMployee.选择 Developer Studio菜单的 Insert/New Cas选项,调出 New Class对话框。在 Class Type组合框中选择 Generic(普通类),填 写类名 EMployee,在对话框下方的 Base class(es)框中输入基类 CObject 在 Workspace窗口的 Class view中选择生成的 EMployee类的定义,添加代码 class CEmp public cob ject DECLARE SERIAL ( CEmployee) public string m strName //姓名 int m ns //性别 COleDateTime m bIrthdate;//出生日期 BOOL m mArried //婚否 CString m strDept //工作部门 string m strPosition;//职务 float m fsalary: //工资 EMployee(仆} CEmployee& operator =(CEmployee& e); virtual EMployee o virtual void Serialize(CArchive &ar EMployee类的对象即为一个职工的档案,我们用序列化实现文档的存取,所以要为 EMployee类编写序列化代码。这包括 DECLARE SERIAL()宏和 IMPLEMENT SERIAL ()宏(在 EMployee类的源代码文件中),一个没有参数的构造函数,重载的赋值运算 符和 Serialize()成员函数。在 EMployee类的源代码文件中添加以下代码 IMPLEMENT SERIAL ( CEmployee, COb ject, 1) //重载的赋值运算符 CEmployee& CEmployee: operator =(CEmployee& e)
第 15 单元 控件 310 CListBox *pLB = (CListBox *)GetDlgItem(IDC_DEPT); pLB->InsertString(-1, "办公室"); pLB->InsertString(-1, "开发部"); pLB->InsertString(-1, "生产部"); pLB->InsertString(-1, "销售部"); pLB->InsertString(-1, "人事部"); return CDialog::OnInitDialog(); } 其中 GetDlgItem()为对话框类的成员函数,用于取对话框控件的指针。 为项目添加有关自定义的职工类 CEmployee。选择 Developer Studio 菜单的 Insert/New Class…选项,调出 New Class 对话框。在 Class Type 组合框中选择 Generic(普通类),填 写类名 CEmployee,在对话框下方的 Base class (es)框中输入基类 CObject。 在 Workspace 窗口的 Class View 中选择生成的 CEmployee 类的定义,添加代码: class CEmployee : public CObject { DECLARE_SERIAL(CEmployee) public: CString m_strName; // 姓名 int m_nSex; // 性别 COleDateTime m_tBirthdate; // 出生日期 BOOL m_bMarried; // 婚否 CString m_strDept; // 工作部门 CString m_strPosition; // 职务 float m_fSalary; // 工资 CEmployee(){} CEmployee& operator = (CEmployee& e); virtual ~CEmployee(); virtual void Serialize(CArchive &ar); }; CEmployee 类的对象即为一个职工的档案,我们用序列化实现文档的存取,所以要为 CEmployee 类编写序列化代码。这包括 DECLARE_SERIAL()宏和 IMPLEMENT_SERIAL ()宏(在 CEmployee 类的源代码文件中),一个没有参数的构造函数,重载的赋值运算 符和 Serialize()成员函数。在 CEmployee 类的源代码文件中添加以下代码: IMPLEMENT_SERIAL(CEmployee, CObject, 1) // 重载的赋值运算符 CEmployee& CEmployee::operator = (CEmployee& e) {
m strName =e m strName m bIrthday =e m bIrthdate m mArried =e m mArried; m strEp =e m strDept m strPosition =e m strPosition =e m fSalary turn this //序列化函数 void CEmployee: Serialize(CArchive& ar) CObject:: Serialize(ar) if(ar. IsStoring o) ar 〉 m strName ar>〉 m bIrthdate ar >>m mArried ar >>m strPosition ar >>m fSalary 然后修改文档类 CMy Document类定义,添加一个 EMployee类的数组 include "employee. h class CMy 1501Doc public CDocument
第 15 单元 控件 311 m_strName = e.m_strName; m_nSex = e.m_nSex; m_tBirthdate = e.m_tBirthdate; m_bMarried = e.m_bMarried; m_strDept = e.m_strDept; m_strPosition = e.m_strPosition; m_fSalary = e.m_fSalary; return *this; } // 序列化函数 void CEmployee::Serialize(CArchive& ar) { CObject::Serialize(ar); if(ar.IsStoring()) { ar > m_strName; ar >> m_nSex; ar >> m_tBirthdate; ar >> m_bMarried; ar >> m_strDept; ar >> m_strPosition; ar >> m_fSalary; } } 然后修改文档类 CMyDocument 类定义,添加一个 CEmployee 类的数组: #include "employee.h" #define MAX_EMPLOYEE1000 class CMy1501Doc : public CDocument
15单元控件 DECLARE DYNCREATE(CMy 150lDoc) publ CEmployee m empList IMAX EMPLOYEE] int m nCount publIc virtual BOOL On NewDocumento virtual void Serialize(CArchive& ar) virtual void DeleteContentso DECLARE MESSAGE MAPO 为了节省篇幅,这段程序经过删节,与原来由 AppWizard生成的程序有所不同。其中 黑体部分为要添加的代码。注意重载成员函数 DeleteContents()可以手工进行,也可以通 过 Classwizard进行。 Serialize()和 Deletecontents()两个成员函数的代码如下: void CMy 150lDoc:: Serialize(CArchive& ar) if(ar. IsStoringo) 〉 m n Count for(int i=0: i<m nCount: i++) m empList [i]. Serialize(ar) void CMy 150lDoc: DeleteContents o m nCount=0;//在打开文件和建立新文件时将数组大小置0 CDocument:: DeleteContents o 即在文档类的 Serialize()函数中,数据的序列化工作是通过调用 Employee类的 serialize()函数实现的。 实际上,要为本程序添加的大部分代码均在视图类中。首先在视图类 Cmy View类的定 义中添加一个用于记录当前操作的是哪个记录的数据成员 int m n CurrEmp 并为视图类重载 OnInitialUpdate()成员函数,在其中初始化该变量: void CMy 1501View:: OnInitialUpdate o
第 15 单元 控件 312 { DECLARE_DYNCREATE(CMy1501Doc) public: CEmployee m_empList[MAX_EMPLOYEE]; int m_nCount; public: virtual BOOL OnNewDocument(); virtual void Serialize(CArchive& ar); virtual void DeleteContents(); DECLARE_MESSAGE_MAP() }; 为了节省篇幅,这段程序经过删节,与原来由 AppWizard 生成的程序有所不同。其中 黑体部分为要添加的代码。注意重载成员函数 DeleteContents()可以手工进行,也可以通 过 ClassWizard 进行。Serialize()和 DeleteContents()两个成员函数的代码如下: void CMy1501Doc::Serialize(CArchive& ar) { if(ar.IsStoring()) ar > m_nCount; for(int i=0; i<m_nCount; i++) m_empList[i].Serialize(ar); } void CMy1501Doc::DeleteContents() { m_nCount = 0; // 在打开文件和建立新文件时将数组大小置 0 CDocument::DeleteContents(); } 即在文档类的 Serialize()函数中,数据的序列化工作是通过调用 Cemployee 类的 Serialize()函数实现的。 实际上,要为本程序添加的大部分代码均在视图类中。首先在视图类 CmyView 类的定 义中添加一个用于记录当前操作的是哪个记录的数据成员: int m_nCurrEmp; 并为视图类重载 OnInitialUpdate()成员函数,在其中初始化该变量: void CMy1501View::OnInitialUpdate() {