⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap10_7.htm

📁 VC++编程实例。非常详细
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<html>

<head>
<title>10.7 学习Enroll例程</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 3.0">
<link rel="stylesheet" href="../../../cpcw.css"></head>

<body link="#3973DE" alink="#3973DE" background="../../bg.gif">
<div align="center"><center>
    <table width="85%" border="0">
      <tr bgcolor="#FFFFFF"> 
        <td> 
          <div align="center"> 
            <center>
            </center>
          </div>
          <p align="CENTER"><font color="red"><b>10.7 学习Enroll例程</b></font></p>
          <p align="JUSTIFY"> Visual C++提供了一个名为Enroll的例子来作为学习MFC数据库编程的教程.Enroll分为四步,本节的任务就是指导读者完成前三步的Enroll例程,并对其进行较彻底的剖析.通过学习这三步例程,读者将掌握用AppWizard和ClassWizard创建MFC数据库应用程序的方法.</p>
          <p align="JUSTIFY"> 在开始学习Enroll例程时,读者也许会感到用AppWizard创建数据库应用很容易,似乎不用学习前面几节的内容.诚然,AppWizard自动地为应用程序加入了许多与数据库有关的代码,大大简化了数据库应用的开发.但AppWizard不是万能的,它建立的数据库应用往往不能满足用户的需要.用户真正想知道的是如何不依赖AppWizard而编写自己的数据库应用程序,这也正是本章的宗旨所在.事实上,前面几节的分析以及后面进行的对Enroll例程的分析正是为这一宗旨服务的.</p>
          <p align="JUSTIFY"> 在学习Enroll以前,请读者先从Visual 
            C++ 5.0的光盘上将Enroll(在samples 
            \ mfc \ tutorial \ enroll目录下)在前三步的例程拷到硬盘上,以供参考.另外,Enroll要用到Access数据库STDRED32.MDB,该文件在VC5.0的Stdreg例程中(在samples 
            \ mfc \ database \ stdreg目录下),请读者将该例子也拷贝到硬盘上.</p>
          <p align="JUSTIFY"> <b></b>10.7.1 注册数据源</p>
          <p align="JUSTIFY"> ODBC应用程序不能直接使用数据库,用户必需为要使用的数据库注册数据源.注册数据源的工作由ODBC管理器完成,该管理器位于Windows 
            95控制面板的32位ODBC内.现在让我们为Access数据库STDREG32.MDB注册数据源.</p>
          <p align="JUSTIFY"> 打开控制面板,双击“32位ODBC”图标,则会显示一个“ODBC数据源管理器”,如图10.5所示。在管理器中选择“用户DSN”页,用户DSN只对用户可见而且只能用户当前机器。</p>
          <p align="center"> <img src="T10_5.gif" alt="T10_5.tif (174104 bytes)" width="460" height="355"></p>
          <p align="center"> 图10.5 ODBC数据源管理器</p>
          <p align="JUSTIFY">点击“添加”按钮,则会弹出一个“创建新数据源”对话框。在该对话框中选择Microsoft 
            Access Driver(*.mdb),然后按完成按钮。接下来会显示一个ODBC 
            Microsoft Access 97 Setup对话框,如图10.6所示,该对话框用来把数据库与一个数据源名连接起来。在Data 
            Source Name:栏中输入Student 
            Registration,然后点击Select...按钮,在随后弹出的对话框中找到并选择STDREG32.MDB。连按两个OK按钮后,一个名为Student 
            Registration的新数据源就被注册到了管理器中。</p>
          <p align="center"> <img src="T10_6.gif" alt="T10_6.tif (156780 bytes)" width="471" height="312"></p>
          <p align="center"> 图10.6 
            ODBC Microsoft Access 97 Setup对话框</p>
          <div align="center"> 
            <center>
              <table border="2" cellpadding="2" cellspacing="0" width="100%" bgcolor="#80D6FF">
                <tr> 
                  <td width="100%"> <b></b>提示:如果要为dBase或FoxPro数据库注册数据源,则应该选择一个目录而不是文件作为数据源。这是因为在Access中,一个MDB文件可以包含多张表,因此可以认为一个MDB文件就是一个数据库。而在dBase或FoxPro中,一个DBF文件只能对应一张表,一个数据库可能会包含好几个DBF文件,所以可以认为某一个包含了若干DBF文件的目录是一个数据库。<b></b></td>
                </tr>
              </table>
            </center>
          </div>
          <p align="JUSTIFY">10.7.2 Enroll的第一个版本</p>
          <p align="JUSTIFY"> Enroll第一个版本如图10.3所示,该程序具有浏览记录集和修改记录这两个基本功能。在修改了表单中的记录后,移动到一个新的记录上就可以保存对原记录的修改。注意在表单中Course和Section编辑框都是只读的,这是因为这两个字段的内容较重要,用户不能随便修改。Enroll使用了STDREG32.MDB的Section表,该表是一张课程表,其内容如表10.2所示。</p>
          <p align="JUSTIFY"> 现在让我们来建立Enroll应用程序。首先,用AppWizard来完成Enroll程序框架的建立,请读者按下面几步进行:</p>
          <blockquote> 
            <p align="JUSTIFY">启动AppWizard,指定一个名为Enroll的MFC工程。</p>
            <p align="JUSTIFY">在MFC AppWizard的第一步选择Single 
              document。</p>
            <p align="JUSTIFY">在MFC AppWizard的第二步选择Database 
              view without file support,然后点击Data 
              Source...按钮,在Database 
              Options对话框中的ODBC组合框中选择Student 
              Registration数据源,如图10.7所示。然后按“OK”按钮,则会打开一个Select 
              Database Table对话框,如图10.8所示。在该对话框中选择Section表。按OK按钮退出。</p>
            <p align="JUSTIFY">在MFC AppWizard的第六步中,将类CEnrollSet改名为CSectionSet,将类CEnrollView改名为CSectionForm。</p>
            <p align="JUSTIFY">按Finish按钮,建立Enroll工程。</p>
          </blockquote>
          <p align="center"> <img src="T10_7.gif" alt="T10_7.tif (155892 bytes)" width="470" height="248"></p>
          <p align="center"> 图10.7 
            Database Options对话框</p>
          <p align="center"> <img src="T10_8.gif" alt="T10_8.tif (135432 bytes)" width="452" height="279"></p>
          <p align="center"> 图10.8 
            Select Database Table对话框</p>
          <p align="JUSTIFY"> 打开工作区的类视图,可以发现AppWizard自动创建了一个记录集类CSectionSet和一个记录视图类CSectionForm,这两个类分别是CRecordset和CRecordView的派生类。AppWizard也为CSectionSet类自动创建了域数据成员。</p>
          <p align="JUSTIFY"> 打开工作区的资源视图,读者不难找到一个ID为IDD_ENROLL_FORM的对话框模板,该模板将被记录视图用来显示表单。清除该模板中的所有控件,并把模板的尺寸扩大到183×110,然后按图10.3的式样放置控件。这里可以采取一个偷懒的方法:打开VC5.0已作好的第一个版本Enroll的资源文件(Enroll.rc),找到并打开IDD_ENROLL_FORM对话框模板,按住Ctrl键并用鼠标选择模板中的所有控件,然后按Ctrl+Insert键拷贝所选的控件。切换到自己的IDD_ENROLL_FORM对话框模板,然后按Shift+Insert键把刚才拷贝的控件粘贴到模板中。</p>
          <p align="JUSTIFY"> 接下来的任务是用ClassWizard把表单中的控件与记录集的域数据成员连接起来,以实现控件与当前记录的DDX数据交换。请读者按如下步骤操作:</p>
          <blockquote> 
            <p align="JUSTIFY">进入ClassWizard,选择Member 
              Variables页并且选择CSectionForm类。</p>
            <p align="JUSTIFY">在变量列表中双击IDC_CAPACITY项,则会显示Add 
              Member Variable对话框。注意该对话框的Member 
              variable name栏显示的是一个组合框,而不是平常看到的编辑框。如图10.9所示,在组合框的列表中选择m_pSet-&gt;m_Capacity。按OK按钮确认。</p>
            <p align="JUSTIFY">仿照第2步,为其他控件连接记录集的域数据成员。根据控件的ID,不难确定对应的域数据成员。</p>
          </blockquote>
          <p align="center"> <img src="T10_9.gif" alt="T10_9.tif (159244 bytes)" width="424" height="349"></p>
          <p align="center"> 图10.9 
            Add Member Variable对话框</p>
          <p align="JUSTIFY">  </p>
          <p align="JUSTIFY"> 在CSectionForm类的定义内可以找到下面一行:</p>
           
          <p align="JUSTIFY">CSectionSet* m_pSet;</p>
           
          <p align="JUSTIFY">可见m_pSet是CSectionForm类的成员,它指向一个CSectionSet对象。用ClassWizard可以把控件与象记录集这样的“外部数据”连接起来,这是ClassWizard在数据库编程方面的一个特殊应用。</p>
          <p align="JUSTIFY"> 编译并运行Enroll,读者会惊奇的发现Enroll居然是一个相当不错的记录浏览器,并且用户可以对记录进行修改。</p>
          <p align="JUSTIFY"> 现在,让我们来分析一下AppWizard和ClassWizard为Enroll干了哪些事情。</p>
          <p align="JUSTIFY"> 在文档类CEnrollDoc的定义中,有如下一行:</p>
           
          <p align="JUSTIFY">CSectionSet m_sectionSet;</p>
           
          <p align="JUSTIFY">可见AppWizard在CEnrollDoc类中嵌入了一个CSectionSet对象。这相当于调用了构造函数CSectionSet(NULL),CSectionSet类的构造函数的声明如下:<br>
            CSectionSet(CDatabase* pDatabase 
            = NULL);</p>
          <p align="JUSTIFY"> 函数的定义在清单10.5中列出。可以看出,构造函数调用了基类的构造函数,并对域数据成员进行了初始化。通过10.5.4我们知道,若传递NULL参数给CRecordset的构造函数,那么CRecordset::Open函数将自动构建一个CDatabase对象,并根据CRecordset:: 
            GetDefaultConnect返回的连接字符串建立与数据源的连接。CSectionSet提供了虚拟函数GetDefaultConnect的新版本,如清单10.6所示,在该函数中提供了数据源Student 
            Registration。</p>
          <p align="JUSTIFY"> <b> </b></p>
          <p align="JUSTIFY"> <b>清单10.5 
            CSectionSet的构造函数</b></p>
           
          <p align="JUSTIFY">CSectionSet::CSectionSet(CDatabase* pdb)</p>
          <p align="JUSTIFY">: CRecordset(pdb)</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">//{{AFX_FIELD_INIT(CSectionSet)</p>
          <p align="JUSTIFY">m_CourseID = _T(&quot;&quot;);</p>
          <p align="JUSTIFY">m_SectionNo = _T(&quot;&quot;);</p>
          <p align="JUSTIFY">m_InstructorID = _T(&quot;&quot;);</p>
          <p align="JUSTIFY">m_RoomNo = _T(&quot;&quot;);</p>
          <p align="JUSTIFY">m_Schedule = _T(&quot;&quot;);</p>
          <p align="JUSTIFY">m_Capacity = 0;</p>
          <p align="JUSTIFY">m_nFields = 6;</p>
          <p align="JUSTIFY">//}}AFX_FIELD_INIT</p>
          <p align="JUSTIFY">m_nDefaultType = snapshot;</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY"> <b> </b></p>
          <p align="JUSTIFY"> <b>清单10.6 
            派生类的GetDefaultConnect函数</b></p>
           
          <p align="JUSTIFY">CString CSectionSet::GetDefaultConnect()</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">return _T(&quot;ODBC;DSN=Student Registration&quot;);</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY">  </p>
          <p align="JUSTIFY"> 至于记录集的建立,实际上是在CRecordView:: 
            OnInitialUpdate中完成的,这部分代码对用户是透明的,这里在清单10.7中列出。在该函数中调用CRecordset::Open来建立记录集。在函数的开头调用了OnGetRecordset函数来获取与记录视图相连的记录集对象。CSectionForm提供了虚拟函数OnGetRecordset的新版本,如清单10.8所示,该函数把m_pSet提交给调用者。至于m_pSet的初始化,则是在CSectionForm::OnInitialUpdate函数中完成的,如清单10.9所示。</p>
          <p align="JUSTIFY"> <b> </b></p>
          <p align="JUSTIFY"> <b>清单10.7 
            CRecordView:: OnInitialUpdate函数</b></p>
           
          <p align="JUSTIFY">void CRecordView::OnInitialUpdate()</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">CRecordset* pRecordset = OnGetRecordset();</p>
          <p align="JUSTIFY">// recordset must be allocated already</p>
          <p align="JUSTIFY">ASSERT(pRecordset != NULL);</p>
           
          <p align="JUSTIFY"> </p>
           
          <p align="JUSTIFY">if (!pRecordset-&gt;IsOpen())</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">CWaitCursor wait;</p>
          <p align="JUSTIFY">pRecordset-&gt;Open();</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
           
          <p align="JUSTIFY">CFormView::OnInitialUpdate();</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
          <p align="JUSTIFY"> <b> </b></p>
          <p align="JUSTIFY"> <b>清单10.8 
            派生类的OnGetRecordset函数</b></p>
           
          <p align="JUSTIFY">CRecordset* CSectionForm::OnGetRecordset()</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">return m_pSet;</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
          <p> <b> </b></p>
          <b> 
          <p align="JUSTIFY">  </p>
          </b> 
          <p align="JUSTIFY"><b>清单10.9 派生类的OnInitialUpdate函数</b></p>
           
          <p align="JUSTIFY">void CSectionForm::OnInitialUpdate()</p>
          <p align="JUSTIFY">{</p>
          <p align="JUSTIFY">m_pSet = &amp;GetDocument()-&gt;m_sectionSet;</p>
          <p align="JUSTIFY">CRecordView::OnInitialUpdate();</p>
          <p align="JUSTIFY">}</p>
           
          <p align="JUSTIFY"> </p>
          <p> <b> </b></p>
          <b> 
          <p align="JUSTIFY">  </p>
          </b> 
          <p align="JUSTIFY"><b> </b>注意到在CRecordView:: 
            OnInitialUpdate中调用CRecordset::Open时未提供任何参数,这意味着Open函数将从CRecordset::GetDefaultSQL中获取SQL信息。CSectionSet提供了虚拟函数GetDefaultSQL的新版本,如清单10.10所示,该函数返回了“Section”表名。</p>
          <p align="JUSTIFY"> <b> </b></p>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -