实验十三 数据库(1)
实验目的和要求
对于大量数据处理,采用数据库更为安全简便。例如,对于学生信息管理系统,常常需要处理学生的基本信息、课程成绩以及课程信息等,这些信息用数据库表的形式来描述更为清晰。本实验将在列表视图的显示视图中显示学生的基本信息内容。
(1)用Microsoft Access 2003创建一个数据库main.mdb,含有4个数据表:学生基本信息表student、课程信息表course、课程成绩表score和专业数据表special(具体表结构见教材附录),并建立ODBC联接。
(2)创建学生课程成绩表score的CRecordSet派生类CScoreSet。
(3)在主菜单中添加“课程成绩(&S)”顶层菜单,在该菜单添加“添加(&A)”、“删除(&D)”和“修改(&C)”子菜单。
(4)选择“添加”菜单命令,弹出“学生课程成绩”对话框,单击“添加”按钮,在score表中添加一条记录,并自动更新列表视图显示的内容。如图9.1所示。
图9.1 学生课程信息输入及显示 图9.2 学生课程信息修改及显示
(5)当选定列表视图中的某个列表项后,选择“删除”菜单命令,弹出消息对话框,询问是否确认删除,单击“确定”后,当前选择的列表项所在的数据表记录被删除,并自动更新列表视图显示的内容。
(6)当选定列表视图中的某个列表项后,选择“修改”菜单命令,弹出“学生课程成绩”对话框,对话框的内容就是当前选择的列表项中的内容,修改后,单击“修改”按钮,当前选择的列表项所在的数据表记录被修改,并自动更新列表视图显示的内容。如图9.2所示。
实验准备和说明
(1)具备知识:MFC的ODBC常用编程。
(2)创建本次实验工作文件夹“…\Visual C++程序\实验\实验9”。
(3)创建数据库所在的文件夹“…\Visual C++程序\实验\实习”。
实验内容和步骤
这里以Microsoft Access 2003为例说明数据库和数据表的创建过程。
② 启动Microsoft Access 2003。
② 选择“文件”→“新建”菜单,在右边任务窗格中单击“空数据库”,弹出一个对话框,将文件路径指定到“…\Visual C++程序\实验\实习”,指定数据库名main.mdb。单击“创建”按钮,出现如图9.3所示的数据库设计窗口。
图9.3 数据库设计窗口 图9.4 表设计界面
③ 双击“使用设计器创建表”,出现如图9.4所示的表设计界面。其中,单击数据类型框的下拉按钮,可在弹出的列表中选择适当的数据类型。在下方的常规页面中可以设置字段大小、格式等内容。
④ 按表9.1添加字段名和数据类型,关闭表设计界面,弹出一个消息对话框,询问是否保存刚才设计的数据表,单击“是(Y)”按钮,出现如图9.5所示的对话框,在表名称中输入score,单击““确定”按钮。此时出现一个消息对话框,用来询问是否要为表创建主关键词,单击[否(N)”按钮。注意:若单击“是(Y)”按钮,则系统会自动为表添加另一个字段ID。
表9.1 学生课程成绩表(score)结构
⑤ 在数据库设计窗口中,双击score表,就可向数据表输入记录数据。如图9.6是记录输入的结果。
图9.5 保存数据表 图9.6 在score表中添加的记录
⑥ 按照上面的过程,添加学生基本信息表student、课程信息表course和专业数据表special,并输入如图9.7所示的记录。
图9.7 各数据表添加的记录
⑦ 关闭Microsoft Access 2003。
① 运行ODBC组件,进入ODBC数据源管理器。
② 单击“添加”按钮,弹出有一驱动程序列表的“创建新数据源”对话框,在该对话框中选择Microsoft Access Driver。
③ 单击“完成”按钮,进入指定驱动程序的安装对话框,数据源名称设为“学生信息管理系统”,单击“选择”按钮将本实验中的main.mdb数据库。
④ 单击“确定”按钮,刚才创建的用户数据源被添加在“ODBC数据源管理器”的“用户数据源”列表中。
启动Visual C++ 6.0系统。
① 用MFC AppWizard创建一个单文档应用程序Ex_Student,在向导的第六步将CEx_StudentView的基类由CView改为CListView。
② 在CEx_StudentView::PreCreateWindow函数添加下列代码,用来设置列表视图内嵌列表控件的风格:
BOOL CEx_StudentView::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= LVS_REPORT; // 报表风格
return CListView::PreCreateWindow(cs);
}
① 在Ex_Student中添加学生基本信息表student、课程信息表course、课程成绩表score和专业数据表special的CRecordSet派生类CStudentSet、CCourseSet、CScoreSet和CSpecialSet。
② 在stdafx.h文件中添加CRecordSet头文件包含#include <afxdb.h>。
① 复制对话框资源IDD_SCORE。
② 复制对话框类文件Score.h和Score.cpp,并添加到工程中。
③ 将Score.cpp文件前面的头文件包含#include "Ex_List.h"修改为#include "Ex_Student.h"。
① 打开菜单资源IDR_MAINFRAME,添加“课程成绩(&S)”顶层菜单,在该菜单添加“添加(&A)”(ID_SCORE_ADD)、“删除(&D)”(ID_SCORE_DEL)和“修改(&C)”(ID_SCORE_CHANGE)子菜单。
② 在CEx_StudentView类添加成员函数DeleteAllColumn,用来删除列表视图的标题头,以便能再创建标题头显示不同的信息。
void CEx_StudentView::DeleteAllColumn()
{
CListCtrl& m_ListCtrl = GetListCtrl();
int nCount = 0;
CHeaderCtrl* pHeaderCtrl = m_ListCtrl.GetHeaderCtrl();
if ( pHeaderCtrl!= NULL)
nCount = pHeaderCtrl->GetItemCount();
for (int i=0;i < nCount;i++)
m_ListCtrl.DeleteColumn(0);
}
③ 在CEx_StudentView类添加成员函数DispScoreInfo,用来显示课程成绩信息。
void CEx_StudentView::DispScoreInfo(CString strFilter)
{
DeleteAllColumn(); // 删除表头
CListCtrl& m_ListCtrl = GetListCtrl();
CString strHeader[]={"学号", "课程号","成绩","学分"};
for (int nCol=0; nCol<sizeof(strHeader)/sizeof(CString); nCol++)
m_ListCtrl.InsertColumn(nCol,strHeader[nCol],LVCFMT_LEFT,100);
m_ListCtrl.DeleteAllItems(); // 删除所有的列表项
CScoreSet sSet;
sSet.m_strFilter = strFilter;
sSet.m_strSort = "studentno,course";
sSet.Open();
int nItem = 0;
CString str;
while (!sSet.IsEOF()) {
m_ListCtrl.InsertItem( nItem, sSet.m_studentno); // 插入学号
m_ListCtrl.SetItemText( nItem, 1, sSet.m_course);
str.Format("%4.1f", sSet.m_score);
m_ListCtrl.SetItemText( nItem, 2, str);
str.Format("%3.1f", sSet.m_credit);
m_ListCtrl.SetItemText( nItem, 3, str);
nItem++;
sSet.MoveNext();
}
sSet.Close();
}
④ 在Ex_StudentView.cpp前面添加CScoreSet类和CScoreDlg的头文件包含:
#include "Ex_StudentDoc.h"
#include "Ex_StudentView.h"
#include "ScoreSet.h"
#include "ScoreDlg.h"
⑤ 为CEx_StudentView类添加一个成员变量m_strFilter,类型为CString。
⑥ 用MFC ClassWizard在CEx_StudentView类中映射菜单ID_SCORE_ADD的COMMAND消息,并添加下列代码:
void CEx_StudentView::OnScoreAdd()
{
CScoreDlg dlg;
if (dlg.DoModal()!= IDOK) return;
CScoreSet sSet;
sSet.Open();
sSet.AddNew();
sSet.m_course = dlg.m_strCourseNo;
sSet.m_studentno = dlg.m_strStuNo;
sSet.m_score = dlg.m_fScore;
sSet.m_credit = dlg.m_fCredit;
sSet.Update();
sSet.Requery();
sSet.Close();
// 更新列表视图
MessageBox("稍等几秒钟后,单击“确定”按钮!","特别提示",MB_OK|MB_
ICONINFORMATION);
m_strFilter.Format("studentno='%s'", dlg.m_strStuNo);
// 打开并显示所有学号为dlg.m_strStuNo的记录
DispScoreInfo( m_strFilter );
}
⑦ 为CEx_StudentView类添加成员函数GetListCtrlCurSel,用来获取当前选择的列表项索引,其代码如下:
int CEx_StudentView::GetListCtrlCurSel()
{
CListCtrl& m_ListCtrl = GetListCtrl();
POSITION pos;
pos = m_ListCtrl.GetFirstSelectedItemPosition();
if (pos == NULL){
MessageBox("你还没有选中列表项!");
return -1;
}
return m_ListCtrl.GetNextSelectedItem( pos );
}
⑧ 用MFC ClassWizard在CEx_StudentView类中映射菜单ID_SCORE_DEL的COMMAND消息,并添加下列代码:
void CEx_StudentView::OnScoreDel()
{
int nItem = GetListCtrlCurSel();
if (nItem<0) return;
CListCtrl& m_ListCtrl = GetListCtrl();
CString strItem, str;
strItem = m_ListCtrl.GetItemText( nItem, 0 );
str.Format("你确实要删除 %s 列表项(记录)吗?", strItem );
if ( IDOK != MessageBox(str, "删除确认", MB_ICONQUESTION | MB_OKCANCEL )) return;
CString strStudentNO = m_ListCtrl.GetItemText( nItem, 0 );
CString strCourseNO = m_ListCtrl.GetItemText( nItem, 1 );
CScoreSet infoSet;
infoSet.m_strFilter.Format("studentno='%s' AND course='%s'", strStudentNO, strCourseNO);
infoSet.Open();
if (!infoSet.IsEOF()) {
CRecordsetStatus status;
infoSet.GetStatus(status); // 获取当前记录集状态
infoSet.Delete(); // 删除当前记录
if (status.m_lCurrentRecord==0) // 若当前记录索引号为0(0表示第一条记录)
infoSet.MoveNext(); // 下移一个记录
else
infoSet.MoveFirst(); // 移动到第一个记录处
}
if (infoSet.IsOpen()) infoSet.Close();
// 更新列表视图
MessageBox("稍等几秒钟后,单击“确定”按钮!","特别提示",MB_OK|MB_
ICONINFORMATION);
DispScoreInfo( m_strFilter );
}
⑨ 用MFC ClassWizard在CEx_StudentView类中映射菜单ID_SCORE_CHANGE的COMMAND消息,并添加下列代码:
void CEx_StudentView::OnScoreChange()
{
int nItem = GetListCtrlCurSel();
if (nItem<0) return;
CListCtrl& m_ListCtrl = GetListCtrl();
CString strStudentNO = m_ListCtrl.GetItemText( nItem, 0 );
CString strCourseNO = m_ListCtrl.GetItemText( nItem, 1 );
CScoreSet sSet;
sSet.m_strFilter.Format("studentno='%s' AND course='%s'", strStudentNO, strCourseNO);
sSet.Open();
CScoreDlg dlg;
dlg.m_strOKText = "修改";
dlg.m_strCourseNo = sSet.m_course;
dlg.m_strStuNo = sSet.m_studentno;
dlg.m_fScore = sSet.m_score;
dlg.m_fCredit = sSet.m_credit;
if (IDOK != dlg.DoModal()) {
if (sSet.IsOpen()) sSet.Close();
return;
}
sSet.Edit();
sSet.m_score = dlg.m_fScore; // 只能修改成绩
sSet.Update();
sSet.Requery();
if (sSet.IsOpen()) sSet.Close();
// 更新列表视图
MessageBox("稍等几秒钟后,单击“确定”按钮!","特别提示",MB_OK|MB_
ICONINFORMATION);
m_strFilter.Format("studentno='%s'", dlg.m_strStuNo);
// 打开并显示所有学号为dlg.m_strStuNo的记录
DispScoreInfo( m_strFilter );
}
⑩ 在CEx_StudentView::OnInitialUpdate函数中添加下列代码:
void CEx_StudentView::OnInitialUpdate()
{
CListView::OnInitialUpdate();
DispScoreInfo( "" );
}
(11)编译运行并测试。
分析上述运行结果以及思考与练习,写出实验报告。
实验十三 数据库(2)
实验目的和要求
本次实验在实验9的基础上完成进行。
(1)修改“学生课程成绩”对话框及其CScoreDlg类代码,使其能根据课程名称确定课程号和学分。
图10.1 修改后的“学生课程成绩”对话框
(2)创建“查询条件”对话框及其CSeekDlg类,并根据查询条件在列表视图中显示出满足条件的学生课程成绩记录,如图10.2所示。
图10.2 查询
实验准备和说明
(1)具备知识:MFC的ODBC多个表的编程方法。
(2)创建本次实验工作文件夹“…\Visual C++程序\实验\实验10”。
(3)将实验9的Ex_Student工程复制到本次实验工作文件夹中。
实验内容和步骤
① 启动Visual C++ 6.0,打开单文档应用程序Ex_Student。
② 将项目工作区窗口切换到ResourceView页面,打开对话框资源IDD_SCORE。按图10.1所示的控件布局,向对话框再添加一个组合框控件(IDC_COMBO_NAME)和4个用于显示课程专业、类型、课时数和开课学期数据的静态文本控件,将其ID号分别设为IDC_STATIC_SPECIAL、IDC_STATIC_TYPE、IDC_STATIC_HOURS和IDC_STATIC_TERM,它们的属性均设为水平和垂直居中,其他控件可直接从图10.2中看出。
③ 打开MFC ClassWizard的Member Variables页面,在Class name中选择CStuDlg,选中所需的控件ID号,双击鼠标或单击Add Variables按钮。再为表10.1控件添加控件 变量。
表10.1 控件变量
① 在ScoreDlg.cpp文件前面添加CScoreSet类的头文件包含:
#include "ScoreDlg.h"
#include "CourseSet.h"
② 在CScoreDlg::OnInitDialog函数中添加下列代码:
BOOL CScoreDlg::OnInitDialog()
{
CDialog::OnInitDialog();
if (!m_strOKText.IsEmpty())
{
GetDlgItem( IDOK )->SetWindowText( m_strOKText );
GetDlgItem( IDC_COMBO_NAME )->EnableWindow( FALSE );
GetDlgItem( IDC_EDIT_COURSENO )->EnableWindow( FALSE );
GetDlgItem( IDC_EDIT_CREDIT )->EnableWindow( FALSE );
} else {
// 将课程信息表的课程名称添加到组合框中
CCourseSet cSet;
cSet.Open();
while (!cSet.IsEOF()) {
int nIndex = m_comboName.AddString(cSet.m_coursename);
DWORD dCourseNo = atol(cSet.m_courseno);
m_comboName.SetItemData( nIndex, dCourseNo );
cSet.MoveNext();
}
if (cSet.IsOpen()) cSet.Close();
m_comboName.SetCurSel(0);
OnSelchangeComboName();
}
return TRUE; // return TRUE unless you set the focus to a control
}
③ 用MFC ClassWizard为控件IDC_COMBO_NAME映射CBN_SELCHANGE的消息,并添加下列代码:
void CScoreDlg::OnSelchangeComboName()
{
int nIndex = m_comboName.GetCurSel();
if (nIndex == CB_ERR) return;
CString str;
m_comboName.GetLBText( nIndex, str);
DWORD dCourseNo = m_comboName.GetItemData( nIndex );
CCourseSet cSet;
cSet.m_strFilter.Format("courseno='%u'", dCourseNo);
cSet.Open();
if (!cSet.IsEOF()){
m_strType = cSet.m_coursetype;
m_strSpecial = cSet.m_special;
m_strHours.Format("%d", cSet.m_hours);
m_strTerm.Format("%d", cSet.m_openterm);
m_strCourseNo = cSet.m_courseno;
m_fCredit = cSet.m_credit;
}
cSet.Close();
UpdateData(FALSE);
}
④ 编译运行并测试。
① 按Ctrl+R快捷键,弹出“插入资源”对话框,在资源类型列表中选择Dialog,单击“新建”按钮。
② 将该对话框资源的ID设为IDD_DIALOG_SEEK,标题设为“查询条件”,字体设为“宋体,9号”。
③ 将OK和Cancel按钮的标题改为“确定”和“取消”。
④ 打开对话框网格,参看图10.2的控件布局,为对话框添加如表10.2所示的一些控件。
表10.2 查询条件对话框添加的控件
⑤ 按Ctrl+W快捷键或双击对话框资源模板的空白处,为IDD_DIALOG_SEEK创建一个对话框类CSeekDlg。
⑥ 打开ClassWizard的Member Variables页面,看Class name是否是CSeekDlg,选中所需的控件ID号,双击鼠标。依次为表10.3控件增加成员变量。
表10.3 控件变量
⑦ 为CSeekDlg类添加下列成员变量,并在构造函数中将m_bTerm设为TRUE:
public:
BOOL m_bTerm; // 是否存在学期查询条件
int m_nTerm; // 学期数
CStringArray m_strItemArray; // 由外部提供的IDC_COMBO1数据存放此变量中
⑧ 用MFC ClassWizard为CSeekDlg类映射WM_INITDIALOG消息,并添加下列 代码:
BOOL CSeekDlg::OnInitDialog()
{
CDialog::OnInitDialog();
if (!m_strTitle.IsEmpty()) UpdateData( FALSE );
m_comboSeek.ResetContent();
for (int i=0; i<m_strItemArray.GetSize(); i++)
{
int nIndex = m_comboSeek.FindString( 0, m_strItemArray[i] );
if (nIndex == CB_ERR)
m_comboSeek.AddString( m_strItemArray[i] );
}
m_comboSeek.SetCurSel(0);
if (m_bTerm) {
m_comboTerm.ResetContent();
CString strTerm;
for (i=0; i<=8; i++)
{
if (i==0) strTerm = "所有学期";
else
strTerm.Format("第%d学期", i);
int nIndex = m_comboTerm.AddString(strTerm);
m_comboTerm.SetItemData( nIndex, i );
}
m_comboTerm.SetCurSel(0);
OnSelchangeCombo2();
} else {
GetDlgItem(IDC_STATIC_TERM)->EnableWindow( FALSE );
GetDlgItem(IDC_COMBO2)->EnableWindow( FALSE );
}
return TRUE; // return TRUE unless you set the focus to a control
}
⑨ 用MFC ClassWizard为控件IDC_COMBO2映射CBN_SELCHANGE消息,并添加下列代码:
void CSeekDlg::OnSelchangeCombo2()
{
int nIndex = m_comboTerm.GetCurSel();
if (nIndex == CB_ERR) return;
m_nTerm = m_comboTerm.GetItemData( nIndex );
}
① 在Ex_StudentView.cpp文件前面,添加CSeekDlg类的头文件包含:
#include "ScoreSet.h"
#include "ScoreDlg.h"
#include "SeekDlg.h"
#include "CourseSet.h"
② 打开菜单资源,在“课程成绩”菜单下添加一个子菜单“查询(&Q)”,设其ID为ID_SCORE_SEEK。
③ 用MFC ClassWizard在CEx_StudentView类中映射菜单ID_SCORE_SEEK的COMMAND消息,并添加下列代码:
void CEx_StudentView::OnScoreSeek()
{
CSeekDlg dlg;
dlg.m_strTitle = "选择学号:";
// 获取列表项第一列内容
CString strTemp;
CListCtrl& m_ListCtrl = GetListCtrl();
int nItemCount = m_ListCtrl.GetItemCount();
dlg.m_strItemArray.RemoveAll();
for ( int nItem=0; nItem<nItemCount; nItem++){
strTemp = m_ListCtrl.GetItemText(nItem, 0);
dlg.m_strItemArray.Add( strTemp );
}
if (IDOK != dlg.DoModal()) return;
CString str;
str.Format("studentno = '%s'", dlg.m_strSeek);
DispScoreAndCourseInfo( str, dlg.m_nTerm);
}
④ 为CEx_StudentView类添加成员函数DispScoreAndCourseInfo(CString strFilter, int nOpenTerm),用于根据实现多表记录的访问,并根据查询条件显示学生课程成绩的更多 信息。
void CEx_StudentView::DispScoreAndCourseInfo(CString strFilter, int nOpenTerm)
{
DeleteAllColumn(); // 删除表头
CListCtrl& m_ListCtrl = GetListCtrl();
CString strHeader[]={"学号", "课程号", "课程所属专业", "课程名称","课程类别","开课学期","课时数","学分","成绩"};
int nLong[] = {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]);
m_ListCtrl.DeleteAllItems(); // 删除所有的列表项
CScoreSet sSet;
sSet.m_strFilter = strFilter;
sSet.m_strSort = "studentno";
sSet.Open();
int nItem = 0;
CString str;
while (!sSet.IsEOF()) {
CCourseSet cSet;
if (nOpenTerm == 0) // 所有学期
cSet.m_strFilter.Format("courseno='%s'", sSet.m_course);
else
cSet.m_strFilter.Format("courseno='%s' AND openterm=%d",sSet.m_course,
nOpenTerm);
cSet.Open();
UINT i;
if (!cSet.IsEOF()){
// 通过Get获取相关字段记录内容
m_ListCtrl.InsertItem( nItem, sSet.m_studentno); // 插入学号
for (i=0; i<cSet.m_nFields; i++) {
cSet.GetFieldValue(i, str); // 获取指定字段值
m_ListCtrl.SetItemText( nItem, i+1, str);
}
str.Format("%0.1f", sSet.m_score);
m_ListCtrl.SetItemText( nItem, i+1, str);
nItem++;
}
cSet.Close();
sSet.MoveNext();
}
sSet.Close(); }
⑤ 编译运行并测试,结果如图10.2所示。
分析上述运行结果以及思考与练习,写出实验报告。
图10.3 “专业数据字典”对话框
华北科技学院计算机学院综合性实验实验报告课程名称程序设计语言(C)实验学期20##至20##学年第二学期学生所在学院建筑工程学院年…
计算机系综合性实验实验报告课程名称程序设计语言C实验学期20xx至20xx学年第二学期学生所在系部年级专业班级学生姓名学号任课教师…
FileQuit实验名称TURBOC环境认识1实验时间316实验地点54232ALTX二主要内容输入C语言程序设计教材中例题熟悉C…
实验报告实验报告1课程名称c语言程序设计指导老师黄瑜成绩这项留空实验项目名称c程序的运行环境和运行方法实验类型验证性实验试验组成员…
实验十三数据库1实验目的和要求对于大量数据处理采用数据库更为安全简便例如对于学生信息管理系统常常需要处理学生的基本信息课程成绩以及…
学号:__________姓名:__________班级:__________日期:__________指导教师:________…
#includestdio.h#includemath.h#includewindows.h#definer10#defineR1…
华北科技学院计算机学院综合性实验实验报告课程名称程序设计语言(C)实验学期20##至20##学年第二学期学生所在学院建筑工程学院年…
计算机系综合性实验实验报告课程名称程序设计语言C实验学期20xx至20xx学年第二学期学生所在系部年级专业班级学生姓名学号任课教师…
计算机系综合性实验实验报告课程名称程序设计语言C实验学期20xx至20xx学年第二学期学生所在系部年级专业班级学生姓名学号任课教师…
——在低年级加强写字指导的研究龙村镇第二小学温珺人类步入信息时代,文化的传播与交流方式产生了翻天覆地的变化。随着键盘敲击的速度越来…