驾照考试系统
其实本程序主要是熟悉了windows系统的应用程序基于消息机制的编程,同时熟悉了几个控件的操作,下面上主要的代码
新建一个基于DLG的mfc程序,加上下面的头文件
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> using namespace std; //问题的结构体 struct Question { string question; string answer[4]; int right_answer; }; //定义全局变量 100个题目 Question quest[100];
DLG成员
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
class CTESTDlg : public CDialog { // Construction public: CTESTDlg(CWnd* pParent = NULL); // standard constructor // Dialog Data //{{AFX_DATA(CTESTDlg) enum { IDD = IDD_TEST_DIALOG }; // NOTE: the ClassWizard will add data members here //}}AFX_DATA // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CTESTDlg) protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL // Implementation protected: HICON m_hIcon; // Generated message map functions //{{AFX_MSG(CTESTDlg) virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); afx_msg void OnStudy(); afx_msg void OnSelchangeAnswers(); afx_msg void OnTest(); afx_msg void OnNextbt(); //}}AFX_MSG DECLARE_MESSAGE_MAP() private: int mark;//考试分值,五个题目,一个20分,满分100 int QS[5];//随机题库序号 int count2;//题库总数 int count_Q;//当前输出的题目数量 };
其中count2用来保存读取的题目的个数,count_Q用来保存当前输出的题目个数,mark为考试当前得分,QS保存每次进入考试的时候随机生成的考试题目序号
DLG的初始化代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
BOOL CTESTDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here //读取题目,放置到题目结构体中 CFile file("test.txt",CFile::shareExclusive); char *pBuf; DWORD len; len = file.GetLength(); pBuf = new char[len+1]; pBuf[len] = '\0'; file.Read(pBuf,len); file.Close(); //将缓冲区的题目转换至结构体中 count用于计算复制给那个结构体中的东西 int count = 0; count2 = 0; for (int i = 0,j = 0;pBuf[j] != '\0';j++) { if (pBuf[j] == '\n') { char * temp = new char[j-i+1]; temp[j-i] = '\0'; for (int k = i;k < j;k++) { temp[k-i] = pBuf[k]; } if (count%6 == 0) { quest[count2].question.append(temp,j-i); } if (count%6 == 1) { quest[count2].answer[0].append(temp,j-i); } if (count %6 == 2) { quest[count2].answer[1].append(temp,j-i); } if (count %6 == 3) { quest[count2].answer[2].append(temp,j-i); } if (count %6 == 4) { quest[count2].answer[3].append(temp,j-i); } if (count %6 == 5) { quest[count2].right_answer = atoi(temp); count2++; } delete temp; i = j; count++; } } return TRUE; // return TRUE unless you set the focus to a control }
这里主要是用了一个读取文件的算法,首先将放置在记事本中以相同格式摆放的字符读取到缓冲区中,然后按照循环将字符串分离,放置到指定的结构体中,这里就完成了题库的初始化,其中算法流程如下:
下面就是主界面框的响应函数了,在主界面添加了下面的几个控件,左下角的listbox空间,右边的下一题按钮,还有listbox上面的一个编辑框(),,其中,编辑框用来防止题目,listbox用来防止选项(假如是学习模式,那么listbox显示正确答案).然后是正确和取消按钮都是退出程序(新建向导自动生成的,也懒得删除了.)
下面咱们开始做东西了哈.首先是添加单选按钮的相应函数如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void CTESTDlg::OnStudy() { // TODO: Add your control notification handler code here //将题目计数器置0,同时将listbox控件清空,插入第一个题目,放置正确答案在控件中 count_Q = 0; ((CListBox*)GetDlgItem(IDC_ANSWERS))->ResetContent(); SetDlgItemText(IDC_EDITQT,quest[count_Q].question.c_str()); ((CListBox*)GetDlgItem(IDC_ANSWERS))->AddString((quest[count_Q].answer[quest[count_Q].right_answer].c_str())); }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void CTESTDlg::OnTest() { // TODO: Add your control notification handler code here //初始化获得分值 mark = 0; //初始化随机数种子 srand((int)time(0)); //生成将要考试的10个随机数题目 int *NBuf = new int[count2]; for(int i = 0;i <= count2;i++) NBuf[i] = i; for (i = 0;i <= 4;i++) { int temp = rand()%(count2+1); while(NBuf[temp] == -1) { temp = rand()%(count2+1); } QS[i] = NBuf[temp]; NBuf[temp] = -1; } //将题目计数器置0,同时将listbox控件清空,插入第一个题目,放置所有答案在控件中 count_Q = 0; ((CListBox*)GetDlgItem(IDC_ANSWERS))->ResetContent(); SetDlgItemText(IDC_EDITQT,quest[count_Q].question.c_str()); for(i = 0;i <= 3;i++) ((CListBox*)GetDlgItem(IDC_ANSWERS))->AddString((quest[QS[count_Q]].answer[i].c_str())); }
下面咱们仔细分析下,
当我们按下学习按钮,首先将当前输出题目count_Q置为0,即第一个题目,然后将对应的题目和正确答案放置于相应的控件上.
假如按下的是考试按钮,首先同样将count_Q置0,但是这里的准备工作要稍微多点,因为涉及到随机生成的问题,成绩初始化为0,初始化随机数种子,然后生成一个随机数数列,且里面的数不重复(生成算法专门罗列),然后将保存的随即题目的第一题输出.
下面是最重要的下一题按钮的响应函数.代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
void CTESTDlg::OnNextbt() { if (GetCheckedRadioButton(IDC_STUDY,IDC_TEST) == IDC_STUDY) {//如果是选择的学习 count_Q++; if (count_Q == count2+1) { MessageBox("题库已完","提示",MB_OK); } ((CListBox*)GetDlgItem(IDC_ANSWERS))->ResetContent(); SetDlgItemText(IDC_EDITQT,quest[count_Q].question.c_str()); ((CListBox*)GetDlgItem(IDC_ANSWERS))->AddString((quest[count_Q].answer[quest[count_Q].right_answer].c_str())); } else if(GetCheckedRadioButton(IDC_STUDY,IDC_TEST) == IDC_TEST) {//选择的是考试 count_Q++; //进行成绩判定 if ((((CListBox*)GetDlgItem(IDC_ANSWERS))->GetCurSel()) ==quest[count_Q-1].right_answer) { mark++; } if (5 ==count_Q) { string temp = "考试已经考完,您的成绩为:"; char t[5]; itoa(mark*20,t,10); temp.append(t); MessageBox(temp.c_str()); return; } //清空listbox和编辑框,然后输入下个题目 ((CListBox*)GetDlgItem(IDC_ANSWERS))->ResetContent(); SetDlgItemText(IDC_EDITQT,quest[QS[count_Q]].question.c_str()); for(int j = 0;j <= 3;j++) ((CListBox*)GetDlgItem(IDC_ANSWERS))->AddString((quest[QS[count_Q]].answer[j].c_str())); }else {//防止未选择类型而导致程序崩溃 MessageBox("请选择 学习 或者 考试类型"); return; } }
首先判断当前选定的是学习还是考试按钮,假如是学习,将题目计数器++,然后判定题库是否用完,然后清空控件,输出下一个题目及答案.
假如选定的考试,首先判定是否在listbox里面选定了某个答案,若没有,则跳出函数,return,否则将题目计数器++,然后判定选定的答案是否是正确答案,正确,则mark++,下面判断要考试的5个题目是否已经考完,假如考完了,则提示当前得分,若没考完,则输出下一个随机题目.
如果没有选定单选按钮,则提示要选择,不然程序会崩溃.
上面就是整个流程,在编程过程中,遇到很多的困难,尤其是控件的使用问题,全部是自己百度+摸索得出来的.然后就是这次自己写了一个读取文件的算法,学习了一个用空间换取时间的不同的随机数生成算法,感觉还是蛮好
本次编程中感觉自己略显不足的地方:
1.编程的时候思绪不够清晰,比较混乱,尤其是变量的命名,多了以后就分不清了.下次注意
不过欣慰的是,虽然写程序遇到过很多问题,但是都凭着良好的感觉将问题给解决了.
替换了默认的图标,感觉不错,附上最喜欢的钢琴曲一首