{ AfxMessageBox("必须设置一个正确答案!,然后确认"); return; }
UpdateData(true);
if(m_Judge == "") { AfxMessageBox("必须填写出该题的题目!然后确认"); return; }
//将当前判断题序号所对应的答案处理成字符串写入当前的INI文件
CString strKey; CString strSel; strSel.Format("Item%d", iJudge);
if(RedioY->GetCheck()) strKey = "Y"; if(RedioN->GetCheck()) strKey = "N";
::WritePrivateProfileString("JudgeResult",strSel,strKey,strINI);
//将判断题序号所对应的题目写入题库、题目索引写入INI文件
strFilename.Format( ".\\TestBase\\%dJudge%d.txt", iconFig, iJudge );
::WritePrivateProfileString( "JudgeTitle", strSel, strFilename, strINI );
WriteFile( strFilename );
//设置写入INI成功后将列表框中当前选中的判断题选项标题变为OK!并给出提示
CString strList; strList.Format( " 判断题%d OK!", iJudge );
m_List.DeleteString(ListJudgePos); m_List.InsertString( ListJudgePos, strList );
CString strTitle; strTitle.Format( "设置判断题%d答案成功", iJudge );
AfxMessageBox(strTitle); GetDlgItem(IDC_JUDGE_OK)->SetWindowText("OK!");
}
第五步:即多选题设置对话框如图5,这部分主要完成的功能是将多选题显示在列表中;将判断题的题目标题写入题库中,再将相应题目索引以及设置的标准答案记录在当前所在那套题的INI文件中,具体代码如下步骤进行处理。
首先为文本框添加CString 类型变量m_SelectMore并设置如下几个全局变量
CButton *Redio1; CButton *Redio2; CButton *Redio3; CButton *Redio4;
int iA =0; int iB=0; int iC=0; int iD=0; //记录各Redio单选按钮状态,0表示未选中,1表示选中
int iMoreCount; //多选题的数量
int iSelectMore ; //记录当前多选题序号
int ListMorePos; //记录当前多选题选项在列表中的位置,便于完成答案时给出OK提示
int iconfig; //当前所选中那套题的序号
CString strCurrentini; //当前的INI文件路径文件名
CString strfileName; //记录当前多选题所对应题库中的文件名
然后为该对话框添加初始化消息函数WM_INITDIALOG并在其中添加如下代码,主要功能是为全局变量中定义的各变量赋予初始值以方便各地方调用,代码如下
Redio1 = (CButton *)GetDlgItem(IDC_RADIOA); Redio2 = (CButton *)GetDlgItem(IDC_RADIOB);
Redio3 = (CButton *)GetDlgItem(IDC_RADIOC); Redio4 = (CButton *)GetDlgItem(IDC_RADIOD);
//从INI总表中获得当前那套题的序号并处理成INI文件名,以方便在各个地方进行正确读写
iconfig = ::GetPrivateProfileInt("CONFIG","CurrentConfig", 0 , ".\\CONFIG.INI");
strCurrentini.Format(".\\Config%d.ini", iconfig);
//从INI总表中获得多选题数量并将选题显示在列表中,同时对已设置的赋予OK标志以防遗漏
iMoreCount = ::GetPrivateProfileInt("CONFIG","SelectMoreCount", 0 , ".\\CONFIG.INI");
CString strItem; CString strListItem; CString strResult;
for( int i=1; i<=iMoreCount; i++ )
{ strItem.Format("Item%d", i);
::GetPrivateProfileString("SelectMoreTitle",strItem,NULL,strResult.GetBuffer(128),128,strCurrentini);
if(strResult!="") { strListItem.Format(" 多选题%d OK!", i); m_List.AddString(strListItem); }
else { strListItem.Format(" 多选题%d", i); m_List.AddString(strListItem); }
}
分别添加一个WriteFile(CString FileName)函数和ReadFile(CString FileName)函数,主要功能是将多选题中设置的题目写入题库中或从题库中读出选题题目并在文本框中显示出来。
void CDlg_SetSelectMore::WriteFile(CString FileName)
{ CFile file; file.Open(strfileName,CFile::modeWrite|CFile::modeCreate);
int len=m_SelectMore.GetLength(); char *buffer=new char[len+1];
strcpy(buffer,m_SelectMore); buffer[len]='\0';
file.Write(buffer,len); file.Close(); delete buffer;
}
void CDlg_SetSelectMore::ReadFile(CString FileName)
{CFile file; if(!file.Open(strfileName,CFile::modeRead)) { m_SelectMore=""; UpdateData(false); return; }
else
{ int len=file.GetLength(); char *buffer=new char[len+1]; file.Read(buffer,len); buffer[len]='\0';
m_SelectMore=buffer; UpdateData(FALSE); delete buffer; file.Close();
}
}
这部分主要针对多选题选项的单击响应处理,主要功能是根据单击时的所在标记与提示并从当前INI配置文件中获取当前题目标题与答案显示出来,以方便修改。
先添加一个多选题选项的设置函数SetMoreItem(),具体代码如下:
void CDlg_SetSelectMore::SetMoreItem()
{ //清空所有被选中的单选框以避免引起混乱
Redio1->SetCheck(0); Redio2->SetCheck(0); Redio3->SetCheck(0); Redio4->SetCheck(0);
//根据单击多选题选项时的标记,从INI配置中找出该题的配置的答案并显示出来
CString strSelectItem; strSelectItem.Format("SelectMoreItem%d",iSelectMore);
iA = ::GetPrivateProfileInt(strSelectItem,"A",0,strCurrentini);
iB = ::GetPrivateProfileInt(strSelectItem,"B",0,strCurrentini);
iC = ::GetPrivateProfileInt(strSelectItem,"C",0,strCurrentini);
iD = ::GetPrivateProfileInt(strSelectItem,"D",0,strCurrentini);
if(iA == 1) Redio1->SetCheck(1); if(iB == 1) Redio2->SetCheck(1);
if(iC == 1) Redio3->SetCheck(1); if(iD == 1) Redio4->SetCheck(1);
//根据单击多选题选项时的标记,从INI配置中找出该题的配置题目并在Edit框中显示出来
CString strItemName; strItemName.Format( "Item%d", iSelectMore );
::GetPrivateProfileString("SelectMoreTitle",strItemName,NULL,strfileName.GetBuffer(128),128,strCurrentini);
ReadFile(strfileName);
//设置多选题按下时窗口与确认按钮的标题
CString strDlgTitle; CString strOK;
strDlgTitle.Format( "多选题%d", iSelectMore ); SetWindowText(strDlgTitle);
strOK.Format( "确认多选题%d的设置", iSelectMore );
GetDlgItem(IDC_MORE_OK)->SetWindowText(strOK+"的设置");
}
然后为列表框添加列表单击响应函数且在函数中作好标记后调用多选题的配置函数: void CDlg_SetSelectMore::OnSelchangeList1()
{ ListMorePos = m_List.GetCurSel(); iSelectMore = m_List.GetCurSel()+1; SetMoreItem(); }
既然是多选题就必须为Redio单选按钮组设置多选与取消选中的功能,方法是首先依次为添加单击消息响应函数并依次进入个Redio按钮,给出如下相应代码。
void CDlg_SetSelectMore::OnRadio1()
{ //Redio1单选按钮按下时根据全局变量中iA,iB,iC,iD值来确定当前选中状态
if(iA == 1) Redio1->SetCheck(1); if(iB == 1) Redio2->SetCheck(1);
if(iC == 1) Redio3->SetCheck(1); if(iD == 1) Redio4->SetCheck(1);
//设置Redio单选按钮1的选中与取消功能
if(iA == 0) { Redio1->SetCheck(1); iA = 1; return; }
else { Redio1->SetCheck(0); iA = 0; return; }
}
void CDlg_SetSelectMore::OnRadio2()
{ //Redio2单选按钮按下时根据全局变量中iA,iB,iC,iD值来确定当前选中状态
if(iA == 1) Redio1->SetCheck(1); if(iB == 1) Redio2->SetCheck(1);
if(iC == 1) Redio3->SetCheck(1); if(iD == 1) Redio4->SetCheck(1);
//设置Redio单选按钮2的选中与取消功能
if(iB == 0) { Redio2->SetCheck(1); iB = 1; return; }
else { Redio2->SetCheck(0); iB = 0; return; }
}
void CDlg_SetSelectMore::OnRadio3()
{ //Redio3单选按钮按下时根据全局变量中iA,iB,iC,iD值来确定当前选中状态
if(iA == 1) Redio1->SetCheck(1); if(iB == 1) Redio2->SetCheck(1);
if(iC == 1) Redio3->SetCheck(1); if(iD == 1) Redio4->SetCheck(1);
//设置Redio单选按钮3的选中与取消功能
if(iC == 0) { Redio3->SetCheck(1); iC = 1; return; }
else { Redio3->SetCheck(0); iC = 0; return; }
}
void CDlg_SetSelectMore::OnRadio4()
{ //Redio4单选按钮按下时根据全局变量中iA,iB,iC,iD值来确定当前选中状态
if(iA == 1) Redio1->SetCheck(1); if(iB == 1) Redio2->SetCheck(1);
if(iC == 1) Redio3->SetCheck(1); if(iD == 1) Redio4->SetCheck(1);
//设置Redio单选按钮4选中与取消功能
if(iD == 0) { Redio4->SetCheck(1); iD = 1; return; }
else { Redio4->SetCheck(0); iD = 0; return; }
}
确认按钮的处理,这部分所主要完成的功能是将当前所设置的多选题题目与答案写入当前的INI文件中:
void CDlg_SetSelectMore::OnMoreOk()
{ //检测多选题设置格式是否合要求
UpdateData(true);
if(m_SelectMore == "") { MessageBox("必须填写出该题的题目!然后确认"); return; }
CString strList; CString strTitle;
if(!Redio1->GetCheck()&&!Redio2->GetCheck()&&!Redio3->GetCheck()&&!Redio4->GetCheck())
{ MessageBox("必须设置答案!,然后确认"); strList.Format( " 多选题%d", iSelectMore );
m_List.DeleteString(ListMorePos); m_List.InsertString( ListMorePos, strList ); return;
}
else //设置成功后给出相应的提示
{ strList.Format( " 多选题%d OK!", iSelectMore );
m_List.DeleteString(ListMorePos); m_List.InsertString( ListMorePos, strList );
strTitle.Format("多选题%d设置成功", iSelectMore); AfxMessageBox(strTitle);
GetDlgItem(IDC_MORE_OK)->SetWindowText("OK!");
}
//将多选题序号所对应的标准答案处理成字符串写入当前那套题的INI文件中
CString strResult1="0"; CString strResult2="0"; CString strResult3="0";CString strResult4="0";
CString strItem; strItem.Format("SelectMoreItem%d",iSelectMore);
if(Redio1->GetCheck()) strResult1 = "1"; if(Redio2->GetCheck()) strResult2 = "1";
if(Redio3->GetCheck()) strResult3 = "1"; if(Redio4->GetCheck()) strResult4 = "1";
::WritePrivateProfileString(strItem,"A",strResult1,strCurrentini);
::WritePrivateProfileString(strItem,"B",strResult2,strCurrentini);
::WritePrivateProfileString(strItem,"C",strResult3,strCurrentini);
::WritePrivateProfileString(strItem,"D",strResult4,strCurrentini);
//将多选题序号所对应的题目写入题库、题目索引写入INI文件
CString strSelect; strSelect.Format("Item%d", iSelectMore);
strfileName.Format( ".\\TestBase\\%dMore%d.txt", iconfig, iSelectMore );
::WritePrivateProfileString("SelectMoreTitle", strSelect, strfileName, strCurrentini);
WriteFile(strfileName);
}
这样便完成了网考试卷制作机的网考试卷制作功能,所制作的最终结果就是一个INI配置总表,各套考题所对应的INI表和一个题库。最后交代一下操作题部分的处理如图6所示,这部分主要针对的是中小学网考的操作题部分,在此仅提出一个探讨性的解决实施方案意见,其中的文本框主要用来记录考题题目。
(1)文本框Redio按钮,则主要用来处理限时对照打字操作题。实现时注意限制规定的字符数如200个英文字符作为评分的根据;评分时可根据字符串的比较来决定给分。
(2)IE操作Redio按钮,则主要用来处理浏览网页、保存网页、设置主页等操作。实现时可将题目与要求同时写入相应的INI文件中作为评分的根据;评分时可根据检测网页标题、查找文件等方式来进行给分。
(3)文件操作Redio按钮,则主要用来处理文件文件夹的创建、删除、复制、移动等操作。实现时可将题目与要求同时写入相应的INI文件中来作为评分的根据;评分时则根据查找文件、文件夹的方式来决定给分。
(4)其余几项如设置字体、字号操作等操作。首先启动出相应类型的文件并在其中给出样题和几个标准答案来作为评分的根据写入INI文件;评分时则根据对比的方式来决定给分。
2.网考机的实现方法
由于网考试卷制作机是将考试的一切设置基本配置在INI总表中、各套考题题目配置在题库中、各考题的题目索引与答案配置在各自的INI文件中。故网考机设计的关键就是如何从总表中获得基本配置数据并决定启动出那一套考题;然后根据选中的INI题目索引记载启动出题库中所对应的考题;再将考试中的所有答案以及与标准答案相比较后所得的分数连同考号均记录在一个Temp.ini的文件中;最后在交卷完成考试时根据临时INI文件中的记载统计出各项分数及总分并写入以考生考号为文件名的INI文件中上传服务器,这样便完成了网考机的网考功能。具体方法是首先在MFC平台下创建一个名为IEExamSys的对话框程序基本布局如下图7、图8所示,具体处理按以下步骤进行。
图7 网考机界面 图8登录对话框
第一步:首先为列表框添加CListBox类型变量m_List且在属性中取消SORT属性;为Edit文本框添加CString类型变量m_edit且属性中设置为多行与允许回车;在头文件部添加包头代码
#include "Dlg_TestCord.h" //考号、密码对话框
(1)然后添加如下几个全局变量以方便在程序的各个地方随时赋值、取值
CButton *RedioA; CButton *RedioB; CButton *RedioC; CButton *RedioD;
int iRedio ; //记录单击答案组中的是第几个Redio单选按钮
int iA=0; int iB=0; int iC=0; int iD=0; //记录各Redio单选按钮选中状态, 其中1表示选中
int iSingleCount; int iJudgeCount; int iMoreCount; //依次用来记录单选题、判断题、选题数量
int iSingle = 0; int iJudge = 0; int iMore = 0; //记录各选题当前的题目序号
int iListSelPos; //记录当前选题列表中选中位置,便于在完成答题时给出OK提示
int iConfig; //当前所选中那套题的序号
CString strCurrentINI; //当前那套考题的INI文件路径与文件名
CString strFileName; //记录题库中所要打开的题目文件名
CString strTestCord; //记录考生考号
(2)在初始化程序BOOL CIEExamSysDlg::OnInitDialog()中添加如下代码:
//首先在初始化函数中为全局变量中定义的四个Redio单选按钮赋值
RedioA = (CButton *)GetDlgItem(IDC_RADIO1); RedioB = (CButton *)GetDlgItem(IDC_RADIO2);
RedioC = (CButton *)GetDlgItem(IDC_RADIO3);RedioD = (CButton *)GetDlgItem(IDC_RADIO4);
/*启动考号、密码登陆对话框其中所要完成的主要功能有:从INI总表中获得服务器的连接信息并以传统方式登陆服务器。以传统方式效验输入的考号与密码是否有效,如果有效则将考号显示在界面上并写入Temp.ini文件中;如果无效则返回该登陆框并给出提示。以传统方式决定该考生选用哪套题,决定后将INI总表中当前配置序号改写为选中那套题的序号以便在后面打开考题时不至于出错。以传统方式启动倒计时定时器开始答题。注意在程序中添加一个倒计时定时器。
说明:由于这部分均属于传统网考部分故在此略去有关代码。
从总表中读取当前所选中的那套题并处理成配置文件名赋予全局变量以方便调用*/
iConfig = ::GetPrivateProfileInt("CONFIG", "CurrentConfig", 0, ".\\CONFIG.INI");
strCurrentINI.Format(".\\Config%d.ini", iConfig);
//从总INI配置表中读取考号与考试时间并显示在网考机上(这部分略去)
//从INI总表中依次读取单选题、多选题、判断题的配置数量并将所有的考题显示在列表框中
iSingleCount = ::GetPrivateProfileInt("CONFIG", "SelectSingleCount", 0, ".\\CONFIG.INI");
iJudgeCount = ::GetPrivateProfileInt("CONFIG", "JudgeCount", 0, ".\\CONFIG.INI");
iMoreCount = ::GetPrivateProfileInt("CONFIG", "SelectMoreCount", 0, ".\\CONFIG.INI");
int iSinglePoints = ::GetPrivateProfileInt("CONFIG", "SelectSinglePoints", 0, ".\\CONFIG.INI");
int iJudgePoints = ::GetPrivateProfileInt("CONFIG", "JudgePoints", 0, ".\\CONFIG.INI");
int iMorePoints = ::GetPrivateProfileInt("CONFIG", "SelectMorePoints", 0, ".\\CONFIG.INI");
CString strListItem;
strListItem.Format("一单选题(每小题%d分)", iSinglePoints); m_List.AddString(strListItem);
for(int i=1;i<=iSingleCount;i++) {strListItem.Format(" 单选题%d",i)
;m_List.AddString(strListItem);}
if( iJudgeCount != 0 )
{ strListItem.Format("二判断题(每小题%d分)",iJudgePoints);
m_List.AddString(strListItem);
for( int ii=1; ii<=iJudgeCount; ii++ )
{strListItem.Format(" 判断题%d",ii); m_List.AddString(strListItem);}
}
if(iMoreCount!=0)
{ if(iJudgeCount==0) //如果没有设置判断题,那么多选题的标题序号也随着改变
{ strListItem.Format("二多选题(每小题%d分)", iMorePoints);
m_List.AddString(strListItem); }
else { strListItem.Format("三多选题(每小题%d分)",
iMorePoints);m_List.AddString(strListItem); }
for( int iii=1; iii<=iMoreCount; iii++ )
{ strListItem.Format(" 多选题%d",iii); m_List.AddString(strListItem); }
}
第二步:依次为单选题、判断题、多选题选项各添加一个配置处理函数并在列表单击响应函数中调用。所要完成的主要功能是设置Redio按钮组的显示格式;根据选中的INI题目索引记载从题库中启动出相应的题目;从Temp.ini记载中获取已做过的答案并显示出来,以方便更改。
首先添加一个ReadFile(CString FileName)函数,目的是从题库中启动出题目显示出来。
void CIEExamSysDlg:: ReadFile(CString FileName)
{ CFile file; if( !file.Open( strFileName, CFile::modeRead ) )
{ m_edit=""; UpdateData(false); AfxMessageBox("题库中没有找到该题!"); return; }
else
{ int len = file.GetLength(); char *buffer = new char[len+1];
file.Read(buffer,len); buffer[len] = '\0';
m_edit = buffer; UpdateData(FALSE); delete buffer; file.Close();
}
}
为单选题选项添加的配置函数是SelectSingleConfig()代码如下:
void CIEExamSysDlg::SelectSingleConfig()
{ //当处于单选题选项状态时应把判断题、多选题的题目序号标记清空
iJudge = 0; iMore = 0;
//设置单选题答案组所需要格式
RedioA->SetWindowText("A"); RedioB->ShowWindow(true);
RedioC->ShowWindow(true); RedioD->SetWindowText("D");
//清空所有被选中的单选框以避免引起混乱
RedioA->SetCheck(0); RedioB->SetCheck(0); RedioC->SetCheck(0); RedioD->SetCheck(0);
//根据单选题选中时留下的序号标记,从Temp.ini文件中获得做过的答案显示出来,便于更改
CString strSelectItem; CString strItemResult;
strSelectItem.Format("Item%d", iSingle);
::GetPrivateProfileString("SelectSingleResult",strSelectItem,NULL,strItemResult.GetBuffer(128),128,".\\Temp.ini");
if(strItemResult == "A") RedioA->SetCheck(1); if(strItemResult == "B") RedioB->
SetCheck(1);
if(strItemResult == "C") RedioC->SetCheck(1); if(strItemResult == "D") RedioD->
SetCheck(1);
//根据单选题序号标记,从INI配置中获得相应的题库索引并启动出题目显示在文本框中
::GetPrivateProfileString("SelectSingleTitle",strSelectItem,NULL,strFileName.GetBuffer(128),128, strCurrentINI);
ReadFile(strFileName);
}
为判断题选项添加的配置函数是JudgeConfig(),代码如下:
void CIEExamSysDlg::JudgeConfig()
{ //当处于判断题选项状态时把单选题、多选题的序号标记清空
iSingle = 0; iMore = 0;
//清空所有被选中的单选框以避免引起混乱
RedioA->SetCheck(0); RedioB->SetCheck(0); RedioC->SetCheck(0); RedioD->SetCheck(0);
//设置判断题答案组所需要的格式
RedioA->SetWindowText("正确"); RedioB->ShowWindow(false);
RedioC->ShowWindow(false); RedioD->SetWindowText("错误");
//根据判断题选中时留下的序号标记,从Temp.ini文件中获得做过的答案显示出来,便于更改
CString strSelectItem; CString strItemResult; strSelectItem.Format("Item%d", iJudge);
::GetPrivateProfileString("JudgeResult",strSelectItem,NULL,strItemResult.GetBuffer(128),128,".\\Temp.ini");
if(strItemResult == "Y") RedioA->SetCheck(1); if(strItemResult == "N") RedioD->
SetCheck(1);
//根据判断题序号标记,从INI配置中获得相应的题库索引并启动出题目显示在文本框中
::GetPrivateProfileString("JudgeTitle",strSelectItem,NULL,strFileName.GetBuffer(128),128,strCurrentINI);
ReadFile(strFileName);
}
为多选题选项添加的配置函数是SelectMoreConfig(),代码如下:
void CIEExamSysDlg::SelectMoreConfig()
{ //当处于多选题选项时应把单选题、判断题的序号标记清空
iSingle = 0; iJudge = 0;
//设置多选题答案组所需要的格式
RedioA->SetWindowText("A"); RedioB->ShowWindow(true);
RedioC->ShowWindow(true); RedioD->SetWindowText("D");
//清空所有被选中的单选框以避免引起混乱
RedioA->SetCheck(0); iA=0; RedioC->SetCheck(0); iC=0;
RedioB->SetCheck(0); iB=0; RedioD->SetCheck(0); iD=0;
//根据多选题选中时留下的序号标记,从Temp.ini文件中获得做过的答案显示出来,便于更改
|