驾照考试系统

其实本程序主要是熟悉了windows系统的应用程序基于消息机制的编程,同时熟悉了几个控件的操作,下面上主要的代码

新建一个基于DLG的mfc程序,加上下面的头文件

#include <iostream>
using namespace std;
//问题的结构体
struct Question
{
    string question;
    string answer[4];
    int right_answer;
};
//定义全局变量  100个题目
Question quest[100];
question.h头文件

DLG成员

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;//当前输出的题目数量
};
DLG的成员

 其中count2用来保存读取的题目的个数,count_Q用来保存当前输出的题目个数,mark为考试当前得分,QS保存每次进入考试的时候随机生成的考试题目序号

DLG的初始化代码

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] = '';
    file.Read(pBuf,len);
    file.Close();
    //将缓冲区的题目转换至结构体中 count用于计算复制给那个结构体中的东西
    int count = 0;
    count2 = 0;
    for (int i = 0,j = 0;pBuf[j] != '';j++)
    {
        if (pBuf[j] == '
')
        {
            char * temp = new char[j-i+1];
            temp[j-i] = '';
            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
}
DLG对话框初始化代码

这里主要是用了一个读取文件的算法,首先将放置在记事本中以相同格式摆放的字符读取到缓冲区中,然后按照循环将字符串分离,放置到指定的结构体中,这里就完成了题库的初始化,其中算法流程如下:

下面就是主界面框的响应函数了,在主界面添加了下面的几个控件,左下角的listbox空间,右边的下一题按钮,还有listbox上面的一个编辑框(),,其中,编辑框用来防止题目,listbox用来防止选项(假如是学习模式,那么listbox显示正确答案).然后是正确和取消按钮都是退出程序(新建向导自动生成的,也懒得删除了.)

 下面咱们开始做东西了哈.首先是添加单选按钮的相应函数如下

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()));
}
学习按钮响应函数
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,初始化随机数种子,然后生成一个随机数数列,且里面的数不重复(生成算法专门罗列),然后将保存的随即题目的第一题输出.

下面是最重要的下一题按钮的响应函数.代码如下:

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;
    }
}
NextButton响应函数

首先判断当前选定的是学习还是考试按钮,假如是学习,将题目计数器++,然后判定题库是否用完,然后清空控件,输出下一个题目及答案.

假如选定的考试,首先判定是否在listbox里面选定了某个答案,若没有,则跳出函数,return,否则将题目计数器++,然后判定选定的答案是否是正确答案,正确,则mark++,下面判断要考试的5个题目是否已经考完,假如考完了,则提示当前得分,若没考完,则输出下一个随机题目.

如果没有选定单选按钮,则提示要选择,不然程序会崩溃.

上面就是整个流程,在编程过程中,遇到很多的困难,尤其是控件的使用问题,全部是自己百度+摸索得出来的.然后就是这次自己写了一个读取文件的算法,学习了一个用空间换取时间的不同的随机数生成算法,感觉还是蛮好

本次编程中感觉自己略显不足的地方:

1.编程的时候思绪不够清晰,比较混乱,尤其是变量的命名,多了以后就分不清了.下次注意

不过欣慰的是,虽然写程序遇到过很多问题,但是都凭着良好的感觉将问题给解决了.

替换了默认的图标,感觉不错,附上最喜欢的钢琴曲一首

原文地址:https://www.cnblogs.com/color-my-life/p/3213524.html