崔麗紅
摘要:基于光標(biāo)閱讀機(jī)評(píng)卷系統(tǒng),定制實(shí)現(xiàn)了一種課程教學(xué)滿意度測(cè)評(píng)系統(tǒng)。介紹了測(cè)評(píng)系統(tǒng)組成,給出了信息卡打印、數(shù)據(jù)匯總分析處理兩個(gè)功能模塊的實(shí)現(xiàn)方法和源代碼,為快速準(zhǔn)確采集處理來(lái)源分散、數(shù)量巨大的測(cè)評(píng)信息提供了一種簡(jiǎn)單易用的輔助工具。
關(guān)鍵詞:測(cè)評(píng)卡設(shè)計(jì);課程編碼;匯總統(tǒng)計(jì);數(shù)據(jù)分析
中圖分類號(hào):G424 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2016)36-0121-03
光學(xué)標(biāo)記閱讀機(jī)(Optical Mark Reader),簡(jiǎn)稱OMR,是一種高速的信息錄入設(shè)備,它集光、機(jī)、電于一體,運(yùn)用光電轉(zhuǎn)換原理以極快的速度識(shí)別填涂點(diǎn),從載有信息的信息卡上讀取數(shù)據(jù),并通過(guò)數(shù)據(jù)電纜送入計(jì)算機(jī)。由于OMR每秒鐘錄入數(shù)千個(gè)信息,且誤碼率極低。因此,OMR在標(biāo)準(zhǔn)化考試、報(bào)名管理、稅務(wù)申報(bào)、戶籍管理、人口普查、投票選舉、民意測(cè)驗(yàn)、干部測(cè)評(píng)、彩票發(fā)行等眾多領(lǐng)域被應(yīng)用。
為實(shí)現(xiàn)課程教學(xué)質(zhì)量考核評(píng)價(jià)信息處理達(dá)到智能化、考評(píng)方法的規(guī)范化和輔助決策科學(xué)化,提高考評(píng)數(shù)據(jù)分析處理能力和工作效率,增強(qiáng)考評(píng)結(jié)果的信度和效度,我們研發(fā)了“基于OMR的課程教學(xué)質(zhì)量滿意度測(cè)評(píng)系統(tǒng)”(簡(jiǎn)稱系統(tǒng)),系統(tǒng)供教務(wù)部門測(cè)評(píng)課程教學(xué)質(zhì)量時(shí)對(duì)各種數(shù)據(jù)信息進(jìn)行統(tǒng)計(jì)匯總和分析處理,生成各種考評(píng)資料,管理各種考評(píng)信息,為準(zhǔn)確評(píng)價(jià)課程提供依據(jù)。系統(tǒng)與人工制作發(fā)放紙質(zhì)測(cè)評(píng)表、人工統(tǒng)計(jì)相比,它解決了人工易出錯(cuò)、效率低下,以及測(cè)評(píng)結(jié)果計(jì)算機(jī)數(shù)據(jù)錄入中的瓶頸問(wèn)題,把人們從繁重的機(jī)械勞動(dòng)中解脫出來(lái)。系統(tǒng)與直接用網(wǎng)絡(luò)測(cè)評(píng)系統(tǒng)相比,解決了需要將學(xué)生集中到計(jì)算機(jī)房以及匿名評(píng)價(jià)人數(shù)不易控制問(wèn)題,可以集中學(xué)生在短暫時(shí)間內(nèi)實(shí)施完成,使采集處理那些來(lái)源分散而數(shù)量巨大的信息變得輕而易舉,快速而準(zhǔn)確。
1 測(cè)評(píng)系統(tǒng)組成與使用流程
系統(tǒng)由光標(biāo)閱讀機(jī)、打印機(jī)、機(jī)讀信息卡和配套軟件、數(shù)據(jù)處理分析應(yīng)用軟件組成。系統(tǒng)應(yīng)用特點(diǎn)是統(tǒng)一制卡、分散填涂、集中錄入、快速處理。根據(jù)要采集的信息設(shè)計(jì)印制信息卡,并編制相應(yīng)的應(yīng)用軟件,然后把信息卡分發(fā)下去分散填涂,再把填涂好的卡收集起來(lái)用OMR閱讀,最后由計(jì)算機(jī)進(jìn)行分析處理和管理。因此,按照考評(píng)的工作流程,完成一次考評(píng)活動(dòng)可分為“考評(píng)準(zhǔn)備”〉“滿意度測(cè)評(píng)”〉“測(cè)評(píng)結(jié)果輸出”〉“測(cè)評(píng)結(jié)果分析”四個(gè)部分。
2 測(cè)評(píng)系統(tǒng)編程中具體代碼實(shí)現(xiàn)
2.1 測(cè)評(píng)機(jī)讀信息卡設(shè)計(jì)
根據(jù)測(cè)評(píng)課程的特點(diǎn)、要求和測(cè)評(píng)過(guò)程,合理設(shè)計(jì)機(jī)讀信息卡。匿名情況下,學(xué)號(hào)不涂寫。學(xué)生班次可以制卡時(shí)直接打印。編號(hào)的含義可以為在有多頁(yè)情況下的頁(yè)碼,也可以為學(xué)生班次,可以制卡時(shí)直接打印。通常情況下,測(cè)評(píng)信息卡片制作時(shí),課程名稱可在Microsoft Word中輸入套打。本文為了便于后續(xù)匯總統(tǒng)計(jì),將所有課程統(tǒng)一編碼放在數(shù)據(jù)庫(kù)中,在自主研發(fā)的軟件中讀取數(shù)據(jù)庫(kù)輸入課程名稱套打,優(yōu)點(diǎn)有二:一是可以分門別類選擇課程進(jìn)行選擇輸入打印,減少輸入錯(cuò)誤;二是編碼時(shí)只要將同一門課程的編碼設(shè)置相同,之后不管這門課程出現(xiàn)在哪一張卡片中,以及在卡片中的名稱如何,都可以正確匯總出這門課程測(cè)評(píng)票數(shù)。三是自由操作卡片中的所有信息。
2.1.1 讀取課程代碼
void CTXPropertyPage1::GetCodeMain()
{//讀取學(xué)生班次的代碼,以便在信息卡中按學(xué)生班次輸入課程
CComboBox* pBox1 = (CComboBox*)GetDlgItem(IDC_COMBO_CODEMAIN);
CString str;
int index=pBox1->GetCurSel();
pBox1->GetLBText(index,str);
ASSERT(m_pDB);
ASSERT(m_pDB->IsOpen());
CString strRecordIdQuery = _T( "name ='") + str + _T("'") ;
int nCodeMain;
CDaoRecordset rs(m_pDB);
try { CString strSelect(_T("Select * From ["));
strSelect += "codemain";//表名稱
strSelect += _T("]");
rs.Open(dbOpenDynaset,strSelect);
if ( rs . FindFirst ( strRecordIdQuery ) )
{ COleVariant var;
var = rs.GetFieldValue(2);
nCodeMain=V_I2(&var);}}
catch (CDaoException* e)
{ DisplayDaoException(e);
e->Delete();
return; }
rs.Close();
m_GeoAtt.m_nCodeMain=nCodeMain;
SetDlgItemInt(IDC_E_CODE_MAIN,nCodeMain);}
void CTXPropertyPage1::SetCodeSbCurSel_init()
{//設(shè)置當(dāng)前課程編碼和名稱
CComboBox* pBox2 = (CComboBox*)GetDlgItem(IDC_COMBO_CODESB);
ASSERT(m_pDB);
ASSERT(m_pDB->IsOpen());
int nCodeSb;
CDaoRecordset rs(m_pDB);
CString strCodeMain;
strCodeMain.Format("%d",m_GeoAtt.m_nCodeMain);
CString strSQL(_T("Select * From ["));
strSQL += "codesb";//表名稱
strSQL += _T("] ");
strSQL += "WHERE ([codemain] = " + strCodeMain +_T(" ) or ( [codemain] =0 ) ");
try {// Open the recordset using the filtered SQL string
rs.Open( dbOpenDynaset, strSQL );
pBox2->ResetContent();
COleVariant var;
rs.MoveFirst();
var = rs.GetFieldValue(1);
pBox2->AddString(CCrack::strVARIANT(var));
var=rs.GetFieldValue(2);
nCodeSb=V_I2(&var);
pBox2->SetCurSel(0);
rs.MoveNext();
while (!rs.IsEOF())
{ var = rs.GetFieldValue(1);
pBox2->AddString(CCrack::strVARIANT(var));
rs.MoveNext(); }}
catch (CDaoException* e)
{ DisplayDaoException(e);
e->Delete();
return; }
rs.Close();
if(!m_bFirst)
{ m_GeoAtt.m_nCodeSb=nCodeSb;
SetDlgItemInt(IDC_E_CODESB,nCodeSb);
CString str;
pBox2->GetLBText(pBox2->GetCurSel(),str);
SetDlgItemText(IDC_E_TEXT,str);}}
2.1.2 輸出課程信息及代碼
void CDrawView::SaveFilesAs()
{//在保存時(shí)輸出設(shè)計(jì)的信息卡的課程代碼和名稱
CFileDialog filedlg(FALSE,"*.drw","測(cè)評(píng)卡.drw",OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
"系統(tǒng)內(nèi)部文件 (*.drw) |*.drw|| ",NULL);
CMainFrame *pMainFrm = ((CMainFrame *)AfxGetMainWnd());
filedlg.m_ofn.lpstrInitialDir=pMainFrm->m_sMainDirectory;
if(filedlg.DoModal() == IDOK)
{ CString filename = filedlg.GetPathName();
CDrawDoc* pDoc = GetDocument();
pDoc->DoSave(filename);
//將套打結(jié)果存為與原始文件同名的txt格式文件
POSITION pos = pDoc->m_objects.GetHeadPosition();
int id = filename.ReverseFind('.');
filename=filename.Left(id)+".txt";
ofstream outfile(filename);
int iKechengshu=0;
int iXuhao=0; //套打數(shù)據(jù)記錄,輸出制卡時(shí)所填涂的隊(duì)號(hào)或頁(yè)碼
while (pos != NULL)
{ CDrawObj* pObj = pDoc->m_objects.GetNext(pos);
if(pObj->IsKindOf( RUNTIME_CLASS( CDrawRect)) &&!pObj->IsKindOf( RUNTIME_CLASS( CDrawText)))
{ iXuhao++;
if(pObj->m_GraphicAtt.m_nIndexfillmode)
{outfile< outfile< pos = pDoc->m_objects.GetHeadPosition(); //套打數(shù)據(jù)記錄,輸出序號(hào)、班級(jí)號(hào)、課程編碼和課程名稱 while (pos != NULL) { CDrawObj* pObj = pDoc->m_objects.GetNext(pos); if(pObj->IsKindOf( RUNTIME_CLASS( CDrawText)))
{ iKechengshu++;
outfile<
outfile< outfile.close(); }} 輸出文件的文本文件內(nèi)容,第一行為填涂的頁(yè)碼(編碼),其余各行為:序號(hào)、班號(hào)、課程編碼和課程名稱。實(shí)際上,在設(shè)計(jì)卡片時(shí)可將編號(hào)和20門課程的位置處分別留有矩形空白和文字空白,只需在輸入時(shí)將多余位置設(shè)為白色,即可不打印輸出課程名為空白的行。 2.2 測(cè)評(píng)信息處理 圖1 測(cè)評(píng)信息卡保存文件數(shù)據(jù)內(nèi)容 評(píng)估結(jié)果處理代碼如下: // InstrXlsFilePath為上面的測(cè)評(píng)結(jié)果統(tǒng)計(jì)表;InstrXlsFilePath為制卡時(shí)輸出的卡片信息文本文件 // OutstrXlsFilePath為輸出的結(jié)果文件 void CMainFrame::ProcessSourceData(CString InstrXlsFilePath,CString InstrTxtFilePath,CString OutstrXlsFilePath) { //寫表頭開(kāi)始 CStringArray sampleArray; sampleArray.RemoveAll(); sampleArray.Add("序號(hào)"); sampleArray.Add("課程編碼"); sampleArray.Add("課程名稱"); sampleArray.Add("優(yōu)秀"); sampleArray.Add("良好"); sampleArray.Add("合格"); sampleArray.Add("不合格"); ((CMainFrame*)AfxGetMainWnd())->ExportData(OutstrXlsFilePath,sampleArray); //寫表頭結(jié)束 CString stringBianhao="",stringXuhao="",stringZhuanyeBianma="",stringBianma="",stringKechengming="",stringAll=""; CString stringYouxiu="",stringLianghao="",stringHege="",stringBuhege=""; CStdioFile infile1; if(!infile1.Open(InstrTxtFilePath,CFile::modeRead)) { MessageBox("file error"); return; } infile1.ReadString(stringBianhao); int iYouxiu, iLianghao,iHege,iBuhege; int iTotalRows; iTotalRows = 0; for(int iItem = 0; iItem < 20; iItem ++) { sampleArray.RemoveAll(); CString strXuhao; strXuhao.Format("%d",iItem+1); sampleArray.Add(strXuhao); infile1.ReadString(stringAll); int nPositon; //空格位置 nPositon = 0; //第一個(gè)空格位置 for(int i=0;i stringKechengming = stringAll.Right(stringAll.GetLength()-nPositon);//最后一個(gè) stringAll=stringAll.Left(nPositon); for(int j=0;j { if(stringAll.GetAt(j)==(' ')) nPositon=j; } stringKechengming = stringAll.Right(stringAll.GetLength()-nPositon);//倒數(shù)第二個(gè) //處理空白情況 if(stringKechengming.Find("空白")==-1 ) { stringAll=stringAll.Left(nPositon); for(int k=0;k {if(stringAll.GetAt(k)==(' ')) nPositon=k;} stringBianma = stringAll.Right(stringAll.GetLength()-nPositon);//倒數(shù)第二個(gè) sampleArray.Add(stringBianma);
sampleArray.Add(stringKechengming);
{ //excel 文件讀取優(yōu)秀、良好、合格和不合格結(jié)果
CStringArray sampleArray2;
CSpreadSheet ssResult(InstrXlsFilePath,"測(cè)評(píng)原始數(shù)據(jù)"); ssResult.BeginTransaction();
iTotalRows=ssResult.GetTotalRows();
iYouxiu=0; iLianghao=0; iHege=0; iBuhege=0;
for(int M=3;M { ssResult.ReadRow(sampleArray2,M); //MessageBox(sampleArray2[2]); if(sampleArray2[2].GetAt(iItem)=='A') iYouxiu++; if(sampleArray2[2].GetAt(iItem)=='B') iLianghao++; if(sampleArray2[2].GetAt(iItem)=='C') iHege++; if(sampleArray2[2].GetAt(iItem)=='D') iBuhege++; }} stringYouxiu.Format("%d",iYouxiu); stringLianghao.Format("%d",iLianghao); stringHege.Format("%d",iHege); stringBuhege.Format("%d",iBuhege); sampleArray.Add(stringYouxiu); sampleArray.Add(stringLianghao); sampleArray.Add(stringHege); sampleArray.Add(stringBuhege); ((CMainFrame*)AfxGetMainWnd())->ExportData(OutstrXlsFilePath,sampleArray); }} stringAll=""; iTotalRows = iTotalRows-2;//從第三行開(kāi)始 stringAll.Format("成功匯總了%d條數(shù)據(jù)",iTotalRows); AfxMessageBox(stringAll);} void CMainFrame::ExportData(CString strXlsFlile, CStringArray &m_strarray) {//導(dǎo)出為Microsoft excel格式文件 CSpreadSheet ssSave(strXlsFlile,"DATA"); ssSave.BeginTransaction(); ssSave.AddRow(m_strarray); ssSave.Commit();} 3 結(jié)束語(yǔ) 通過(guò)以上思路實(shí)現(xiàn)了一個(gè)基于光標(biāo)閱讀機(jī)讀入數(shù)據(jù),然后利用程序進(jìn)行統(tǒng)計(jì)分析,可以實(shí)現(xiàn)學(xué)校課程教學(xué)質(zhì)量滿意度的測(cè)評(píng),實(shí)踐表明,只要在涂卡過(guò)程中完成按照要求進(jìn)行,系統(tǒng)就能夠滿足快速準(zhǔn)確測(cè)評(píng)的需要。使用過(guò)程中也發(fā)現(xiàn)一些問(wèn)題,比如使用激光打印機(jī)打印卡片可使卡片受熱發(fā)生彎曲,讀卡時(shí)易出現(xiàn)卡紙現(xiàn)象,應(yīng)保持信息卡的平整、干燥、潔凈,不折疊,可以使光標(biāo)閱讀機(jī)卡紙率大大下降;使用簽字筆或熒光筆涂卡會(huì)出現(xiàn)不能識(shí)別的情況;讀卡程序輸出的excel文件版本過(guò)老,使作者編寫的處理程序無(wú)法讀取數(shù)據(jù)等,在系統(tǒng)開(kāi)發(fā)過(guò)程中要注意解決這些問(wèn)題,可進(jìn)一步提高系統(tǒng)使用效率。