張占陽
(長安大學 地測學院 地理信息系統(tǒng)系,陜西 西安 710054)
傳統(tǒng)的信息管理系統(tǒng)涉及的內(nèi)容廣泛,但社會對其發(fā)展和完善有了極大增加,因而規(guī)范管理、提高工作效率已變得尤為重要[1-3]。一般情況下,在系統(tǒng)總體設計和系統(tǒng)編碼實現(xiàn)的過程中就已經(jīng)設定了屬性段或值域,從而使得外部信息或數(shù)據(jù)錄入時只能n:n對號入座,而采集或收集的其他附加信息就有可能被忽略或刪掉,這一部分無用信息由于無法錄入到信息管理系統(tǒng)的數(shù)據(jù)庫中而白白浪費掉。當然,一般的信息管理系統(tǒng)都給出了指定的字段,所以在輸入數(shù)據(jù)時只需要按照指定的字段輸入內(nèi)容即可,只有當需要錄入新的數(shù)據(jù)信息時才需要通過更新數(shù)據(jù)庫來添加新的屬性段或字段,但增加新字段使系統(tǒng)或數(shù)據(jù)庫更新,會帶來大量的人力或資金的消費。因此,這里針對研究生管理系統(tǒng)(IMS)設計了一種較為合理、更加完善的人機對話框來實現(xiàn)在錄入基本信息或所需信息的同時能夠?qū)崿F(xiàn)附加類或新增類信息的錄入。
基于VC++建立一個 “隱藏工具欄”、“初始化狀態(tài)欄”的單文檔研究生IMS(信息管理系統(tǒng))MFC[4]工程,該工程的具體目的是實現(xiàn)研究生基本信息、專業(yè)信息、選課信息及其對應新增附加信息的輸入和錄入。
在MFC工程類中建立基于對話框類的研究生基本信息類(CBaseXinxi),并在該類中建立基本信息變量姓名、性別、民族、籍貫(省、市)、生日、血型、身高以及自我介紹等,其中姓名、民族、生日、身高和自我介紹屬于編輯框類變量,性別屬于單選框類變量,籍貫中的省及血型屬于組合框類變量,市屬于列表框類變量。
通過對研究生基本信息建立類向?qū)氤跏蓟瘮?shù)WM_InitDialog(),并在該函數(shù)中對各變量進行初始化,使性別變量默認為男性(即SetCheck(TRUE)),設定組合框變量“省”當前選擇項目為第一個項目(即 SetCurSel(0)),再對列表框變量“市”通過AddString(項目名)添加第一個項目并將其作為默認選中項目,設定血型當前默認血型類型 (如O型)。建立基于組合框類“省”的響應函數(shù)WM_SelChange(),實現(xiàn)對省級以下各城市的不同選擇。這樣,基本信息對話框建立完成。但需要在工程Doc類中引入一個CBaseXinxi類的對象或指針,使得在View類菜單響應函數(shù)“輸入研究生基本信息函數(shù)”中實現(xiàn)對該類對象或指針的調(diào)用并返回對話框中的基本信息,從而為后期的數(shù)據(jù)錄入、數(shù)據(jù)處理、數(shù)據(jù)應用以及分析等奠定基礎,圖1為研究生基本信息的錄入,研究生基本信息的顯示則如圖2所示。
圖1 研究生基本信息輸入示例Fig.1 Inputting example of graduate basic information
圖2 研究生基本信息顯示示例Fig.2 Displaying example of graduate basic information
一般情況下,當信息系統(tǒng)建立之后,只需按系統(tǒng)中給出的基本信息字段來采集學生對應的基本信息,如本示例研究生基本信息對話框中只需按照姓名、性別、民族、籍貫、生日、身高、血型和自我介紹來采集或錄入各班級學生的數(shù)據(jù)作為各個記錄,并將這些數(shù)據(jù)存入到指定庫中。同理,研究生專業(yè)信息對話框類(CprofessioanXinxi)和研究生選課信息對話框類(CxuanKeXinxi)的建立思想和基本信息對話框大同小異,內(nèi)含字段:姓名、學號、學院、專業(yè)、電話、導師等,數(shù)據(jù)錄入和顯示與前者思路類似,這里不再詳細介紹。圖3、圖4分別為研究生專業(yè)信息對話框和選課信息錄入對話框。
圖3 研究生專業(yè)信息對話框Fig.3 Dialog box of graduate professional information
圖4 研究生選課信息對話框Fig.4 Dialog box of graduate elective course information
對于系統(tǒng)對話框中給定的字段,只需錄入指定的記錄即可。但有時根據(jù)用戶需求,需要增添許多新信息,相應的系統(tǒng)就必須增加許多新的功能模塊來實現(xiàn)對新增數(shù)據(jù)的各種處理和應用,這就要求必須對系統(tǒng)和對應的數(shù)據(jù)庫進行更新,而更新和建庫費用又是巨大的,這就給系統(tǒng)庫的更新和維護人員帶來了很多新問題。因此提出了一種基于對話框的附加信息錄入方法,在錄入新增數(shù)據(jù)的同時既能指定字段或?qū)傩杂颍帜芴砑訉母鱾€記錄數(shù)據(jù)。
對于新增數(shù)據(jù),可以采用建立對話框的形式來解決附加數(shù)據(jù)類型和數(shù)據(jù)變量的轉(zhuǎn)換和輸入。附加信息錄入步驟可大致歸結(jié)如下:
1)在MFC工程中其他類不變的情況下,建立其派生類附加信息類 (CFujiaXinxin),同時規(guī)定其公有繼承CDialog類;2)在附加信息類中增加字符串Cstring類型的指針或變量,其名稱為字段或?qū)傩杂?,同時增加一個CString類型的記錄1變量,使新增字段和新增記錄相對應;3)在CFujiaXinxin類中添加若干CString類型變量或指針,變量或指針名為字段或?qū)傩杂?i(1<i<n,n為新增信息類數(shù)量);因為一般情況下一個字段對應一個小的記錄數(shù)據(jù),所以也需要增加若干CString類型的記錄i變量 (1<i<n,n為新增信息類數(shù)據(jù));4)對附加信息類進行初始化,使其中的CString型變量進行兩兩對應(即數(shù)據(jù)類型和數(shù)據(jù)變量的1:1對應);5)在各個信息類中引入CFujiaXinxin類的變量或指針,實現(xiàn)對附加信息類數(shù)據(jù)的調(diào)用;6)在各個信息類中增加按鈕CButton類對象,并引入按鈕相應函數(shù)[5];7)完善各個按鈕響應函數(shù),實現(xiàn)對應的數(shù)據(jù)處理、應用等,如通過附加信息類的變量或指針實現(xiàn)對附加信息的歸類、存儲、顯示和其他數(shù)據(jù)分析與處理等功能;8)在工程類子類View類中調(diào)用各個信息對話框,再通過各個信息對話框調(diào)用附加信息類對話框,從而實現(xiàn)對不同附加信息類的分類對應存儲和應用等。圖5為附加信息的數(shù)據(jù)數(shù)錄入,研究生附加選課信息顯示則如圖6所示。
圖5 研究生附加選課信息錄入示例Fig.5 Inputting example of graduate additional elective course information
圖6 研究生附加選課信息顯示示例Fig.6 Displaying example of graduate additional elective course information
通過上述過程,可實現(xiàn)研究生基本信息、專業(yè)信息和選課信息的常規(guī)錄入以及新增附加信息的基本錄入。但需要注意的是,附加信息類中的變量類型都是CString型的,而錄入的附加信息可能是 int型、folat型、Char型和 BSTR型或VARIANT型,也可能是幾種類型的組合,這就需要討論CString類型向不同類型的轉(zhuǎn)換問題[6]。
CString是一種很有用的數(shù)據(jù)類型,它很大程度上簡化了MFC中的許多操作,使得MFC在做字符串操作時方便很多。隨著科技的飛速發(fā)展,CString型變量與其他類型變量之間的轉(zhuǎn)換算法和方法也越來越完善,這里簡單介紹VC++中CString型轉(zhuǎn)換成int型、Char型和BSTR型的大致思路[7]。
把CString類型的數(shù)據(jù)轉(zhuǎn)化成整數(shù)類型最簡單的方法就是使用標準的字符串到整數(shù)轉(zhuǎn)換例程。雖然通常覺得使用_atoi()函數(shù)是一個好選擇,但并非是唯一的正確選擇。如果決定使用 Unicode字符,那就應該用_ttoi(),它在ANSI編碼系統(tǒng)中被編譯成_atoi(),而在 Unicode編碼系統(tǒng)中編譯成_wtoi()。 當然也可以考慮使用 _tcstoul()或者 _tcstol(),它們都能把字符串轉(zhuǎn)換成任意進制的長整數(shù)(如二進制、八進制、十進制或十六進制),不同點在于前者轉(zhuǎn)化后的數(shù)據(jù)是無符號的(unsigned),而后者相反。
對于系統(tǒng)的某些屬性段(如性別或地區(qū)編號等)可以設置成Char型的值域,而通過外部設備錄入的信息為CString型數(shù)據(jù),這時就需要考慮CString型向Char型轉(zhuǎn)化的諸多問題。由于CString型轉(zhuǎn)化為Char*型的方法比較普遍,這里主要介紹目前被廣泛運用的3種轉(zhuǎn)換方法。
3.2.1 強制類型轉(zhuǎn)換為LPCTSTR
這是一種略微硬性的轉(zhuǎn)換,有關“正確”的做法,人們在認識上還存在許多混亂,正確的使用方法有很多,但錯誤的使用方法可能與正確的使用方法一樣多。首先要了解CString是一種很特殊的C++對象,里面包含了3個值:一個指向某個數(shù)據(jù)緩沖區(qū)的指針,一個是該緩沖中有效的字符記數(shù),一個是緩沖區(qū)長度。有效字符數(shù)的大小可以是從0到該緩沖最大長度減1之間的任何數(shù) (因為字符串結(jié)尾有一個NULL字符)。字符記數(shù)和緩沖區(qū)長度被巧妙隱藏。
除非做一些特殊的操作,否則不可能知道給CString對象分配的緩沖區(qū)的長度。這樣,即使獲得了該0緩沖的地址,也無法更改其中的內(nèi)容,不能截短字符串,也絕對沒有辦法加長它的內(nèi)容,否則第一時間就會看到溢出。LPCTSTR操作符(或者更明確地說就是 TCHAR*操作符)在 CString類中被重載了,該操作符的定義是返回緩沖區(qū)的地址。因此,如果需要一個指向CString的字符串指針的話,可以這樣做:
這是由C語言的強制類型轉(zhuǎn)化規(guī)則實現(xiàn)的,當需要強制類型轉(zhuǎn)化時,C++規(guī)定允許這種選擇。這種強制轉(zhuǎn)化適合所有這種情況,任何帶有LPCTSTR類型參數(shù)的函數(shù)都會強制執(zhí)行這種轉(zhuǎn)換。有一件事情是不能做的,那就是修改字符串。比如,嘗試用“,”代替“.”,不要這樣做,因為由于國際化問題,應該使用十進制轉(zhuǎn)換的National Language Support特性。需注意的是,緩沖有一個計數(shù),它是不可存取的(它位于CString地址之下的一個隱藏區(qū)域),如果改變這個串,緩沖中的字符計數(shù)不會反映所做的修改。此外,如果字符串長度恰好是該字符串物理限制的長度,那么擴展該字符串將改寫緩沖以外的任何數(shù)據(jù),那就是改寫無權(quán)進行寫操作的內(nèi)存數(shù)據(jù),也會毀壞不屬于自己的內(nèi)存,這也是應用程序真正的致命之處。
3.2.2 使用CString對象的GetBuffer方法
有時如果需要修改CString型變量中的內(nèi)容,有一個特殊的方法可以使用,就是調(diào)用CString型變量的GetBuffer()函數(shù),它的作用是返回一個可寫的緩沖指針。如果只是打算修改字符或截短字符串,可以通過如下代碼實現(xiàn):
這是GetBuffer的第一種用法,也是最簡單的一種,不用給它傳遞參數(shù),它使用默認值0,意思是使用該字符串指針但不加長它。當調(diào)用ReleaseBuffer時,字符串的實際長度會被重新計算,然后被存入到CString對象中。必須強調(diào)一點,在GetBuffer()和 ReleaseBuffer()范圍中,一定不要調(diào)用操作緩沖函數(shù)的CString型對象的任何方法。因為ReleaseBuffer()被調(diào)用之前,該CString型對象的完整性得不到保障。
需要注意的是,如果有一個常量串指針,這個串指針本身的值被存儲在只讀內(nèi)存中,如果試圖存儲它,即使已經(jīng)調(diào)用了GetBuffer(),并獲得一個只讀內(nèi)存的指針,存入操作也會失敗,并報告指針值存取錯誤。通常C程序員都有一個通病就是分配一個固定長度的緩沖,對它進行sprintf()操作,然后將它賦值給一個CString型的變量或指針。如下面示例:
采用此方法,即使字符串長度超過指定字符長度的時候,也不會破壞堆棧。
還有一個常見的錯誤就是:既然固定大小的內(nèi)存不工作,那么就采用動態(tài)分配字節(jié)。但這種做法弊端更為明顯。如下示例:
其實它可以能被簡單地寫成:
需要注意,sprintf()例子都不是Unicode就緒的,盡管可以使用tsprintf()以及用_T()來包圍格式化字符串,但是基本思路不變,而且是在走彎路,也很容易出錯。
3.2.3 利用控件接口
經(jīng)常需要把一個CString型的值傳遞給一個控件,如CComboxCtrl、CTreeviewCtrl等。MFC提供了很多便利來重載這個操作,但在大多數(shù)情況下,使用“原始”形式的更新,因此需要將某個串指針存儲到TVINSERTITEMSTRUCT結(jié)構(gòu)的TVITEM成員中。如果打算獲取存儲在控件中的數(shù)據(jù),則所需方法稍有不同,如對某個CTreeCtrl使用GetItem()方法想獲取項目的文本。但知道這些文本的長度不會超過limit_length,可以這樣寫:
其實上面代碼對所有類型的Set方法都適用,但并不需要都這么做,因為所有類型的Set方法(包括Insert方法)都不會改變字符串的內(nèi)容。但當需要寫CString型對象時,必須保證緩沖是可寫的,這正是GetBuffer()所做的事。需注意:一旦調(diào)用了一次 GetBuffer()函數(shù),那么在調(diào)用 ReleaseBuffer()之前不要對此CString型對象做任何操作。
當使用ActiveX控件編程時,經(jīng)常需要將某個值表示成BSTR類型。BSTR是一種記數(shù)字符串,是Intel平臺上的寬字符串(Unicode),而且可以包含嵌入的NULL字符??梢哉{(diào)用CString對象的AllocSysString方法將CString轉(zhuǎn)化成 BSTR:
現(xiàn)在指針b指向的就是一個新分配的BSTR對象,該對象是CString的一個拷貝,其中包含結(jié)尾NULL字符,現(xiàn)在可以將它傳遞給任何需要BSTR的接口。通常情況下,BSTR由接收它的組件釋放,如果需要自己釋放 BSTR,可以調(diào)用此函數(shù):SysFreeString(b)。
綜上所述,在子類函數(shù)中對附加信息類進行訪問,能在輸入基本信息的同時又實現(xiàn)對新增信息的輸入和分類以及各分類變量的錄入和存儲。
通過在需要擴增新信息的各個類中調(diào)用新增或附加信息類的對象即可實現(xiàn)對新增信息的逐一訪問,同時為實現(xiàn)對新增數(shù)據(jù)的后期應用和處理分析等奠定了基礎。而附加信息類對話框不僅能夠?qū)π落浫氲姆峭愋畔⑦M行分類存儲,而且實現(xiàn)了錄入數(shù)據(jù)類型與研究生信息管理系統(tǒng)(IMS)數(shù)據(jù)庫所需數(shù)據(jù)類型之間的相互轉(zhuǎn)換。從而在一定程度上解決了因系統(tǒng)或數(shù)據(jù)庫更新而帶來的時間冗長、資金龐大的問題。
[1]吳涵.基于VC++的研究生信息管理系統(tǒng)的設計與實現(xiàn)[J].計算機技術(shù)與發(fā)展,2006,16(12):184-186.WU Han.Design and implementation of graduate information management system based on VC++[J].Computer Technology and Development,2006,16(12):184-186.
[2]王佩紅,劉慧婷.基于VB的學生成績管理系統(tǒng)的設計與實現(xiàn)[J].計算機技術(shù)與發(fā)展,2007,17(12):169-172.WANG Pei-hong,LIU Hui-ting.Design and realization of student achievements management system based on VB[J].Computer Technology And Development,2007,17(12):169-172.
[3]劉成忠,王聯(lián)國.學位與研究生管理信息系統(tǒng)設計[J].甘肅科技,2006,22(9):60-61,71.LIU Cheng-zhong,WANG Lian-guo.Design of the degree and graduate managementinformation system[J].Gansu Science and Technology,2006,22(9):60-61,71.
[4]李英.Visual C++編程與項目開發(fā)[M].上海:華東理工大學出版社,2008.
[5]汪旭冉.VC++6.0在對話框最小化與提示條設計中的應用分析[J].黑龍江科技信息,2008(23):71-71,50.WANG Xu-ran.Application and analysis of VC++6.0 in minimizing the dialog box and designing the article tips[J].Heilongjiang Technology Information,2008(23):71-71,50.
[6]王燕.面向?qū)ο蟮睦碚撆cC++實踐[M].北京:清華大學出版社,1996.
[7]侯俊杰.深入淺出MFC[M].武漢:華中科技大學出版社,2001.