文/郭向東 王麗峰
本文主要介紹基于Authorware和Access開發(fā)考試管理系統(tǒng)的方法。從題庫管理、考試設(shè)置、注冊(cè)管理到成績(jī)回收,給出了邏輯結(jié)構(gòu)和程序代碼,其中對(duì)題庫管理進(jìn)行了比較詳細(xì)的陳述。
筆者曾在《中國(guó)教育網(wǎng)絡(luò)》2013年2~3月上發(fā)表了一篇題為《基于Authorware和Access的考試系統(tǒng)設(shè)計(jì)》的文章,就考試系統(tǒng)的設(shè)計(jì)進(jìn)行了詳盡的介紹。嚴(yán)格說來,它是一個(gè)考試客戶端。一個(gè)完整的系統(tǒng),應(yīng)由考試子系統(tǒng)、數(shù)據(jù)庫和管理子系統(tǒng)構(gòu)成。它們之間的信息流關(guān)系如圖1所示。很明顯,這是一種傳統(tǒng)的C/S模式。先是由管理端將數(shù)據(jù)庫中為考試提供若干約束性設(shè)置的數(shù)據(jù)表和各類試題庫進(jìn)行更新或更換;再是考試端訪問數(shù)據(jù)庫獲取相關(guān)信息和考題,考試完后交卷,將得分寫入數(shù)據(jù)庫;最后是管理端將數(shù)據(jù)庫中考生分?jǐn)?shù)回收、將題庫備份后清空,以備下一次(科)考試。
為保證系統(tǒng)正常運(yùn)行,數(shù)據(jù)庫中可供考試端和管理端訪問的數(shù)據(jù)表至少應(yīng)有:shezhi存放科目名稱、時(shí)限、各題型小題數(shù)及小題分;zhuce存放注冊(cè)考生的學(xué)號(hào)、姓名、密碼;chengji存放考生的學(xué)號(hào)、姓名、各大題得分及總成績(jī);而xuanzeti、tiankongti、duoxuanti等表,則分別存放單選、填空和多選等題型題目的編號(hào)、題干、各選項(xiàng)、正確答案。
圖1 考試客戶端信息關(guān)系流
圖2 管理與系統(tǒng)
本文將基于Authorware和Access對(duì)考試管理系統(tǒng)的設(shè)計(jì)進(jìn)行探討。
考試管理系統(tǒng)的工作就是對(duì)考前和考后的數(shù)據(jù)庫進(jìn)行管理和處理,具體功能和流程圖如圖2所示。
首先,管理端必須與位于服務(wù)器上的數(shù)據(jù)庫建立連接。在封面上的“服務(wù)器”文本框中(如圖3所示)鍵入其位置,比如用局域網(wǎng)中某一臺(tái)計(jì)算機(jī)A010充當(dāng)服務(wù)器,這時(shí)可以鍵入\A010,回車?!皥D2”中“服務(wù)器”交互的“*”圖標(biāo)的程序和“連接數(shù)據(jù)庫”圖標(biāo)的程序相繼運(yùn)行,按指定的位置、賬戶和密碼完成連接:
position:=EntryText
--記錄鍵入的位置。
dblist:="DSN=test info;"
圖3 考試管理系統(tǒng)登錄界面
dblist:=dblist^"Description=試題庫;"
dblist:=dblist^"FIL=MS Access;"
dblist:=dblist^"DBQ="^position^"\數(shù)據(jù)包\shitiku.mdb;"
dblist:=dblist^"uid=auth;"
dblist:=dblist^"pwd=123456;"
result:=tMsDBRegister(4,dbtype,dblist)
接下來,“操作”圖標(biāo)的程序運(yùn)行,打開數(shù)據(jù)庫:
Databasename:="test info"
ODBCError:=""
ODBCHandle:=ODBCOpen(WindowHandle,ODBCError,Dat abasename,"","")
至此,管理端便可開始考試管理工作了。
考試客戶端作為一個(gè)考試平臺(tái),所承接的絕不會(huì)只是單一科目的考試,其科目名稱、題目數(shù)量、分?jǐn)?shù)分配、時(shí)間限制等都會(huì)有所不同。因此,在一場(chǎng)考試之前,考試管理端要將有關(guān)信息送入數(shù)據(jù)庫,以供考試客戶端訪問并初始化。
圖4 科目時(shí)間群組設(shè)置
由于時(shí)限、科目名稱、各大題的小題數(shù)量、分?jǐn)?shù)等設(shè)置信息量小,完全可以在系統(tǒng)的顯示頁面上即時(shí)輸入。因此,我們采用“文本響應(yīng)”的方式來實(shí)現(xiàn)?!翱颇繒r(shí)間”群組的設(shè)置如圖4的“層3”,其他群組類似。在“填空”、“單選”和“多選”的題數(shù)設(shè)置時(shí)要注意鍵入的數(shù)值必須小于或等于題庫中現(xiàn)有的題量。為了避免錯(cuò)誤,在對(duì)應(yīng)的圖標(biāo)中安排有相應(yīng)的程序(以“單選”為例):
danx_num:=EntryText
sqlstring:="select count(*) from xuanzeti"
jilu_danx:=ODBCExecute(ODBCHandle,sqlstring)
if danx_num>jilu_danx then
SystemMessageBox(WindowHandle,"當(dāng)前單選題庫題目只有"^jilu_danx^"題。"^Return^"設(shè)置不得超過此數(shù)。","提醒",48)
GoTo(@"單選項(xiàng)")
end if
整個(gè)顯示頁面如圖5所示。用8個(gè)變量將相應(yīng)文本框中的設(shè)置信息記錄下來,單擊“確定”,便寫入數(shù)據(jù)庫。“確定”圖標(biāo)(圖4)的程序如下:
sqlstring:="update shezhi set 科目="^"'"^kemu^"'"^",時(shí)限="^timelim
sqlstring:=splstring^",填空題數(shù)="^tk_num^",小題分1="^tk_fen
sqlstring:=sqlstring^",單選題數(shù)="^danx_num^",小題分2="^danx_fen sqlstring:=sqlstring^",多選題數(shù)="^duox_num^",小題分3="^duox_fen^"where shezhi.ID=1"
gengxin:=ODBCExecute(ODBCHand le,sqlstring)
ODBCClose(ODBCHandle)
SystemMessageBox(WindowHandle,"考分/時(shí)間設(shè)置成功","告知",48)
GoTo(@"操作")
圖5 顯示頁面
“題庫管理”有三個(gè)子功能:分大類題型“傳送新題”,“備份舊題”,“清空舊題”。
“傳送新題”——是將當(dāng)前考試要使用的題目送達(dá)題庫,以供考試組題。新題文件應(yīng)事先準(zhǔn)備好,考慮到源文件最好不要依賴操作系統(tǒng)之外的第三方軟件,我們采用txt文件。至于文件名,應(yīng)固定下來。比如用于單選題傳送的新題文件,取名為“傳送新題_danx.txt”。新題文件中,題目編號(hào)從1開始,自然連續(xù),不得缺號(hào)(因?yàn)槿碧?hào)會(huì)在考試端隨機(jī)組題時(shí)造成錯(cuò)誤),物理順序不限。值得特別提醒的是,用記事本編輯題目時(shí),一定要注意每一題的各項(xiàng)之間用制表位分隔,而兩題之間用回車符分隔,不然就會(huì)造成傳送失敗。同時(shí),要注意與表結(jié)構(gòu)吻合,以單選題為例,每小題均由“編號(hào)”、“題干”、“答案A”、“答案B”、“答案C”、“答案D”、“正答”等7項(xiàng)數(shù)據(jù)組成,不得出現(xiàn)缺項(xiàng)或錯(cuò)項(xiàng)。為了避免不同計(jì)算機(jī)上“本地磁盤”安排的不確定性,程序要求待傳文件應(yīng)放在c:盤上。
程序如下:
建數(shù)組,讀txt源文件,檢測(cè)其行數(shù)。
result:=Array("",7)xintilist:=ReadExtFile("c:\傳送新題_danx.txt")xintiline:=LineCount(xintilist)
用數(shù)組變量循環(huán)讀取i行j項(xiàng)的數(shù)據(jù)并寫入xuanzeti表中的各字段,若有空項(xiàng),此題不寫(數(shù)據(jù)庫中已設(shè)置,無須程序),并告知。
repeat with i:=2 to xintiline
resultstring:=GetLine(xintilist,i)
repeat with j:=1 to 7
result[j]:=GetLine(resultstring,j,j,Tab)if result[j]="" then
SystemMessageBox(WindowHandle,"第"^i-1^"題第"^j^"項(xiàng)空缺或錯(cuò)位,此題不能傳送。"^Return^"請(qǐng)修改完善后再傳送!","告知",48)
end if
end repeat
sqlstring:="insert into xuanzeti (編號(hào),題干,答案A,答案B,答案C,答案D,正答)values("^result[1]
sqlstring:=sqlstring^","^"'"^result[2]^"'"^","^"'"^result[3]^"'"^","^"'"^result[4]^"'"^","^"'"^result[5]^"'"^","^"'"^resu lt[6]^"'"^","
sqlstring:=sqlstring^"'"^result[7]^"'"^")"
chuanshong:=ODBCExecute(ODBCHandle,sqlstri ng)
end repeat
測(cè)出庫中xuanzeti表里的記錄總數(shù),與源文件比較,并告知用戶。
sqlstring:="select count(*) from xuanzeti"
jilu_num:=ODBCExecute(ODBCHandle,sqlstring)
if jilu_num<>xintiline-1 then
SystemMessageBox(WindowHandle,"新題傳送少了"^xintiline-jilu_num-1^"道題。"^Return^"題中不要使用西文單引號(hào)!","告知",48)
else
SystemMessageBox(WindowHandle,"新題悉數(shù)傳送。共"^jilu_num^"道題。","告知",48)
end if
新題傳送的關(guān)鍵是如何讀取txt文件中一行(也是一題)的各項(xiàng)。程序使用ReadExtFile()函數(shù)讀取整個(gè)源文件,再用LineCount()函數(shù)檢測(cè)出總行(題)數(shù),而GetLine()函數(shù)根據(jù)參數(shù)安排的不同既可從字符串中讀出指定的某一行,也可讀取其中的某一項(xiàng)。再輔以數(shù)組變量和循環(huán),問題就迎刃而解了。
“備份舊題”——是將庫中現(xiàn)存的題保存到txt文件中,以備未來使用或存檔之需。同理,備份文件也被指定存放在c:上,待用戶稍后取走。請(qǐng)看程序:
AppendExtFile("c:\備份舊題_danx.txt","
編號(hào) 題干
答案A 答案B
答案C 答案D
正答Return
sqlstring:="select min(編號(hào)) from xuanzeti"minid:=ODBCExecute(ODBCHandle,sqlstring)
sqlstring:="select max(編號(hào)) from xuanzeti"
maxid:=ODBCExecute(ODBCHandle,sqlstring)
圖7
--查出最小的ID值和最大的ID值
repeat with i:=minid to maxid
sqlstring:="select * from xuanzeti where xuanzeti.編號(hào) ="^i
jilu:=ODBCExecute(ODBCHandle,sqlstring)
AppendExtFile("c:\備份舊題_danx.txt",jilu^Return)end repeat
acctotxt:=ReadExtFile("c:\備份舊題_danx.txt")
txtline:=LineCount(acctotxt)
--從access備份形成的txt文件中得出記錄的條數(shù)。
SystemMessageBox(WindowHandle,"舊題備份完畢。共"^txtline-1^"條。"^Return^"請(qǐng)?jiān)赾:\取走文件"^"“"^"備份舊題_danx.txt”。","告知",48)
GoTo(@"題庫操作")
與前面?zhèn)魉托骂}相反,它是將數(shù)據(jù)庫中的信息寫入txt文件,使用函數(shù)AppendExtFile()先創(chuàng)建txt文件,并將字段名寫入,再循環(huán)讀取數(shù)據(jù)庫中各條記錄,追加進(jìn)該文件。
無論是傳送還是備份,系統(tǒng)都要提示用戶文件名是什么,放在哪里,注意些什么問題。大大提高了軟件的易用性。
“清空舊題”——是將當(dāng)前題庫中的記錄刪除,只保留表結(jié)構(gòu),以備傳送新題。程序代碼非常簡(jiǎn)單:
SystemMessageBox(WindowHandle, "您確實(shí)要清空嗎?", "警告" ,36)
sqlstring:="delete from xuanzeti"
qingkong:=ODBCExecute(ODBCHandle,sqlstring)
因?yàn)槊繄?chǎng)考試都可能是不同的考生,為了節(jié)省時(shí)間,減少折騰,我們常常需要預(yù)先集體批量注冊(cè),把當(dāng)場(chǎng)考試的考生信息傳送至數(shù)據(jù)庫,讓考生開考時(shí)直接登錄。
注冊(cè)的傳送、備份、清空與題庫管理類似,只是對(duì)接的數(shù)據(jù)表不同而已。
考生的原始成績(jī)信息,可以分析出很多反映試卷質(zhì)量指標(biāo)和教學(xué)質(zhì)量指標(biāo)的數(shù)據(jù),如考試信度、效度、區(qū)分度、難度和及格率、優(yōu)分率、平均分等,在程序中加入相應(yīng)的模塊很容易實(shí)現(xiàn)??紤]程序的簡(jiǎn)明,本系統(tǒng)未做安排?!俺煽?jī)回收”只對(duì)考生最基本的成績(jī)信息進(jìn)行回收,包括“序號(hào)”、“學(xué)號(hào)”、“姓名”、“填空”、“單選”、“多選”、“總分”等。為了方便識(shí)別回收的成績(jī)文件,程序在創(chuàng)建成績(jī)文件時(shí),文件名中包含“科目”和“日期”的信息,因此,之前要對(duì)“科目”變量kemu和“日期”變量riqi賦值。
“確定”圖標(biāo)中源程序如下:
AppendExtFile("c:\"^"《"^kemu^"》"^"成績(jī)_"^riqi^".txt","序號(hào) 學(xué)號(hào) 姓名填空 單選 多選 總分"^Return)
sqlstring:="select min(ID) from chengji"
minid:=ODBCExecute(ODBCHandle,sqlstring)
sqlstring:="select max(ID) from chengji"
maxid:=ODBCExecute(ODBCHandle,sqlstring)
--查出最小的ID值和最大的ID值
repeat with i:=minid to maxid
sqlstring:="select * from chengji where chengji.ID="^i
jilu:=ODBCExecute(ODBCHandle,sqlstring)
AppendExtFile("c:\"^"《"^kemu^"》"^"成 績(jī) _"^riqi^".
txt",jilu^Return)
end repeat
acctotxt:=ReadExtFile("c:\"^"《"^kemu^"》"^"成績(jī) _"^riqi^".txt")
txtline:=LineCount(acctotxt)
--從access回收形成的txt文件中得出記錄的條數(shù)。
SystemMessageBox(WindowHandle,"成績(jī)回收完畢。共"^txtline-1^"條。"^Return^"請(qǐng)?jiān)赾:\取走文件"^"“"^"《"^kemu^"》"^"成績(jī)_"^riqi^".txt”。","告知",48)
GoTo(@"封面2")
當(dāng)然,我們還可以為“成績(jī)回收”增加選擇性回收的功能,使其更加方便和完善。
如果不用考試管理系統(tǒng),我們也可以手工對(duì)數(shù)據(jù)庫進(jìn)行操作,但是相當(dāng)麻煩的工作,而且一要求用戶有使用數(shù)據(jù)庫的技能,二要求計(jì)算機(jī)能提供Access環(huán)境。特別是數(shù)據(jù)庫的安全可能因此受到威脅,結(jié)構(gòu)可能遭到破壞,甚至招致整個(gè)系統(tǒng)癱瘓??梢?,考試管理系統(tǒng)的作用是十分重要的。