Presentation is loading. Please wait.

Presentation is loading. Please wait.

第9章数据库应用 9.1数据库和ODBC操作 9.2MFC ODBC应用编程 9.3ADO数据库编程 9.4数据库相关的ActiveX控件

Similar presentations


Presentation on theme: "第9章数据库应用 9.1数据库和ODBC操作 9.2MFC ODBC应用编程 9.3ADO数据库编程 9.4数据库相关的ActiveX控件"— Presentation transcript:

1 第9章数据库应用 9.1数据库和ODBC操作 9.2MFC ODBC应用编程 9.3ADO数据库编程 9.4数据库相关的ActiveX控件
9.5综合应用

2 9.1数据库和ODBC操作 9.1.1 数据库基本概念 1. 数据库和DBMS
数据库基本概念 1. 数据库和DBMS 数据库是指以一定的组织形式存放在计算机存储介质上的相互关联的数据的集合。例如,把一个学校的教师、学生和课程等数据有序地组织起来,存储在计算机磁盘上,就构成了一个数据库。 为了能有效地管理数据库,常常需要数据库管理系统(DBMS)为用户提供对数据库的操作,包括数据库的建立和记录的输入、修改、检索、显示、删除和统计等。DBMS为用户提供的对数据库操作的方法包括交互界面和SQL语句接口。Visual C++就是通过SQL语句接口操作数据库。 目前,使用最多的是关系数据库,有许多关系数据库管理系统(DBMS),如Access、SQL Server、Oracle、Sybase 和Visual Foxpro等, 2. SQL语句 SQL(结构化查询语言)语句是用来在DBMS中访问和操作数据库的标准语言,SQL语言主要包括三个方面:

3 9.1数据库和ODBC操作 (1)数据操纵语言DML(Data Manipulation Language):主要包括查询、插入、删除和修改数据库中的数据的操作。 (2)数据定义语言DDL(Data Definition Language):定义数据库结构,包括定义表、视图和索引等。 (3) 数据控制语言DCL(Data Control Language):包括对数据库的安全性控制、完整性控制以及对事务的定义、并发控制和恢复等。 3. ODBC、DAO和OLE DB Visual C++为用户提供了ODBC(Open Database Connectivity,开放数据库连接)、DAO(Data Access Objects,数据访问对象)及OLE DB(OLE Data Base,OLE数据库)三种数据库方式,使用户的应用程序从特定的数据管理系统脱离出来。 ODBC提供了应用程序接口(API),使得任何一个数据库都可以通过ODBC驱动器与指定的DBMS相联。用户的程序可通过调用ODBC驱动管理器中相应的驱动程序达到管理数据库的目的。作为Microsoft Windows Open Standards Architecture (WOSA,Windows开放式服务体系结构)的主要组成部分,ODBC一直沿用至今。

4 9.1数据库和ODBC操作 DAO类似于用Microsoft Access或Microsoft Visual Basic编写的数据库应用程序,它使用Jet数据库引擎形成一系列的数据访问对象:数据库对象、表和查询对象、记录集对象等。它可以打开一个Access数据库文件(MDB文件),也可直接打开一个ODBC数据源以及使用Jet引擎打开一个ISAM(被索引的顺序访问方法)类型的数据源(dBASE、FoxPro、Paradox、Excel或文本文件)。 OLE DB试图提供一种统一的数据访问接口,并能处理除了标准关系型数据库中的数据之外,还能处理包括邮件数据、Web上的文本或图形、目录服务(Directory Services)以及主机系统中的IMS和VSAM数据。OLE DB提供一个数据库编程COM(组件对象模型)接口,使得数据的使用者(应用程序)可以使用同样的方法访问各种数据,而不用考虑数据的具体存储地点、格式或类型。这个COM接口与ODBC相比,其健壮性和灵活性要高得多。但是,由于OLE DB的程序比较复杂,因而对于一般用户来说使用ODBC和DAO方式已能满足一般数据库处理的需要。 4. ADO ADO 是目前在Windows环境中比较流行的客户端数据库编程技术。它是Microsoft为最新和最强大的数据访问范例OLE DB而设计的,是一个便于使用的应用程序层接口。ADO使用户应用程序能够通过“OLE DB提供者”访问和操作数据库服务器中的数据。由于它兼具有强大的数据处理功能(处理各种不同类型的数据源、分布式的数据处理等等)和极其简单、易用的编程接口,因而得到了广泛的应用。

5 9.1数据库和ODBC操作 ADO技术基于COM(Component Object Model,组件对象模型),具有COM组件的许多优点,可以用来构造可复用应用框架,被多种语言支持,能够访问包括关系数据库、非关系数据库及所有的文件系统。另外,ADO还支持各种B/S与基于Web的应用程序,具有远程数据服务RDS(Remote Data Service)的特性,是远程数据存取的发展方向。 表9.1 学生课程成绩表(score)及其表结构 学号(studentno)       课程号(course) 成绩(score) 学分(credit) 80 85 70 78 3 2.5 序 号 字段名称 数据类型 字段大小 小数位 字段含义 1 2 4 studentno course score credit 文本 数字 8 7 单精度 学号   课程号   成绩 学分

6 9.1数据库和ODBC操作 9.1.2 MFC ODBC向导过程
用MFC AppWizard使用ODBC数据库的一般过程是:①用Access或其他数据库工具构造一个数据库;②在Windows中为刚才构造的数据库定义一个ODBC数据源;③在创建数据库处理的文档应用程序向导中选择数据源;④设计界面,并使控件与数据表字段关联。 1. 构造数据库 数据库表与表之间的关系构成了一个数据库。作为示例,这里用Microsoft Access 创建一个数据库Student.mdb,其中暂包含一个数据表score,用来描述学生课程成绩,如表9.1所示。在表中包括上、下两部分,上部分是数据表的记录内容,下部分是数据表的结构内容。 需要说明的是,数据表结构可以看成是一个具有行和列的二维表格。表格中的一行称为一个记录,一列称为一个字段,每列的标题称为字段名。 2. 创建ODBC数据源 Windows中的ODBC组件是出现在系统的“控制面板”中的“管理工具”中的“数据源(ODBC)”,如图9.1所示。

7 9.1数据库和ODBC操作 图9.1 Windows XP的管理工具

8 9.1数据库和ODBC操作 双击“数据源(ODBC)”,进入ODBC数据源管理器。在这里,用户可以设置ODBC数据源的一些信息。其中,“用户DSN”页面是用来定义用户自己在本地计算机使用的数据源名(DSN),如图9.2所示。 图9.2 ODBC数据源管理器

9 9.1数据库和ODBC操作 那么,创建一个用户DSN可有如下的过程:
(1)单击[添加]按钮,弹出有一驱动程序列表的“创建新数据源”对话框,在该对话框中选择要添加用户数据源的驱动程序,这里选择“Microsoft Access Driver”,如图9.3所示。 (2)单击[完成]按钮,进入指定驱动程序的安装对话框,单击[选择]按钮将前面创建的数据库调入,然后在数据源名输入“Database Example For VC++”,结果如图9.4所示。 (3)单击[确定]按钮,刚才创建的用户数据源被添加在“ODBC数据源管理器”的“用户数据源”列表中。 图9.3 “创建新数据源”对话框 图9.4 ODBC Access 安装对话框

10 9.1数据库和ODBC操作 3. 在MFC AppWizard中选择数据源
(1)用MFC AppWizard创建一个单文档应用程序Ex_ODBC。 (2)在向导的第2步对话框中加入数据库的支持,如图9.5所示。在该对话框中用户可以选择对数据库支持程序,其中各选项的含义如表9.2所示。 图9.5 向导的第二步对话框

11 9.1数据库和ODBC操作 表9.2 MFC支持数据库的不同选项 选项 创建的视图类 创建的文档类 否(None) 从CView派生
支持文档的常用操作,并在“文件”菜单中有“新建”、“打开”、“保存”、“另存为”等命令。 标题文件(Header files only) 除了在StdAfx.h文件中添加了“#include <afxdb.h>”语句外,其余与“None”选项相同 查看数据库不使用文件支持(Database view without file support) 从CRecordView派生 不支持文档的常用操作,也就是说,创建的文档类不能进行序列化,且在“文件”菜单中没有“新建”等文档操作命令。但用户可在用户视图在中使用CRecordset类处理数据库 查看数据库使用文件支持(Database view with file support) 全面支持文档操作和数据库操作

12 图9.6 “Database Options”对话框 图9.7 “Select Database Tables”对话框
9.1数据库和ODBC操作 (3)选中“数据库查看使用文件支持”项,单击[数据源] (Data Source)按钮,弹出“Database Options”对话框,从中选择ODBC的数据源“Database Example For VC++”,如图9.6所示。 需要说明的是,Recordset type(记录集类型)有动态集(Dynaset)和快照集(Snapshot)之分。动态集能与其他应用程序所做的更改保持同步,而快照集则是数据的一个静态视图。这两种类型在记录集被打开时都提供一组记录,所不同的是:当在一个动态集里滚动一条记录时,由其他用户或应用程序中的其他记录集对该记录所做的更改会相应地显示出来,而快照集则不会。 图9.6 “Database Options”对话框 图9.7 “Select Database Tables”对话框

13 9.1数据库和ODBC操作 (4)保留其他默认选项,单击[OK]按钮,弹出如图9.7所示的“Select Database Tables”对话框,从中选择要使用的表score。 (5)单击[OK]按钮,又回到了向导的第2步对话框。 (6)单击[完成]按钮。开发环境自动打开表单视图CEx_ODBCView的对话框资源模板 IDD_EX_ODBC_FORM以及相应的对话框编辑器。 (7)编译并运行,结果如图9.8所示。 记录浏览按钮 图9.8 Ex_ODBC运行结果

14 9.1数据库和ODBC操作 需要说明的是, MFC AppWizard创建的Ex_ODBC应用程序与一般默认的单文档应 用程序相比较,在类框架方面,有如下几点不同: ● 添加了一个CEx_ODBCSet类,它与上述过程中所选择的数据表score进行数据绑定,也就是说,CEx_ODBCSet对象的操作实质上对数据表进行操作。 ● 将CEx_ODBCView类的基类设置成CRecordView。由于CRecordView的基类是CFormView,因此它需要与之相关联的表单资源。 ● 在CEx_ODBCView类中添加了一个全局的CEx_ODBCSet对象指针变量m_pSet,目的是在表单视图和记录集之间建立联系,使得记录集中的查询结果能够很容易地在表单视图上显示出来。 4. 设计浏览记录界面 在上面的Ex_ODBC中,MFC为用户自动创建了用于浏览数据表记录的工具按钮和相应的“记录”菜单项。若用户选择这些浏览记录命令,系统会自动调用相应的函数来移动数据表的当前位置。 若在表单视图CEx_ODBCView中添加控件并与表的字段相关联,就可以根据表的当前记录位置显示相应的数据。其步骤如下。

15 9.1数据库和ODBC操作 (1)按照图9.9所示的布局,为表单对话框资源模板添加表9.3所示的控件。 图9.9 控件的设计

16 9.1数据库和ODBC操作 表9.3 表单对话框控件及属性 添加的控件 ID号 标 题 其他属性 编辑框(学号) IDC_STUNO —— 默认 编辑框(课程号) IDC_COURSENO 编辑框(成绩) IDC_SCORE 编辑框(学分) IDC_CREDIT (2)按快捷键Ctrl+W,弹出MFC ClassWizard对话框,切换到Member Variables页面,在Class name框中选择CEx_ODBCView,为上述控件添加相关联的数据成员。与以往添加控件变量不同的是,这里添加的控件变量都是由系统自动定义的,并与数据库表字段相关联的。例如,双击IDC_STUNO,在弹出的“Add Member Variable”对话框中的成员变量下拉列表中选择要添加的成员变量名m_pSet->m_studentno,选择后,控件变量的类型将自动设置,如图9.10所示。 图9.10 为控件添加数据成员

17 图9.11 添加的控件变量图 9.12 Ex_ODBC最后运行结果
(3)按照上一步骤的方法,为表9.4所示的其他控件依次添加相关联的成员变量。需要说明的是,控件变量的范围和大小应与数据表中的字段一一对应。结果如图9.11所示。 表9.4 控件变量 控件ID号 变量名 范围和大小 IDC_COURSENO m_pSet->m_course ­7 IDC_SCORE m_pSet->m_score 0~100 IDC_SREDIT m_pSet->m_credit 1~20 图9.11 添加的控件变量图 Ex_ODBC最后运行结果 (4)编译运行并测试,结果如图9.12所示。

18 图9.13 “MFC ClassWizard”对话框
9.1数据库和ODBC操作 ODBC数据表绑定更新 上述MFC ODBC应用程序框架中,数据表score和CEx_ODBCSet类进行数据绑定。但当数据表的字段更新后,例如,若用Access将score数据表再添加一个“备注”字段名(文本类型,长度为50个字符),并关闭Access后,就需要为Ex_ODBC重新为数据表score和CEx_ODBCSet类进行数据绑定的更新,其步骤如下: (1)按快捷键Ctrl+W,打开MFC ClassWizard对话框,切换到“Member Variables”页面。 (2)在“Class name”的下拉列表中选择“CEx_ODBCSet”,此时MFC ClassWizard对话框的[Update Columns]和[Bind All]按钮被激活,如图9.13所示。需要说明的是,[Update Columns] 按钮用来重新指定与CRecordSet类相关的表,而[Bind All]按钮用来指定表的 字段的绑定,即为字段重新指定默认的关联变量。 图9.13 “MFC ClassWizard”对话框

19 图9.14 “Database Options”对话框 图9.15 “Select Database Tables”对话框
9.1数据库和ODBC操作 (3)单击[Update Columns]按钮,又弹出前面的“Database Options”对话框,选择ODBC数据源“Database Example For VC++”,如图9.14所示。单击[OK]按钮,弹出如图9.15所示的“Select Database Tables”对话框,从中选择要使用的表。单击[OK]按钮,又回到MFC ClassWizard界面,如图9.16所示。 图9.14 “Database Options”对话框 图9.15 “Select Database Tables”对话框

20 图9.16 更新后的“Member Variables”页面
9.1数据库和ODBC操作 图9.16 更新后的“Member Variables”页面 (4)单击[Bind All]按钮,MFC Wizard将自动为字段落添加相关联的变量。需要说明的是,在按[Bind All]按钮绑定前最好将已有的字段关联变量删除,以保证数据表字段名更改或删除后与变量绑定的正确性。

21 9.2MFC ODBC应用编程 查询记录 使用CRecordSet类的成员变量m_strFilter、m_strSort和成员函数Open可以对表进行记录的查询和排序。先来看一个示例,该示例在前面的Ex_ODBC的表单中添加一个编辑框和一个[查询]按钮,单击[查询]按钮,将按编辑框中的学号内容对数据表进行查询,并将查找到的记录显示在前面添加的控件中。具体过程如下: (1)打开Ex_ODBC应用程序的表单资源,按图9.17所示的布局添加控件,其中添加的编辑框ID号设为IDC_EDIT_QUERY,“查询”按钮的ID号设为IDC_BUTTON_QUERY。 图9.17 要添加的控件

22 9.2MFC ODBC应用编程 (2)用MFC ClassWizard为控件IDC_EDIT_QUERY添加关联变量m_strQuery。
(3)在CEx_ODBCView类中添加按钮控件IDC_BUTTON_QUERY的BN_CLICKED消息映射,并在映射函数中添加下列代码: 代码中, m_strFilter和m_strSort是CRecordSet的成员变量,用来执行条件查询和结果排序。其中,m_strFilter称为“过滤字符串”,相当于SQL语句中WHERE后的条件串;而m_strSort称为“排序字符串”,相当于SQL语句中ORDER BY后的字符串。若字段的数据类型是文本,则需要在m_strFilter字符串中将单引号将查询的内容括起来,对于数字,则不需要用单引号。 需要注意的是:只有在调用Open函数之前设置m_strFilter和m_strSort才能保证查询和排序有效。如果有多个条件查询,则可以使用AND、OR、NOT来组合,例如下面的代码: m_pSet->m_strFilter = "studentno>=' ' AND studentno<=' '"; (4)编译运行并测试,结果如图9.18所示。

23 9.2MFC ODBC应用编程 图9.18 查询记录 需要说明的是,如果查询的结果有多条记录,可以用CRecordSet类的MoveNext(下移一个记录)、MovePrev(上移一个记录)、MoveFirst(定位到第一个记录)和MoveLast(定位到最后一个记录)等成员函数来移动当前记录位置进行操作。

24 9.2MFC ODBC应用编程 编辑记录 CRecordSet类为用户提供了许多对表记录进行操作的成员函数用来添加记录、删除记录和修改记录等。 1. 增加记录 增加记录是使用AddNew函数,但要求数据库必须是以“可增加”的方式打开的。下面的代码是在表的末尾增加新记录: m_pSet->AddNew(); // 在表的末尾增加新记录 m_pSet->SetFieldNull(&(m_pSet->m_studentno), FALSE); // 设定m_studentno值不为空(NULL) m_pSet-> m_studentno = " "; // 输入新的字段值 m_pSet->Update(); // 将新记录存入数据库 m_pSet->Requery(); // 刷新记录集,这在快照集方式下是必须的

25 9.2MFC ODBC应用编程 2. 删除记录 可以直接使用CRecordSet::Delete函数来删除记录。需要说明的是,要使删除操作有效,还需要移动记录函数。例如下面的代码: CRecordsetStatus status; m_pSet->GetStatus(status); // 获取当前记录集状态 m_pSet->Delete(); // 删除当前记录 if (status.m_lCurrentRecord==0) // 若当前记录索引号为0(0表示第一条记录)则 m_pSet->MoveNext(); // 下移一个记录 else m_pSet->MoveFirst(); // 移动到第一个记录处 UpdateData(FALSE); 3. 修改记录 函数CRecordSet::Edit可以用来修改记录,例如: m_pSet->Edit(); // 修改当前记录 m_pSet->m_name="刘向东"; // 修改当前记录字段值 ...... m_pSet->Update(); // 将修改结果存入数据库 m_pSet->Requery();

26 9.2MFC ODBC应用编程 3. 撤消操作 如果用户在进行增加或者修改记录后,希望放弃当前操作,则在调用CRecordSet::Update()函数之前调用CRecordSet::Move(AFX_MOVE_REFRESH)来撤消操作,便可恢复在增加或修改操作之前的当前记录。 4. 操作界面 需要说明的是,由于记录的添加和修改往往在同一个界面中进行,会造成一些误操作。因此,在修改和添加记录数据之前,往往设计一个对话框用以获得所需要的数据,然后用该数据进行当前记录的编辑。这样就能避免它们的相互影响,且保证代码的相对独立性。 作为示例,下面的过程是在Ex_ODBC的表单视图中增加三个按钮:[添加]、[修改]和[删除],如图9.19所示。单击[添加]或[修改]按钮都将弹出一个如图9.20所示的对话框,在对话框中对数据进行编辑后,单击[确定]按钮使操作有效。

27 图9.19 Ex_ODBC的记录编辑 图9.20 “学生课程成绩表”对话框
9.2MFC ODBC应用编程 图9.19 Ex_ODBC的记录编辑 图9.20 “学生课程成绩表”对话框

28 9.2MFC ODBC应用编程 (1)将Ex_ODBC的项目工作区窗口切换到ResourceView页面,打开用于表单视图CEx_ODBCView的对话框资源IDD_EX_ODBC_FORM。参看图9.19,向表单中添加三个按钮:[添加](IDC_REC_ADD)、[修改](IDC_REC_EDIT)和[删除](IDC_REC_DEL)。 (2)添加一个对话框资源,打开属性对话框将其字体设置为“宋体9号”,标题定为“学生课程成绩表”,ID号设为IDD_SCORE_TABLE。 (3)参看图9.20,将表单中的控件复制到对话框中。复制时先选中 IDD_EX_ODBC_FORM表单资源模板“学生课程成绩表”组框中的所有控件,然后按Ctrl+C,打开对话框IDD_SCORE_TABLE资源,按Ctrl+V即可。 (4)再将[OK]和[Cancel]按钮的标题分别改为“确定”和“取消”。图中具有3D效果的竖直线是用静态图片控件(属性为“框架”、“刻蚀”)构成的。 (5)双击对话框模板或按Ctrl+W快捷键,为对话框资源IDD_SCORE_TABLE创建一个对话框类CScoreDlg。 (6)打开MFC ClassWizard的Member Variables标签,在Class name中选择CScoreDlg,选中所需的控件ID号,双击鼠标或单击Add Variables按钮。依次为控件添加控件变量,结果如图9.21所示。

29 9.2MFC ODBC应用编程 图9.21 为CScoreDlg添加的控件变量

30 9.2MFC ODBC应用编程 (7)用MFC ClassWizard为CScoreDlg添加IDOK按钮的BN_CLICKED的消息映射,并添加下列代码: void CScoreDlg::OnOK() { UpdateData(); m_strStudentNO.TrimLeft(); m_strCourseNO.TrimLeft(); if (m_strStudentNO.IsEmpty()) MessageBox("学号不能为空!"); else if (m_strCourseNO.IsEmpty()) MessageBox("课程号不能为空!"); CDialog::OnOK(); } (8)用MFC ClassWizard为CEx_ODBCView类中的三个按钮:IDC_REC_ADD、IDC_REC_EDIT和IDC_REC_DEL添加BN_CLICKED的消息映射,并添加下列代码: (9)在Ex_ODBCView.cpp文件的开始处添加下列CScoreDlg类的头文件包含语句: #include “ScoreDlg.h” (10) 编译运行并测试。

31 9.2MFC ODBC应用编程 字段操作 在前面的示例中,虽然可以通过CRecordSet对象中的字段关联变量可以直接访问当前记录的相关字段值,但有时在处理多个字段时就不太方便了。CRecordSet类中的成员变量m_nFields(用于保存数据表的字段个数)和成员函数GetODBCFieldInfo及GetFieldValue可以简化多字段的访问操作。 GetODBCFieldInfo函数用来数据表中的字段信息,其函数原型如下: void GetODBCFieldInfo( short nIndex, CODBCFieldInfo& fieldinfo ); 其中,nIndex用于指定字段索引号,0表示第一个字段,1表示第二个字段,以此类推。fieldinfo是CODBCFieldInfo结构参数,用来表示字段信息。 CODBCFieldInfo结构体原型如下: struct CODBCFieldInfo { CString m_strName; // 字段名 SWORD m_nSQLType; // 字段的SQL数据类型 UDWORD m_nPrecision; // 字段的文本大小或数据大小 SWORD m_nScale; // 字段的小数点位数 SWORD m_nNullability; // 字段接受空值(NULL)能力 };

32 9.2MFC ODBC应用编程 结构体裁中,SWORD和UDWORD分别表示short int和unsigned long int数据类型。
GetFieldValue函数用来获取数据表当前记录中指定字段的值,其常用的函数原型如下: void GetFieldValue( short nIndex, CString& strValue ); 其中,nIndex用于指定字段索引号,strValue用来返回字段的内容。 除了上述字段操作外,CRecordSet类的成员函数GetRecordCount和GetStatus,还可分别用来获得表中的记录总数和当前记录的索引,其原型如下: long GetRecordCount( ) const; void GetStatus( CRecordsetStatus& rStatus ) const; 其中,参数rStatus是指向下列的CRecordsetStatus结构的对象: struct CRecordsetStatus { long m_lCurrentRecord; // 当前记录的索引,0表示第一个记录, // 1表示第二个记录,依次类推。但-1表示在第一个记录之前,-2表示不确定。 BOOL m_bRecordCountFinal; // 记录总数是否是最终结果 };

33 9.2MFC ODBC应用编程 需要注意的是,GetRecordCount函数所返回的记录总数在表打开时或调用Requery函数后是不确定的,因而必须经过下列的代码才能获得最终有效的记录总数: while (!m_pSet->IsEOF()) { m_pSet->MoveNext(); m_pSet->GetRecordCount(); } [例Ex_Field] 字段的编程操作 该示例是用列表视图来显示一个课程信息表(参见表9.5)的全部记录内容,并在状态栏中显示记录总数。具体步骤按如下4部分进行: 1)为数据库Student.mdb添加一个数据表course 用Microsoft Access 为数据库Student.mdb添加一个数据表course,如表9.5所示。表中上部分是数据表的记录内容,下部分是数据表的结构内容。需要说明的是,上述字段名最好不要是中文,且一般不能为SQL的关键字no、class、open等,以避免运行结果出现难以排除的错误。

34 9.2MFC ODBC应用编程 2)为文档应用程序添加ODBC的支持
(1)用MFC AppWizard创建一个单文档应用程序Ex_Field,但在向导的第6步将CEx_FieldView的基类由默认的CView选择为CListView类。 (2)将项目工作区窗口切换到FileView页面,展开Header Files所有项,双击stdafx.h,打开该文件。 (3)在stdafx.h中添加ODBC数据库支持的头文件包含#include <afxdb.h>: #ifndef _AFX_NO_AFXCMN_SUPPORT #include <afxcmn.h> // MFC support for Windows Common Controls #endif // _AFX_NO_AFXCMN_SUPPORT #include <afxdb.h> 3)创建数据表score的CRecordSet派生类 (1)按快捷键Ctrl+W,打开MFC ClassWizard对话框。单击[Add Class]按钮,从弹出的下拉菜单中选择“New”。 (2)在弹出的“Add Class”对话框中输入类名(Name)为CCourseSet,指定其基类(Base class)为CRecordSet,结果如图9.22所示。

35 9.2MFC ODBC应用编程 图9.22 定义新的CRecordSet派生类 (3)单击[OK]按钮,弹出“Database Options”对话框。从中选择ODBC的数据源“Database Example For VC++”,单击[OK]按钮,弹出 “Select Database Tables”对话框,从中选择要使用的表course。 (4)单击[OK]按钮回到MFC ClassWizard界面,单击[确定]按钮后,系统自动为用户生成CCourseSet类所需要的代码。 (5)在CEx_FieldView::PreCreateWindow 函数中 添加修改列表视图风格的代码: BOOL CEx_FieldView::PreCreateWindow(CREATESTRUCT& cs) { cs.style &= ~LVS_TYPEMASK; cs.style |= LVS_REPORT; // 报表方式 return CListView::PreCreateWindow(cs); }

36 9.2MFC ODBC应用编程 (6)在CEx_FieldView::OnInitialUpdate函数中添加下列代码:
需要说明的是,当为数据源中的某个数据表映射一个CRecordSet类时,该类对象一定先要调用CRecordSet::Open成员函数,才能访问该数据表的记录集,访问后还须调用CRecordSet::Close成员函数关闭记录集。 (7)在Ex_FieldView.cpp文件的前面添加CCourseSet类的头文件包含语句: #include "Ex_FieldDoc.h" #include "Ex_FieldView.h" #include "CourseSet.h" (8)编译运行,结果如图9.23所示。 图9.23 Ex_Field第一次运行结果

37 9.2MFC ODBC应用编程 4)在状态栏中显示当前记录号和记录总数
(1)在MainFrm.cpp文件中,向原来的indicators数组添加一个元素,用来在状态栏上增加一个窗格,修改的结果如下: static UINT indicators[] = { ID_SEPARATOR, // 第一个信息行窗格 ID_SEPARATOR, // 第二个信息行窗格 ID_INDICATOR_CAPS, ID_INDICATOR_NUM, ID_INDICATOR_SCRL, };

38 9.2MFC ODBC应用编程 (2)为CEx_FieldView类添加一个成员函数DispRecNum成员函数,其代码如下:
void CEx_FieldView::DispRecNum(CCourseSet *pSet) { CString str; CMainFrame* pFrame = (CMainFrame*)AfxGetApp()->m_pMainWnd; // 获得主框架窗口的指针 CStatusBar* pStatus = &pFrame->m_wndStatusBar; // 获得主框架窗口中的状态栏指针 if (pStatus) CRecordsetStatus rStatus; pSet->GetStatus(rStatus); // 获得当前记录信息 str.Format("当前记录:%d 总记录:%d",1+rStatus.m_lCurrentRecord, pSet->GetRecordCount()); pStatus->SetPaneText(1,str); // 更新第二个窗格的文本 }

39 9.2MFC ODBC应用编程 该函数先获得状态栏对象的指针,然后调用SetPaneText函数更新第二个窗格的文本。
(3)在CEx_FieldView类的OnInitialUpdate函数处添加下列代码: void CEx_FieldView::OnInitialUpdate() { CString str; while (!cSet.IsEOF()) {… } DispRecNum( &cSet ); cSet.Close(); // 关闭记录集 (4)在Ex_FieldView.cpp文件的开始处增加下列语句: #include "Ex_FieldDoc.h" #include "Ex_FieldView.h" #include "CourseSet.h" #include "MainFrm.h"

40 9.2MFC ODBC应用编程 (5)将MainFrm.h文件中的保护型变量m_wndStatusBar变成公共变量。
(6)编译运行并测试,结果如图9.24所示。 显示的记录信息 图9.24 Ex_Field最后运行结果

41 9.2MFC ODBC应用编程 多表处理 数据库中表与表之间往往存在着一定的关系,例如要显示一个学生的课程成绩信息,信息包括学号、姓名、课程号、课程所属专业、课程名称、课程类别、开课学期、课时数、学分、成绩,则要涉及到前面的学生课程成绩表(score)、课程表以及学生基本信息表。其中的学生基本信息表如表9.6所示。表中上部分是数据表的记录内容,下部分是数据表的结构内容。 表9.6 学生基本信息表(student)及其表结构 姓名 (studentname) 学号 (sudentno) 性别 (xb) 出生年月 (birthday) 专业 (special) 李明 王玲 张芳 陈涛 true false 电气工程及其自动化 机械工程及其自动化 序 号 字段名称 数据类型 字段大小 小数位 字段含义 1 2 3 4 5 studentname studentno xb birthday special 文本 是/否 日期/时间 20 10 50

42 9.2MFC ODBC应用编程 下面的示例在一个对话框中用两个控件来进行学生课程成绩信息的相关操作,如图9.25所示,左边是树视图,用来显示学生成绩、专业和班级号三个层次信息,单击班级号,所有该班级的学生课程成绩信息将在右边的列表视图中显示出来。 图9.25 Ex_Student运行结果

43 9.2MFC ODBC应用编程 [例Ex_Student] 多表处理(按6部分来阐述)
1)为数据库Student.mdb添加一个数据表student 用Microsoft Access 为数据库Student.mdb添加一个数据表student,如前表9.6所示。 2)创建并设计对话框应用程序 (1)用MFC AppWizard创建一个默认的基于对话框应用程序Ex_Student。 (2)在打开的对话框资源模板中,删除[取消]按钮和默认的静态文本控件。调整对话框大小,将对话框的标题文本改为“处理多表”,将[确定]按钮的标题文本改为“退出”。 (3)参看图8.26的控件布局,向对话框中添加一个树控件,在其属性对话框中,选中“有按钮”、“有线条”、“根部的线”和“总是显示选定内容”属性。 (4)向对话框中添加一个列表控件,在其属性对话框中,将“查看”属性选为“报告”。 (5)用MFC ClassWizard在CEx_StudentDlg类中,添加树控件的控件变量为m_treeCtrl,添加列表控件的控件变量为m_listCtrl。 3)添加对MFC ODBC的支持及记录集 (1)在stdafx.h文件中添加ODBC数据库支持的头文件包含#include <afxdb.h>。 (2)用MFC ClassWizard为数据表student、course和score分别创建CRecordSet派生类CStudentSet、CCourseSet和CScoreSet。

44 9.2MFC ODBC应用编程 4)完善左边树控件的代码
(1)为CEx_StudentDlg类添加一个成员函数FindTreeItem,用来查找指定节点下是否有指定节点文本的子节点,该函数的代码如下: HTREEITEM CEx_StudentDlg::FindTreeItem(HTREEITEM hParent, CString str) { HTREEITEM hNext; CString strItem; hNext = m_treeCtrl.GetChildItem( hParent); while (hNext != NULL) strItem = m_treeCtrl.GetItemText( hNext ); if ( strItem == str ) return hNext; else hNext = m_treeCtrl.GetNextItem( hNext, TVGN_NEXT ); } return NULL; (2)为CEx_StudentDlg类添加一个CImageList成员变量m_ImageList。 (3)在CEx_StudentDlg::OnInitDialog中添加下列代码:

45 9.2MFC ODBC应用编程 (4)在Ex_StudentDlg.cpp文件的前面添加记录集类的包含文件,如下面的代码:
#include "Ex_StudentDlg.h" #include "StudentSet.h" #include "ScoreSet.h" #include "CourseSet.h" (5)编译运行,结果如图9.26所示。 图9.26 Ex_Student第一次运行结果

46 9.2MFC ODBC应用编程 5)完善右边列表控件的代码
(1)在CEx_StudentDlg::OnInitDialog函数中添加下列代码,用来创建列表标题头: BOOL CEx_StudentDlg::OnInitDialog() { sSet.Close(); // 设置列表头 CString strHeader[]={"学号","姓名", "课程号","课程所属专业", "课程名称","课程类别","开课学期","课时数","学分","成绩"}; int nLong[] = {80, 80, 80, 180, 180, 80, 80, 80, 80, 80}; for (int nCol=0; nCol<sizeof(strHeader)/sizeof(CString); nCol++) m_listCtrl.InsertColumn(nCol,strHeader[nCol],LVCFMT_LEFT,nLong[nCol]); return TRUE; // return TRUE unless you set the focus to a control } (2)为CEx_StudentDlg类添加一个成员函数DispScoreAndCourseInfo,用来根据指定的条件在列表控件中用报表形式显示学生成绩的所有信息,该函数的代码如下:

47 9.2MFC ODBC应用编程 (3)编译并运行,结果如图9.27所示。 6)完善两控件的关联代码
图9.27 Ex_Student第二次运行结果 6)完善两控件的关联代码 (1)从上图中可以看出,学生成绩还没有显示出来,下面将实现单击左边的班级号,在右边视图中显示该班级的所有学生成绩信息。 (2)用MFC ClassWizard为CEx_StudentDlg类添加TVN_SELCHANGED消息处理,并添加下列代码:

48 9.2MFC ODBC应用编程 void CEx_StudentDlg::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult) { NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR; HTREEITEM hSelItem = pNMTreeView->itemNew.hItem; // 获取当前选择的节点 // 如果当前的节点没有子节点,那说明该节点是班级号节点 if (m_treeCtrl.GetChildItem(hSelItem) == NULL) CString strSelItem, str; strSelItem = m_treeCtrl.GetItemText( hSelItem ); str.Format("studentno LIKE '%s%%'", strSelItem.Left(6)); DispScoreAndCourseInfo(str); } *pResult = 0; 代码中,调用DispScoreAndCourseInfo 函数是的参数是用来设置数据表(记录集)打开的过滤条件。str是类似的这样内容“studentno LIKE %”,它使得所有学号前面是210101的记录被打开。%是SQL使用的通配符,由于%也是Visaul C++格式前导符,因为在代码中需要两个%。 (3)编译运行并测试。

49 9.3ADO数据库编程 ADO编程的一般过程 在MFC应用程序中使用ADO数据库的一般过程是:①添加对ADO的支持;②创建一个数据源连接;③对数据源中的数据库进行操作;④关闭数据源。 这里先来介绍添加对ADO的支持以及数据源连接和关闭。 1. 添加对ADO的支持 ADO编程有三种方式:使用预处理指令#import、使用MFC中的CIDispatchDriver和 直接使用COM提供的API。这三种方式中,第一种最为简便,故这里采有用这种方法。 下面以一个示例过程来说明在MFC应用程序中添加对ADO的支持。 [例Ex_ADO] 添加对ADO的支持 (1)用MFC AppWizard创建一个默认的单文档应用程序Ex_ADO,但在向导的第6步将CEx_ADOView的基类由默认的CView选择为CListView类,以便更好地显示和操作数据表中的记录。 (2)在CEx_ADOView::PreCreateWindow函数添加下列代码,用来设置列表视图内嵌列表控件的风格:

50 9.3ADO数据库编程 (3)在stdafx.h文件中添加对ADO支持的代码:
BOOL CEx_ADOView::PreCreateWindow(CREATESTRUCT& cs) { cs.style |= LVS_REPORT; // 报表风格 return CListView::PreCreateWindow(cs); } (3)在stdafx.h文件中添加对ADO支持的代码: #endif // _AFX_NO_AFXCMN_SUPPORT #include <afxcmn.h> // MFC support for Windows Common Controls #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "adoEOF") #include <icrsint.h> //{{AFX_INSERT_LOCATION}} 代码中,预编译命令#import是编译器将此命令中所指定的动态链接库文件引入到程序中,并从动态链接库文件中抽取出其中的对象和类的信息。 icrsint.h文件包含了Visual C++扩展的一些预处理指令、宏等的定义,用于与数据库数据绑定。

51 9.3ADO数据库编程 (4)在CEx_ADOApp::InitInstance函数中添加下列代码,用来对ADO的COM环境进行初始化:
BOOL CEx_ADOApp::InitInstance() { ::CoInitialize(NULL); AfxEnableControlContainer(); … } (5)在Ex_ADOView.h文件中为CEx_ADOView定义三个ADO对象指针变量: public: _ConnectionPtr m_pConnection; _RecordsetPtr m_pRecordset; _CommandPtr m_pCommand; 代码中, _ConnectionPtr、_RecordsetPtr和_CommandPtr分别是ADO对象Connection、Recordset和Command的智能指针类型。 2. 连接数据源 只有建立了与数据库服务器的连接后,才能进行其他有关数据库的访问和操作。ADO使用Connection对象来建立与数据库服务器的连接,它相当于MFC中的CDatabase类。和CDatabase类一样,调用Connection对象的Open即可建立与服务器的连接。

52 9.3ADO数据库编程 HRESULT Connection::Open(_bstr_t ConnectionString, _bstr_t UserID, _bstr_t Password, long Options ) 其中,ConnectionString为连接字串,UserID是用户名,Password是登录密码,Options是选项,通常用于设置同步和异步等方式。_bstr_t是一个COM类,用于字符串BSTR(用于Automation的宽字符)操作。 需要说明的是,正确设置ConnectionString是连接数据源的关键。不同的数据,其连接字串有所不同,见表9.7所示。 表9.7 Connection对象的连接字串格式 数据源 格式 ODBC "[Provider=MSDASQL;] {DSN = name | FileDSN = filename}; [DATABASE=database;] UID = user; PWD = password" Access数据库 "Provider = Microsoft.Jet.OLEDB.4.0; Data Source = databaseName; User ID = userName; Password = userPassWord" Oracle数据库 "Provider = MSDAORA; Data Sourse = serverName; User ID = userName; Password = userPassword;" MS SQL数据库 "Provider = SQLOLEDB; Data Source = serverName; Initial Catalog = databaseName; User ID = user; Password = userPassword;" 注:格式字串中,“[]”为可选项,“{}”为必选项,,且等于符号“=”两边不应有空格符。

53 9.3ADO数据库编程 例如:若连接本地当前目录中的Access数据库文件student.mdb,则有:
m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=student.mdb;","","",0); 或者,先设置Connection对象的ConnectionString属性,然后调用Open: m_pConnection->ConnectionString="Provider=Microsoft.Jet.OLEDB.4.0; Data Source=student.mdb;"; m_pConnection->Open("","","",0); 再如,若连接ODBC数据源为"Database Example For VC++"的数据库,则有: m_pConnection->ConnectionString = "DSN=Database Example For VC++"; 3. 关闭连接 用MFC ClassWizard为CEx_ADOView映射WM_DESTROY消息,并添加下列代码: void CEx_ADOView::OnDestroy() { CListView::OnDestroy(); if (m_pConnection) m_pConnection->Close();// 关闭连接 }

54 9.3ADO数据库编程 4. 获取数据源信息 Connection对象除了建立与数据库服务器的连接外,还可以通过OpenSchema来获取数据源的自有信息,如:数据表信息、表字段信息以及所支持的数据类型等。下面的代码用来获取student.mdb的数据表名和字段名,并将信息内容显示在列表视图中: 代码中,__uuidof用来获取对象的的全局唯一标识(GUID)。ConnectionTimeout是连接超时属性,单位为秒。OpenSchema方法中的adSchemaColumns是一个预定义的枚举常量,用来获取与“列”(字段)相关的信息记录集。该信息记录集的主要字段名有“TABLE_NAME”、“COLUMN_NAME”;类似的,若在OpenSchema方法中指定adSchemaTables枚举常量,则返回的记录集的字段名主要有“TABLE_NAME”、“TABLE_TYPE”。 上述代码运行结果如图9.28所示。

55 9.3ADO数据库编程 图9.28 获取数据源表信息

56 9.3ADO数据库编程 9.3.2 Recordset对象使用
Recordset是用来从数据表或某一个SQL命令执行后获得记录集,通过Recordset对象的AddNew、Update和Delete方法可实现记录的添加、修改和删除等操作。 1. 读取数据表全部记录内容 下面的过程是将student.mdb中的course表中的记录显示在列表视图中。 (1)打开菜单资源IDR_MAINFRAME,在顶层菜单“查看”下添加一个“显示Course表记录”子菜单,将其ID号设为ID_VIEW_COURSE。 (2)按快捷键Ctrl+W,弹出ClassWizard对话框,向CEx_ADOView类添加ID_VIEW_COURSE的COMMAND消息映射,保留默认的映射函数OnViewCourse,并在该函数中添加下列代码: 代码中,_variant_t是一个用于COM的VARIANT类,VARIANT类型是一个C结构,由于它既包含了数据本身,也包含了数据的类型,因而它可以实现各种不同的自动化数据的传输。

57 9.3ADO数据库编程 (3)编译运行并测试,结果如图9.29所示。
图9.29 显示Course表所有记录 需要说明的是,上述代码是显示Course表的所有记录,若按条件显示记录,则为“条件查询”。Recordset对象可有下列两种方式来实现。 第一种方式是在调用Recordset的Open方法之前,设置Recordset对象的Filter属性来实现。Filter属性可以为由AND、OR、NOT等构成的条件查询字符串,它相当于 “SELECT…WHERE”SQL语句格式中WHERE的功能。例如: m_pRecordset->Filter = "coursename LIKE 'C%'"; // 查询课程名以C打头的记录 m_pRecordset->Filter = "coursehours>=40 AND credit=3";// 查询课时超过40且学分为3的记录

58 9.3ADO数据库编程 第二种方式是在Recordset的Open方法参数中进行设置。例如:
m_pRecordset->Open( "SELECT * FROM Course WHERE coursename LIKE 'C%'", m_pConnection.GetInterfacePtr(), adOpenDynamic, adLockOptimistic, adCmdText); 事实上,第二种方式就是Command方式。 2. 添加、修改和删除记录 记录的添加、修改和删除是通过Recordset对象的AddNew、Update和Delete方法来实现的。 例如,向course表中新添加一个记录可有下列代码: // 打开记录集 m_pRecordset->AddNew(); // 添加新记录 m_pRecordset->PutCollect("courseno",_variant_t(" ")); m_pRecordset->PutCollect("coursehourse",_variant_t(60)); m_pRecordset->Update(); // 使添加有效 // 关闭记录集 若从course表中删除一个记录可有下列代码: m_pRecordset->Delete(adAffectCurrent); // 删除当前行 m_pRecordset->MoveFirst(); // 调用Move方法,使删除有效

59 9.3ADO数据库编程 若从course表中修改一个记录可有下列代码: // 打开记录集
m_pRecordset->PutCollect("courseno",_variant_t(" ")); m_pRecordset->PutCollect("coursehourse",_variant_t(60)); m_pRecordset->Update(); // 使修改有效 // 关闭记录集 特别强调的是,数据库的表名不能与ADO的某些关键字串同名,例如:user等。另外,通常用Command对象执行SQL命令来实现数据表记录的查询、添加、更新和删除等操作,而用Recordset对象获取记录集,用来显示记录内容。 Command对象使用 Command对象用来执行SQL命令。下面先来简单介绍SQL几个常用语句。 1. SELECT语句 一个典型的SQL查询可以从指定的数据库表中“选择”信息,这时就需要使用SELECT语句来执行。SELECT语句格式如下: SELECT 字段名 FROM 表名 [WHERE子句] [ORDER BY子句] 它的最简单形式是: SELECT * FROM tableName

60 9.3ADO数据库编程 其中,星号(*)用来指定从数据库的tableName表中选择所有的字段(列)。若要从表中选择指定字段的记录,则将星号(*)用字段列表来代替,多个字段之间用逗号分隔。 需要说明的是: (1)在SELECT语句中,若用星号(*)来查询时,则结果集中的字段顺序与数据表中的字段顺序相同。 (2)若字段名称中含有空格,则该字段名称需要用方括号([])来括上。 (3)在不同的DBMS中,字段名称的命名规则不一定相同。但为了确保数据库的兼容性,一般不使用汉字、空格或短划线来作为字段名中的字符,并且也不能与SQL的关键字重名。 1)WHERE子句 在数据表查询SELECT语句中,经常还需要使用WHERE子句来设定查询的条件。它的一般形式如下: SELECT column1, column2,… FROM tableName WHERE condition WHERE子句中的条件可以<(小于)、>(大于)、<=(小于等于)、>=(大于等于)、=(等于)、<>(不等于)和LIKE等运算符。其中,LIKE用于匹配条件的查询,它可以使用“%”和“_(下划线)”等通配符,“%”表示可以出现0个或多个字符,“_”表示该位置处只能出现1个字符。例如: SELECT * FROM Score WHERE studentno LIKE ‘21%’ 则将Score表中所有学号以21打头的记录查询出来。注意,LIKE后面的字符串是以单引号来标识。再如: SELECT * FROM Score WHERE studentno LIKE ‘210105__’

61 9.3ADO数据库编程 则将Score表中所有学号以210105打头的,且学号为8位的记录查询出来。
WHERE子句中的条件还可用AND(与)、OR(或)以及NOT(非)运算符来构造复合条件查询,例如:若查询Score表中成绩(score)在70分到80分之间的记录,则可有下列语句: SELECT * FROM Score WHERE score<=80 AND score>=70 2) ORDER BY子句 在数据表查询SELECT语句中,若将查询到的记录进行排序,则可使用ORDER BY子句。如下面的形式: SELECT column1, column2,… FROM tableName [WHERE condition] ORDER BY col1, co2,… ASC | DESC 其中,ASC表示升序(从低到高),DESC表示降序(从高到低),col1、col2、…分别用来指定是按什么字段来排序。当指定多个字段时,则先按col1排序,当有相同col1的记录时,则相同的记录按col2排序,依此类推。 2. INSERT语句 INSERT语句是用来向表中插入一个新的记录。该语句的常用形式是: INSERT INTO tableName(col1,col2,col3,…,colN) VALUES (val1,val2,val3,…valN)

62 9.3ADO数据库编程 其中,tableName用来指定插入新记录的数据表,tableName后跟一对圆括号,包含一个以逗号分隔的列(字段)名的列表,VALUES后面的圆括号内是一个以逗号分隔的值列表,它与tableName后面的列名列表是一一对应的。需要说明的是,若某个记录 的某个字段值是字符串,则需要用单引号来括起来。例如: INSERT INTO Student(studentno,studentname) VALUES (' ', '张小峰') 将在Student中插入一个新行,其中studentno(学号)为“ ”,studentname(学生姓名)为“张小峰”,对于该记录的其它字段值,由于没有指定相应的值,其结果由系统决定。 3. UPDATE语句 UPDATE语句用于更新表中的数据。该语句的常用形式是: UPDATE tableName SET column1=value1, column2=value2,…,columnN=valueN WHERE condition 该语句可以更新tableName表中一行记录或多行记录的数据,这取决于WHERE后面的条件。关键字SET后面是以逗号分隔的“列名/值”列表。例如: UPDATE Student SET studentname = '王鹏' WHERE studentno = ' ' 将学号为“ ”的记录中的studentname字段内容更新为“王鹏”。

63 9.3ADO数据库编程 4. DELETE语句 DELETE语句用来从表中删除记录,其常用形式如下:
DELETE FROM tableName WHERE condition 该语句可以删除tableNam表中一行记录或多行记录,这取决于WHERE后面的条件。 需要说明的是,与UPDATE语句相同,DELETE语句后面的WHERE子句是可选的。但若不指定WHERE条件,则将删除全部记录,这也是很危险的,使用时要特别注意! 使用Command对象来执行这些SQL命令时,应遵循下列代码步骤: _CommandPtr pCmd; pCmd.CreateInstance(__uuidof(Command)); // 初始化Command指针 pCmd->ActiveConnection = m_pConnection; // 指向已有的连接 pCmd->CommandText ="SELECT * FROM course"; // 指定一个SQL查询 m_pRecordset = pCmd->Execute(NULL, NULL, adCmdText );// 执行命令,并返回一个记录集指针

64 9.4数据库相关的ActiveX控件 9.4.1 使用MSFlexGrid控件
Microsoft FlexGrid (MSFlexGrid) 控件可以显示网格数据,也可以对其进行操作。它提供了高度灵活的网格排序、合并和格式设置功能,网格中可以包含字符串和图片。利用MSFlexGrid可以将某个表的所有记录显示。下面以示例的形式来说明其使用过程,结果如图9.30所示。 图9.30 MSFlexGrid控件的结果

65 9.4数据库相关的ActiveX控件 [例Ex_Grid] 使用MSFlexGrid控件 1)将控件的类添加到项目中
(1)用MFC AppWizard创建一个单文档应用程序Ex_Grid。图9.31 “插入ActiveX控件”对话框 (2)在向导的第2步对话框中,选中“查看数据库使用文件支持”项,单击[数据源]按钮,弹出“Database Options”对话框,从中选择ODBC的数据源“Database Example For VC++”。保留其他默认选项,单击[OK]按钮,在弹出的“Select Database Tables”对话框中,选择要使用的表score。 (3)单击[OK]按钮,又回到了向导的第2步对话框。单击[完成]按钮。开发环境自动打开表单视图的对话框资源模板IDD_EX_GRID_FORM。 (4)在打开的表单资源模板中右击鼠标,从弹出的快捷菜单中选择“Insert Active Control”命令,出现如图9.31所示“插入 Active 控件”对话框。 (5)在对话框的控件列表中选择Micorsoft FlexGrid Control控件,单击[确定]按钮,该控件就添加到表单资源中,参看图9.30,调整其大小和位置。 图9.31 “插入ActiveX控件”对话框

66 9.4数据库相关的ActiveX控件 2)修改MSFlexGrid控件属性
右击添加的Micorsoft FlexGrid Control控件,从弹出的菜单中选择“属性”或“属性MSFlexGrid Object”命令均可打开该控件的属性对话框,如图9.32所示。 图9.32 MSFlexGrid控件的属性对话框 MSFlexGrid控件的属性要比Visual C++的控件属性要多,如“General”、“通用”、“样式”、“字体”、“颜色”、“图片”等。这些属性不仅能设置控件的字体、颜色,而且能设置网格的行数和列数以及其他的功能。

67 9.4数据库相关的ActiveX控件 3)编程控制 (1)保留默认的属性及其控件标识符IDC_MSFLEXGRID1。
(2)用MFC ClassWizard在CEx_GridView类中为刚才添加的MSFlexGrid控件设置一个相关联的控件变量m_MSFGrid。需要说明的是,在此步骤中会出现一些对话框,用于询问是否要添加相关控件的类代码等,选择[是]。 (3)在CEx_ODBCView类的OnInitialUpdate函数中添加下列代码: (4)编译运行。 RemoteData和DBGrid控件 通过被绑定的控件提供对存储在远程 ODBC 数据源中数据的存取。RemoteData 控件允许在某一记录集的行与行之间移动,且允许显示和操作来自于被绑定的控件各行里的数据。通过RemoteData控件,能够: ● 建立起与基于其本身属性的数据源的连接。 ● 创建RDO的结果集。 ● 把当前行的数据传送给相应被绑定的控件。 ● 允许对当前行指针进行定位。 ● 将对被绑定的控件所做的任何更改反传给数据源。

68 9.4数据库相关的ActiveX控件 [例Ex_DBCtrl] 使用RemoteData和DBGrid控件
(1)用MFC AppWizard创建一个默认的单文档应用程序Ex_DBCtrl,但在向导的第6步将CEx_DBCtrlView的基类由默认的CView选择为CFormView类。 (2)在打开的表单资源模板中右击鼠标,从弹出的快捷菜单中选择“Insert Active Control”命令,出现“插入 Active 控件”对话框。 (3)在对话框的控件列表中选择Microsoft RemoteData Control,单击[确定]按钮,RemoteData控件就添加到表单资源中,调整其大小和位置。 (4)右击该控件,从弹出的菜单中选择“属性”或“Properties RemoteDataCtl Object”命令,打开该控件的属性对话框(参看图9.34)。 (5)在“Control(控件)”页面中,从“DataSource”的下拉列表中选择所需要的数据源名 “Database Example For VC++”。 (6)在“SQL”编辑框中键入SQL操作语句“SELECT * FROM score ORDER BY studentno”是检索学生课程成绩表score的所有记录,并按学号排序。设置的结果如图9.34所示。

69 9.4数据库相关的ActiveX控件 图9.34 设置RemoteData控件的Control属性 图9.35 设置CursorDriver属性 (7)将RemoteData控件属性对话框切换到All页面,单击CursorDriver选项,在右侧的组合框中将其属性选择“1-ODBC cursor”。结果如图9.35所示。需要说明的是,由于该控件在这里是用于ODBC的联接,因此必须使用ODBC的游标驱动程序(CursorDriver )才能使其联接成功。

70 9.4数据库相关的ActiveX控件 (8)再次右击表单资源模板,从弹出的快捷菜单中选择“Insert Active Control”命令,在弹出的 “插入 Active 控件”对话框中找到要添加的DBGrid控件,单击[确定]按钮。 (9)参看图9.38,调整添加的DBGrid控件的大小和位置,打开该控件的属性对话框,将数据源(DataRource)设置为RemoteData控件IDC_REMOTEDATACTL1,如图9.36所示。 图9.36 设置DBGrid控件的数据源

71 9.4数据库相关的ActiveX控件 (10)在对话框编辑器的控件布局栏上,单击测试工具按钮(),结果如图9.37所示。按ESC键结束测试。
图9.37 DBGrid控件测试结果 图9.38 Ex_DBCtrl运行结果 (11)编译运行并测试,结果如图9.38。 需要说明的是,大多数情况下,常把RemoteData控件的“显示(Visible)”属性设为不选中,以使DBGrid控件操作看起来是一个独立的界面。

72 9.5综合应用 在这个综合应用程序中,是使用ADO来操作相应的数据表,并在一个基于CListView视图的单文档应用程序Ex_A9中实现。主要任务有: (1)用Access创建一个数据库student.mdb,添加数据表student,如表9.8所示。表中上部分是数据表的记录内容,下部分是数据表的结构内容。 表9.8 学生基本信息表(student)及其表结构 姓名 (studentname) 学号 (sudentno) 性别 (xb) 出生年月 (birthday) 专业 (special)  李明  王玲  张芳  陈涛 true false 电气工程及其自动化 机械工程及其自动化 序 号 字段名称 数据类型 字段大小 小数位 字段含义 1 2 3 4 5 studentname studentno xb birthday special 文本 是/否 日期/时间 20 10 50

73 9.5综合应用 (2)在主菜单中添加“学生信息(&S)”顶层菜单,在该菜单添加“添加(&U)”子菜单。当选择“添加(&U)”子菜单后,出现“学生信息”对话框,单击[添加]后,记录添加到student表中,并自动更新列表视图的列表项。 (3)在列表视图的列表项中,右击鼠标,弹出“学生信息”对话框,单击[修改]按钮,student表中相关记录被修改,同时更新列表视图的列表项。如图9.39所示。 图9.39 右击鼠标弹出修改学生信息对话框

74 9.5综合应用 [例Ex_A9] 使用ADO来操作数据表 1)创建并添加对话框
(1)用MFC AppWizard创建一个单文档应用程序Ex_A9,在创建的第6步将视图的基类选择为CListView。 (2)添加一个对话框资源,打开属性对话框将其字体设置为“宋体9号”,标题定为“学生信息”,ID号设为IDD_STUINFO,创建对话框类CStuInfoDlg。 (3)打开对话框网格,将[确定]和[取消]按钮放置到对话框的下面,按图9.39的控件布局,为对话框添加如表9.9所示的一些控件。 表9.9 添加的控件 添加的控件 ID号 标 题 其他属性 编辑框(姓名) IDC_EDIT_NAME 默认 编辑框(学号) IDC_EDIT_NO 单选按钮(男) IDC_RADIO_M 单选按钮(女) IDC_RADIO_W 日期时间控件(出生年月) IDC_DATETIMEPICKER1 —— 编辑框(专业) IDC_EDIT_SPEC

75 9.5综合应用 (4)打开MFC ClassWizard的Member Variables页面,在Class name中选择CStuInfoDlg,选中所需的控件ID号,双击鼠标或单击Add Variables按钮。依次为下列控件添加成员变量,如表9.10所示。 表9.10 添加的控件变量 控件ID号 变量类别 变量类型 变量名 范围和大小 IDC_EDIT_NAME Value CString m_strName ­20 IDC_EDIT_NO m_strNO 20 IDC_DATETIMEPICKER1 CTime m_tBirth —— IDC_EDIT_SPEC m_strSpec 80

76 9.5综合应用 (5)为CStuInfoDlg类添加一个公有型CString类型成员变量m_strSex,用来保存学生的性别,再添加一个公有型CString类型成员变量m_strOKText,用来设置[确定]按钮的标题。 (6)在CStuInfoDlg类构造函数中将m_strSex的初值设为“男”,m_strOKText的初值设为“添加”。 (7)用MFC ClassWizard分别为CStuInfoDlg类添加单选按钮IDC_RADIO_M和IDC_RADIO_W的BN_CLICKED消息映射,并在映射函数中添加下列代码: void CStuInfoDlg::OnRadioM() { m_strSex = "男"; } void CStuInfoDlg::OnRadioW() m_strSex = "女";

77 9.5综合应用 (8)用MFC ClassWizard为CStuInfoDlg类添加WM_INITDIALOG消息映射,并添加下列初始化代码: BOOL CStuInfoDlg::OnInitDialog() { CDialog::OnInitDialog(); if (m_strSex == "女") CheckRadioButton(IDC_RADIO_M, IDC_RADIO_W, IDC_RADIO_W); else CheckRadioButton(IDC_RADIO_M, IDC_RADIO_W, IDC_RADIO_M); m_strOKText.TrimLeft(); GetDlgItem(IDOK)->SetWindowText(m_strOKText); if (m_strOKText=="修改") GetDlgItem(IDC_EDIT_NAME)->EnableWindow( FALSE );// 不允许修改姓名 GetDlgItem(IDC_EDIT_NO)->EnableWindow( FALSE ); // 不允许修改学号 } return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE

78 9.5综合应用 (9)用MFC ClassWizard为CStuInfoDlg类添加IDOK按钮的BN_CLICKED消息映射,并添加下列代码: void CStuInfoDlg::OnOK() { UpdateData(); m_strName.TrimLeft(); m_strNO.TrimLeft(); if (m_strName.IsEmpty()) MessageBox("必须要有姓名!"); else if (m_strNO.IsEmpty()) MessageBox("必须要有学号!"); else CDialog::OnOK(); } 2)添加对ADO的支持及其他代码 (1)在CEx_A9View::PreCreateWindow函数添加下列代码,用来设置列表视图内嵌列表控件的风格: BOOL CEx_A9View::PreCreateWindow(CREATESTRUCT& cs) cs.style |= LVS_REPORT | LVS_SHOWSELALWAYS ; return CListView::PreCreateWindow(cs);

79 9.5综合应用 (2)在stdafx.h文件中添加对ADO支持的代码:
#endif // _AFX_NO_AFXCMN_SUPPORT #include <afxcmn.h> // MFC support for Windows Common Controls #import "C:\Program Files\Common Files\System\ADO\msado15.dll" \ no_namespace rename("EOF", "adoEOF") #include <icrsint.h> //{{AFX_INSERT_LOCATION}} (3)在CEx_A9App::InitInstance函数中添加下列代码,用来对ADO的COM环境进行初始化: BOOL CEx_A9App::InitInstance() { ::CoInitialize(NULL); AfxEnableControlContainer(); … } (4)在Ex_A9View.h文件中为CEx_A9View定义ADO连接对象指针变量: public: _ConnectionPtr m_pConnection; (5)为CEx_A9View类添加一个成员函数DispAllRec,用于显示数据表Student的所有记录,其代码如下:

80 9.5综合应用 (6)在CEx_A9View::OnInitialUpdate中添加下列初始化代码: (7)编译运行。
void CEx_A9View::OnInitialUpdate() { CListView::OnInitialUpdate(); CListCtrl& m_ListCtrl = GetListCtrl(); m_ListCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); m_pConnection.CreateInstance(__uuidof(Connection)); // 初始化Connection指针 m_pConnection->ConnectionString ="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=..\\student.mdb;"; // 此句代码在一行书写 m_pConnection->ConnectionTimeout = 30; // 允许连接超时时间,单位为秒 HRESULT hr = m_pConnection->Open("","","",0); if (hr != S_OK) MessageBox("无法连接指定的数据库!"); DispAllRec( ); } (7)编译运行。

81 9.5综合应用 3)学生信息记录的添加和修改 (1)打开菜单资源,添加一个顶层菜单“学生信息(&S)”,在该菜单下添加一个子菜单项“添加(&A)”,将该菜单标识设为ID_STUINFO_ADD。 (2)用MFC ClassWizard为CEx_A9View类添加该菜单的COMMAND消息映射,并添加下列代码: (3)在Ex_ADOView.cpp文件的前面添加CStuInfoDlg类的包含语句: #include "Ex_A9View.h" #include "StuInfoDlg.h" (4)用MFC ClassWizard为CEx_A9View类添加WM_RBUTTONDOWN (右击鼠标)消息映射,并添加下列代码: (5)编译运行并测试。

82 习题 1. MFC提供的数据库编程方式有哪些?它们有何不同? 2. 用MFC进行ODBC的编程过程是怎样的? 3. 什么是动态行集(Dynasets)和快照集(Snapshots)?它们的根本区别是什么? 4. 在用CRecordSet成员函数进行记录的编辑、添加和删除等操作时,如何使操作有效? 5. 若对一个数据表进行排序和检索,利用CRecordSet的成员变量m_strFilter和m_strSort如何操作? 6. 如何处理多个表?试叙述其过程及其技巧。 7. 如何用ADO的Command对象来实现对数据表的记录操作? 8. 什么是ActiveX控件?当Visual C++ 6.0安装后,用于数据库的ActiveX控件有哪些? 9. RemoteData和DBGrid控件是如何关联的?又是如何进行数据库的操作的?


Download ppt "第9章数据库应用 9.1数据库和ODBC操作 9.2MFC ODBC应用编程 9.3ADO数据库编程 9.4数据库相关的ActiveX控件"

Similar presentations


Ads by Google