C++ 实验五总结报告

          实验十三 数据库(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++程序\实验\实习”。

实验内容和步骤

1创建数据库和数据表

这里以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。

2创建ODBC数据源

① 运行ODBC组件,进入ODBC数据源管理器。

② 单击“添加”按钮,弹出有一驱动程序列表的“创建新数据源”对话框,在该对话框中选择Microsoft Access Driver。

③ 单击“完成”按钮,进入指定驱动程序的安装对话框,数据源名称设为“学生信息管理系统”,单击“选择”按钮将本实验中的main.mdb数据库。

④ 单击“确定”按钮,刚才创建的用户数据源被添加在“ODBC数据源管理器”的“用户数据源”列表中。

3启动Visual C++ 6.0

启动Visual C++ 6.0系统。

4创建单文档应用程序Ex_Student

① 用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);

}

5为数据表创建CRecordSet用户派生类

① 在Ex_Student中添加学生基本信息表student、课程信息表course、课程成绩表score和专业数据表special的CRecordSet派生类CStudentSet、CCourseSet、CScoreSet和CSpecialSet。

② 在stdafx.h文件中添加CRecordSet头文件包含#include <afxdb.h>。

6复制“学生课程成绩”对话框和CScoreDlg

① 复制对话框资源IDD_SCORE。

② 复制对话框类文件Score.h和Score.cpp,并添加到工程中。

③ 将Score.cpp文件前面的头文件包含#include "Ex_List.h"修改为#include "Ex_Student.h"。

7实现添加、删除和修改功能

① 打开菜单资源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)编译运行并测试。

8写出实验报告

分析上述运行结果以及思考与练习,写出实验报告。

          实验十三 数据库(2)

实验目的和要求

本次实验在实验9的基础上完成进行。

(1)修改“学生课程成绩”对话框及其CScoreDlg类代码,使其能根据课程名称确定课程号和学分。

图10.1  修改后的“学生课程成绩”对话框                                                        

(2)创建“查询条件”对话框及其CSeekDlg类,并根据查询条件在列表视图中显示出满足条件的学生课程成绩记录,如图10.2所示。

图10.2  查询

实验准备和说明

(1)具备知识:MFC的ODBC多个表的编程方法。

(2)创建本次实验工作文件夹“…\Visual C++程序\实验\实验10”。

(3)将实验9的Ex_Student工程复制到本次实验工作文件夹中。

实验内容和步骤

1修改“学生课程成绩”对话框

① 启动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  控件变量

2完善CScoreDlg类代码

① 在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);  

}

④ 编译运行并测试。

3添加并设计“查询条件”对话框及其类

① 按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 );  

}

4完善代码

① 在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所示。

5写出实验报告

分析上述运行结果以及思考与练习,写出实验报告。

图10.3 “专业数据字典”对话框

相关推荐