?? chap10_7.htm
字號:
<p align="JUSTIFY">m_pSet->m_strCourseIDParam = pDoc->m_courseSet.m_CourseID;</p>
<p align="JUSTIFY">m_pSet->m_strSort = "SectionNo";</p>
<p align="JUSTIFY">m_pSet->m_pDatabase
= pDoc->m_courseSet.m_pDatabase; //共享CDatabase</p>
</b>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">CRecordView::OnInitialUpdate();</p>
<p align="JUSTIFY"> </p>
<p> <b> </b></p>
<b>
<p align="JUSTIFY">m_ctlCourseList.ResetContent();</p>
<p align="JUSTIFY">if (pDoc->m_courseSet.IsOpen())</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">while (!pDoc->m_courseSet.IsEOF())</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">m_ctlCourseList.AddString(</p>
<p align="JUSTIFY">pDoc->m_courseSet.m_CourseID);
//向表中加入CourseID字段</p>
<p align="JUSTIFY">pDoc->m_courseSet.MoveNext();</p>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY">m_ctlCourseList.SetCurSel(0);</p>
</b>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">void CSectionForm::OnSelendokCourselist()</p>
<p align="JUSTIFY">{</p>
<p><b> </b></p>
<b>
<p align="JUSTIFY">if (!m_pSet->IsOpen())</p>
<p align="JUSTIFY">return;</p>
<p align="JUSTIFY">m_ctlCourseList.GetLBText(m_ctlCourseList.GetCurSel(),</p>
<p align="JUSTIFY">m_pSet->m_strCourseIDParam);</p>
<p align="JUSTIFY">m_pSet->Requery();
//重新查詢</p>
<p align="JUSTIFY">if (m_pSet->IsEOF())</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">m_pSet->SetFieldNull(&(m_pSet->m_CourseID),
FALSE);</p>
<p align="JUSTIFY">m_pSet->m_CourseID = m_pSet->m_strCourseIDParam;</p>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY">UpdateData(FALSE);</p>
</b>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY"> 在CSectionForm::OnInitialUpdate函數的開頭部分,調用了CRecordset::Open建立CCourseSet記錄集,在調用Open函數之前,指定了按CourseID字段排序記錄集。關于調用Open函數的一些前因后果在前面已經解釋過了,讀者應該不難分析。接下來的代碼讀者可能就看不懂了,為什么在記錄集的m_strFilter過濾字符串中會有一個“?”號呢。</p>
<p align="JUSTIFY"> 這是因為在本例中使用了“參數化記錄集”技術。在記錄集的m_strFilter和m_strSort中,可以用“?”號作為參數使用,這樣在指定過濾器和排序時可以更具靈活性。例如,在OnInitialUpdate函數中,是這樣指定過濾器的:</p>
<b>
<p align="JUSTIFY">m_pSet->m_strFilter = "CourseID = ?";</p>
</b>
<p align="JUSTIFY">在調用Open或Requery時,“?”將會被CSectionSet::m_strCourseIDParam中的內容取代。例如,如果指定m_strCourseIDParam為“MATH101”,則m_strFilter將變成"CourseID
= MATH101"。這樣用戶只要指定了m_strCourseIDParam,就可以定制過濾器。象m_strCourseIDParam這樣的成員被稱作參數數據成員,同域數據成員一樣,它是記錄集所特有的。ClassWizard不支持參數數據成員,用戶只能手工加入之,且其名字由用戶自己確定。</p>
<p align="JUSTIFY"> 參數替換的工作實際上是由CSectionSet::DoFieldExchange中的RFX函數完成的,在DoFieldExchange函數的末尾,我們加入了下面兩行:</p>
<b>
<p align="JUSTIFY">pFX->SetFieldType(CFieldExchange::param);</p>
<p align="JUSTIFY">RFX_Text(pFX, "CourseIDParam", m_strCourseIDParam);</p>
</b>
<p align="JUSTIFY">DoFieldExchange可以識別域數據成員和參數數據成員。第一行調用用來表明隨后的RFX函數用于參數替換。第二行是一個用于m_strCourseIDParam參數的RFX函數。RFX第二個參數的名字可由用戶確定,這里指定其為“CourseIDParam”。</p>
<p align="JUSTIFY"> 用戶可以在m_strFilter和m_strSort中使用一個或多個參數。在有多個參數的情況下,要注意RFX函數的調用次序應與參數出現的次序相對應。框架規定,用戶應該先在m_strFilter中安排參數,然后才是m_strSort。</p>
<p align="JUSTIFY"> CRecordset有兩個數據成員m_nFields和m_nParams分別用來統計域數據成員和參數數據成員的數目。前者由ClassWizard自動計數,而后者必需由用戶來維護。在CSectionSet的構造函數中,m_nParams被置為1,因為只有一個參數數據成員。</p>
<p align="JUSTIFY"> 現在讓我們繼續研究OnInitialUpdate。在調用基類的OnInitialUpdate以前,在程序中有這樣一行代碼:</p>
<b>
<p align="JUSTIFY">m_pSet->m_pDatabase = pDoc->m_courseSet.m_pDatabase;</p>
</b>
<p align="JUSTIFY">m_pDatabase是CRecordset的公共成員,它是指向CDatabase對象的指針。如果應用程序使用了兩個以上的記錄集,在缺省情況下,每個記錄集都會創建一個代表同一數據源的CDatabase對象(參見10.5.4),這顯然沒有必要。上面一行代碼使CSectionSet記錄集共享由CCourseSet記錄集創建的CDatabase對象,這樣,當在CRecordView::
OnInitialUpdate中調用CRecordset::Open打開CSectionSet記錄集時,就不會再創建CDatabase對象了。</p>
<p align="JUSTIFY"> 接下來,程序把CCourseSet的每一個記錄的CourseID字段都加入到組合框中。</p>
<p align="JUSTIFY"> 當用戶在組合框中選擇了新的CourseID時,在CSectionForm::OnSelendokCourselist中,就會把用戶選擇的CourseID設置到m_strCourseIDParam中,然后調用CRecordset::Requery按照定制的過濾器和排序重新查詢和建立記錄集。如果重新建立的記錄集為空,則說明Section表中沒有與指定的CourseID相對應的記錄,這時記錄集被自動設置為NULL。在程序中,調用了CRecordset::
SetFieldNull把m_CourseID字段設置為非空。最后,調用CRecordView::UpdateData更新表單中的控件。</p>
<p align="JUSTIFY"> 從程序中不難看出,使用參數化記錄集的最大好處是可以在程序運行期間方便地指定過濾器和排序,這大大提高了程序的用戶定制查詢能力。</p>
<p align="JUSTIFY"> 編譯并運行Enroll,試試新增加的功能。</p>
<p> <b> </b></p>
<p align="JUSTIFY"><b> </b>10.7.4 Enroll的第三個版本</p>
<p align="JUSTIFY"> Enroll的第三個版本支持記錄的添加和刪除,該版本也演示了對數據庫異常的處理。請讀者先運行VC5.0提供的第三步Enroll程序看一看。第三版Enroll的Record菜單中多了三個命令:Add、Delete和Refresh,它們分別用來添加、刪除和刷新記錄。</p>
<p align="JUSTIFY"> 當用戶選擇Add命令后,就進入了添加模式。這時除Course組合框外,所有的字段都被清除。用戶可以在各編輯框內輸入新記錄的字段值,然后移動到別的記錄上,這樣就把新的記錄保存到數據源中。用戶也可以通過再次選擇Add命令來保存新加的記錄。</p>
<p align="JUSTIFY"> 當用戶選擇Delete命令后,當前記錄被刪除,程序會自動滾動到下一個記錄上。</p>
<p align="JUSTIFY"> Refresh命令用來放棄記錄的修改或添加操作,同時,恢復原記錄的內容。</p>
<p align="JUSTIFY"> 現在就讓我們開始在上一小節Enroll的基礎上制作新版本。若當前工程不是Enroll,請讀者打開上一小節創建的Enroll工程。</p>
<p align="JUSTIFY"> 首先要為Record菜單添加三個菜單項,菜單項的各項屬性在表10.6中列出。請把這三個菜單項加到Record菜單的開頭,并且用一個分隔線和后面的命令隔開。</p>
<p align="JUSTIFY"> <b> </b></p>
<b>
<p align="CENTER">表10.6</p>
</b>
<table border="1" cellspacing="1" cellpadding="1" width="579">
<tr>
<td width="18%"><b>
<p align="JUSTIFY">Caption
</b></td>
<td width="36%"><b>
<p align="JUSTIFY">ID
</b></td>
<td width="46%"><b>
<p align="JUSTIFY">Prompt
</b></td>
</tr>
<tr>
<td width="18%">
<p align="JUSTIFY">&Add
</td>
<td width="36%">
<p align="JUSTIFY">ID_RECORD_ADD
</td>
<td width="46%">
<p align="JUSTIFY">Add a new section
</td>
</tr>
<tr>
<td width="18%">
<p align="JUSTIFY">&Refresh
</td>
<td width="36%">
<p align="JUSTIFY">ID_RECORD_REFRESH
</td>
<td width="46%">
<p align="JUSTIFY">Cancel changes on form,or cancel Add
</td>
</tr>
<tr>
<td width="18%">
<p align="JUSTIFY">&Delete
</td>
<td width="36%">
<p align="JUSTIFY">ID_RECORD_DELETE
</td>
<td width="46%">
<p align="JUSTIFY">Delete section
</td>
</tr>
</table>
<p> </p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY"> 接著,用ClassWizard為上面三個命令創建處理函數,函數名為缺省的。另外,需要為記錄視圖編寫新的OnMove函數來處理滾動命令,這是因為原來的OnMove函數沒有添加記錄的功能。在ClassWizard的CSectionForm類的Messages列表中可以找到OnMove函數,請讀者雙擊并建立該函數。</p>
<p align="JUSTIFY"> 在CSectionForm::OnMove函數處理滾動命令時,必需要有一個標志來判斷當前是否處于添加模式,以便向數據源中加入新記錄或進行普通的滾動處理。請讀者在CSectionForm類的定義中的適當位置加入下面兩行:</p>
<b>
<p align="JUSTIFY">protected:</p>
<p align="JUSTIFY">BOOL m_bAddMode;</p>
</b>
<p align="JUSTIFY">在前兩個版本的Enroll中,Section編輯框都是只讀的,但在添加記錄時,必需允許用戶修改Section編輯框。這是因為SectionNo字段是Section表的主關鍵字,它的值必需唯一,如果在加入新記錄時不改變原來的SectionNo字段,那么將會因為主關鍵字重復而導致異常產生。顯然,我們需要一個CEdit對象來控制IDC_SECTION編輯框,請讀者用ClassWizard為CSectionForm類加入一個與IDC_SECTION對應的CEdit型成員變量,變量的名字為m_ctlSection。</p>
<p align="JUSTIFY"> 最后,請讀者按清單10.13修改程序。</p>
<p align="JUSTIFY"> <b> </b></p>
<p align="JUSTIFY"> <b>清單10.13
CSectionForm類的部分源代碼</b></p>
<p align="JUSTIFY">CSectionForm::CSectionForm()</p>
<p align="JUSTIFY">: CRecordView(CSectionForm::IDD)</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY"><b>. . .</b></p>
<b>
<p align="JUSTIFY">m_bAddMode = FALSE;</p>
</b>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY"> </p>
<p align="JUSTIFY">void CSectionForm::OnSelendokCourselist()</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">if (!m_pSet->IsOpen())</p>
<p align="JUSTIFY">return;</p>
<p align="JUSTIFY">m_ctlCourseList.GetLBText(m_ctlCourseList.GetCurSel(),</p>
<p align="JUSTIFY">m_pSet->m_strCourseIDParam);</p>
<p><b> </b></p>
<b>
<p align="JUSTIFY">if (!m_bAddMode)</p>
<p align="JUSTIFY">{</p>
</b>
<p align="JUSTIFY">m_pSet->Requery();</p>
<p align="JUSTIFY">if (m_pSet->IsEOF())</p>
<p align="JUSTIFY">{</p>
<p align="JUSTIFY">m_pSet->SetFieldNull(&(m_pSet->m_CourseID),
FALSE);</p>
<p align="JUSTIFY">m_pSet->m_CourseID = m_pSet->m_strCourseIDParam;</p>
<p align="JUSTIFY">}</p>
<p align="JUSTIFY">UpdateData(FALSE);</p>
<p><b> </b></p>
<b>
<p align="JUSTIFY">}</p>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -