基於Qt實現駕校科目考試系統的示例代碼

1.設置登錄界面  

LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::LoginDialog)
{
    ui->setupUi(this);
    ui->imgLabel->setScaledContents(true);//設置填充
    this->resize(ui->imgLabel->width(),ui->imgLabel->height());//設置窗口大小
 
    //設置窗口標題
    this->setWindowTitle(("駕校科目一考試登錄"));
    //設置窗口風格
    this->setWindowFlags(Qt::Dialog |Qt::WindowCloseButtonHint);
}

2.登錄功能實現

2.1驗證郵箱地址

首先判斷輸入的賬號是否符合郵箱格式 ,如果符合則進行登錄驗證,否則提示格式錯誤

void LoginDialog::on_loginButton_clicked()
{
    //首先通過正則表達式判斷賬號是否是一個合法的郵箱格式
    //^:表示規則字符串開始、$:表示規則字符串的結束
    //+:表示匹配次數≥1次、*:表示匹配任意次數(可為0次) {n,m}表示匹配次數最少n次 最多m次
    QRegExp rx("^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$");//初始化時指定規則字符串
    bool res = rx.exactMatch(ui->accountEdit->text());//對用戶輸入的賬號進行匹配
    if(res){//匹配成功
        QMessageBox::information(this,"提示","歡迎登錄科目一考試科目系統");
    }else{//匹配不成功
        QMessageBox::information(this,"提示","非法郵箱地址!請您重新輸入");
        ui->accountEdit->clear();//清空賬號輸入框
        ui->codeEdit->clear();//清空密碼輸入框
        ui->accountEdit->setFocus();//賬號輸入框聚焦
        return ; 
    }
 
}

2.2賬號密碼登錄 

當賬號格式合法後,讀取保存賬號和密碼的文檔進行匹配

if(res){//匹配成功
//QMessageBox::information(this,"提示","歡迎登錄科目一考試科目系統");
QString filename;//文件路徑
QString AccInput;//用戶輸入賬號
QString strCode;//用戶輸入密碼
QString strLine;//每次讀取一行數據
QStringList strList;//分割讀取一行數據
 
filename="../account.txt";//設置文件路徑
AccInput=ui->accountEdit->text();//獲取賬號
strCode=ui->codeEdit->text();//獲取密碼
 
QFile file(filename);//初始化
QTextStream stream(&file);//文本類型文件流
//指定隻讀方式打開,指定文件類型式文本類型
if(file.open(QIODevice::ReadOnly|QIODevice::Text)){
    //打開成功
    while(!stream.atEnd()){
        strLine=stream.readLine();//每次讀取一行
        strList = strLine.split(",");//將讀取到的行按","分割
        if(AccInput==strList.at(0)){
            if(strCode==strList.at(1)){
                //賬號和密碼匹配成功
                QMessageBox::information(this,"提示","歡迎進入科目一考試系統");
                file.close();
                return ;
            }else{
                //賬號匹配成功&密碼不成功
                QMessageBox::information(this,"提示","密碼錯誤!請重新輸入!");
                ui->codeEdit->clear();
                ui->codeEdit->setFocus();
                file.close();
                return ;
            }
        }
    }
    QMessageBox::information(this,"提示","輸入賬號有誤!請重新輸入!");
    ui->accountEdit->clear();//清空賬號輸入框
    ui->codeEdit->clear();//清空密碼輸入框
    ui->accountEdit->setFocus();//賬號輸入框聚焦
    file.close();
    return;
}

2.3密碼隱藏 

將密碼控件的echoMode屬性值改為Password即可

3.考試界面開發 

3.1考試用時

首先添加一個考試對話框類;在考試對話框類中添加QTimer和int屬性用於表示計時器和已用時;設定計時器的時間間隔為1s,通過connect函數將計時器與已用時顯示信號槽連接起來

examDialog.h

#ifndef EXAMDIALOG_H
#define EXAMDIALOG_H
#include<QDialog>
#include<QTimer>
class ExamDialog : public QDialog
{
    Q_OBJECT//使用信號槽
public:
    ExamDialog(QWidget* parent=0);
    void initTimer();
private:
    QTimer*m_timer;//計時器
    int m_timeGo;//考試已用時
private slots:  //私有槽方法
    void freshTime();
};
 
#endif // EXAMDIALOG_H

examDialog.cpp 

#include "examdialog.h"
 
ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
    setWindowTitle("考試已用時:0分0秒");
    initTimer();
}
 
void ExamDialog::initTimer()
{
    m_timeGo=0;
    m_timer=new QTimer(this);
    m_timer->setInterval(1000);//設置計時器時間間隔1s
    m_timer->start();//啟動計時器
    //通過connect方法,連接信號槽。m_timer每發送timeout()信號時,由this執行槽方法freshTime()
    connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime()));
 
 
}
 
void ExamDialog::freshTime()
{
    //刷新考試用時
    m_timeGo++;
    QString min=QString::number(m_timeGo/60);//計算分鐘,將整數轉QString
    QString sec=QString::number(m_timeGo%60);
    setWindowTitle("考試已用時:"+min+"分"+sec+"秒");
}

3.2題目佈局 

添加屬性以及初始化方法

public:
    void initLayout();  //初始化佈局管理器
    bool initTextEdit();//初始化文本編輯器
    void initButton();  //初始化按鈕及標簽
private:
 
    QTextEdit*m_textEdit;       //考試題庫顯示
    QLabel*m_titleLabels[10];   //題目標簽
    QRadioButton *m_radioBtns[32];//單選按鈕
    QCheckBox *m_checkBtn[4];   //多選題按鈕
    QRadioButton *m_radioA;     //判斷題A選項
    QRadioButton *m_radioB;     //判斷題B選項
    QGridLayout*m_layout;       //佈局管理器
    QStringList m_answerList;   //答案

在initLayout函數中,設置當前窗口為為管理器父窗口,規定控件間的距離以及控件和窗體間的距離

void ExamDialog::initLayout()
{
    //以當前窗口作為父窗口
    m_layout=new QGridLayout(this);
    m_layout->setSpacing(10);//設置控件之間的間距
    m_layout->setMargin(10);//設置窗體與控件鍵的邊距
 
}

在initTextEdit函數中,讀取文本中的題目信息並將答案行單獨存儲,將讀取到的題目信息顯示在控件中,並將控件交給佈局管理器在窗體上佈局。

bool ExamDialog::initTextEdit()
{
    QString strLine;//保存文件答案行數據
    QStringList strList;//保存讀取到的答案行
    QString fileName("../exam.txt");
    QFile file(fileName);
    QTextStream stream(&file);//文本類型文件流
    stream.setCodec("UTF-8");//指定編碼
 
    if(file.open(QIODevice::ReadOnly|QIODevice::Text)){
        //以當前窗口作為父窗口
        m_textEdit=new QTextEdit(this);
        m_textEdit->setReadOnly(true);//設置文本隻讀
        QString strText;//用於保存顯示到文本編輯器的數據
        int nLines = 0;
        while(!stream.atEnd()){
            if(nLines==0){//過濾首行
                stream.readLine();
                nLines++;
                continue;
            }else if((nLines%6==0&&nLines>=6&&nLines<=6*9)||nLines==6*9+4){//過濾答案行
                strLine = stream.readLine();
                strList=strLine.split(" ");//通過空格分割出答案行的答案
                m_answerList.append(strList.at(1));//獲得答案
                strText+="\n";
                nLines++;
                continue;
            }
            strText+= stream.readLine();//讀取一行
            strText+="\n";
            nLines++;
        }
        //顯示文本內容
        m_textEdit->setText(strText);
        //把控件添加到佈局管理器中
        m_layout->addWidget(m_textEdit,0,0,1,10);
        file.close();
        return true;//讀取完
    }else{
 
        return false;
    }
}

在初始化函數中對窗體背景和字體進行一些設置

ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
    //設置字體大小
    QFont font;
    font.setPointSize(12);
    setFont(font);//設置當前窗口字體
 
    //設置窗體背景顏色
    setPalette(QPalette(QColor(209,215,255)));
 
    setWindowTitle("考試已用時:0分0秒");
    setWindowFlags(Qt::Dialog|Qt::WindowCloseButtonHint);
    resize(800,900);//設置窗體大小
 
    initTimer();
    initLayout();
    if(initTextEdit()){
 
    }else{
        //讀取失敗
        QMessageBox::information(this,"提示","初始化題庫數據文件失敗!");
        //當前應用程序立刻響應槽方法quit
        QTimer::singleShot(0,qApp,SLOT(quit()));
    }
}

3.3按鈕佈局 

佈局方法就是先將控件初始化,然後交給佈局管理器進行佈局。但要註意的是單選按鈕的分組:每個單選題的四個按鈕為一組,判斷題的兩個按鈕為一組

新添加QbuttonGroup屬性  

private:
    QButtonGroup* m_btnGroups[9];//單選按鈕分組

在初始換按鈕函數中 

void ExamDialog::initButton()
{
    QStringList strList={"A","B","C","D"};
 
    for(int i=0;i<10;++i){
        //題目標簽
        m_titleLabels[i]=new QLabel(this);//當前窗口作為父窗口初始化
        m_titleLabels[i]->setText("第"+QString::number(i+1)+"題");
        m_layout->addWidget(m_titleLabels[i],1,i);//交給佈局管理器,默認是占據一行一列
 
        //判斷題
        if(i==9){
            m_radioA=new QRadioButton(this);
            m_radioB=new QRadioButton(this);
 
            m_radioA->setText("正確");
            m_radioB->setText("錯誤");
 
            m_layout->addWidget(m_radioA,2,9);
            m_layout->addWidget(m_radioB,3,9);
 
            //判斷題按鈕分組
            m_btnGroups[8]=new QButtonGroup(this);
            m_btnGroups[8]->addButton(m_radioA);
            m_btnGroups[8]->addButton(m_radioB);
        }
        if(i<8){
            //單選題按鈕分組
            m_btnGroups[i]=new QButtonGroup(this);
        }
        //選擇題
        for(int j=0;j<4;++j){
            if(i==8){
                //多選題
                m_checkBtns[j]=new QCheckBox(this);
                m_checkBtns[j]->setText(strList.at(j));
                m_layout->addWidget(m_checkBtns[j],2+j,8);
            }else if(i<8){
                //單選題
                m_radioBtns[i*4+j]=new QRadioButton(this);
                m_radioBtns[i*4+j]->setText(strList.at(j));
                m_layout->addWidget(m_radioBtns[i*4+j],2+j,i);
 
                m_btnGroups[i]->addButton(m_radioBtns[i*4+j]);
            }
        }
        //提交按鈕
        QPushButton*submitBtn=new QPushButton(this);
        submitBtn->setText("提交");
        submitBtn->setFixedSize(100,35);
        m_layout->addWidget(submitBtn,6,9);
    }
}

3.4提交分數 

首先將提交按鈕與信號槽連接 

connect(submitBtn,SIGNAL(clicked(bool)),this,SLOT(getScore()));

在計算分數前先判斷題目是否全部完成,然後根據讀取的答案計算分數

bool ExamDialog::hasNoSelect()
{
    int radioSelects=0;
    //統計單選題完成數量
    for(int i=0;i<8;++i){
        if(m_btnGroups[i]->checkedButton()){
            radioSelects++;
        }
    }
    //判斷單選題是否全部完成
    if(radioSelects!=8){
        return true;
    }
    //統計多選題選擇數量
    int checkSelect=0;
    for(int i=0;i<4;++i){
        if(m_checkBtns[i]->isChecked()){
            checkSelect++;
        }
    }
    //多選題未選或隻選瞭一個也算未完成
    if(checkSelect==0||checkSelect==1){
        return true;
    }
    //判斷題
    if(!m_radioA->isChecked()&&!m_radioB->isChecked()){
        return true;
    }
    return false;
}
 
void ExamDialog::getScore()
{
    if(hasNoSelect()){
        //有未完成的題目
        QMessageBox::information(this,"提示","您有未完成的題目!請完成考試","是");
        return ;
    }else{
        //開始統分
        int scores =0;
        for(int i=0;i<10;++i){
            //單選題統分
            if(i<8){
                //判斷選中的按鈕與答案的是否一致
                if(m_btnGroups[i]->checkedButton()->text()==m_answerList.at(i)){
                    scores+=10;
                }
            }
            //多選題統分
            if(i==8){
                QString answer=m_answerList.at(i);//獲得多選題答案
                bool hasA=false;
                bool hasB=false;
                bool hasC=false;
                bool hasD=false;
                hasA=answer.contains("A");
                hasB=answer.contains("B");
                hasC=answer.contains("C");
                hasD=answer.contains("D");
 
                bool checkA=m_checkBtns[0]->checkState();
                bool checkB=m_checkBtns[1]->checkState();
                bool checkC=m_checkBtns[2]->checkState();
                bool checkD=m_checkBtns[3]->checkState();
                if(hasA!=checkA||hasB!=checkB||hasC!=checkC||hasD!=checkD){
                    //答案有不一致的
                    continue;
                }else{
                    scores+=10;
                }
            }
            //判斷題統分
            if(i==9){
                if(m_btnGroups[8]->checkedButton()->text()==m_answerList.at(i)){
                    scores+=10;
                }
            }
        }
        int res = QMessageBox::information(this,"提示","您所得分數為:"+QString::number(scores)+"分。是否重新考試?",QMessageBox::Yes|QMessageBox::No);
        if(res==QMessageBox::Yes){
            //重新考試
            return;
        }else{
            //不想重新考試
            close();
        }
    }
}

3.5窗口交互 

實現登錄窗口與考試窗口的連接

當用戶登錄成功後通過done函數發送一個Accepted,當用戶點擊取消時發送一個Rejected,然後在主函數中進行判斷

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    LoginDialog loginDialog;
    int res = loginDialog.exec();   //以模態方式運行
    if(res==QDialog::Accepted){
        ExamDialog examDialog;
        return a.exec();
    }else{
        return 0;
    }
    return a.exec();
}

4.發佈項目 

4.1更改編譯路徑

將當前編譯路徑由debug轉為當前文件所在路徑

4.2設置圖標 

在項目文件中通過 RC_ICONS加載圖標

RC_ICONS += examsys.ico

圖標已經更改過來瞭

4.3通過dos進行項目打包

將項目由DeBug模式改為Release模式,並編譯

建立一個文件夾作為發佈文件,將Release下生成的.exe文件和需要的文檔拷貝進來

進入要發佈文件夾路徑,然後輸入windeployqt 文件名.exe,點擊回車

打包完成 

如果提示 windeployqt不是命令的話需要將安裝的qt的bin路徑添加到環境變量中

到此這篇關於基於Qt實現駕校科目考試系統的示例代碼的文章就介紹到這瞭,更多相關Qt駕校科目考試系統內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: