基于Qt實(shí)現(xiàn)駕??颇靠荚囅到y(tǒng)的示例代碼
1.設(shè)置登錄界面

LoginDialog::LoginDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::LoginDialog)
{
ui->setupUi(this);
ui->imgLabel->setScaledContents(true);//設(shè)置填充
this->resize(ui->imgLabel->width(),ui->imgLabel->height());//設(shè)置窗口大小
//設(shè)置窗口標(biāo)題
this->setWindowTitle(("駕??颇恳豢荚嚨卿?));
//設(shè)置窗口風(fēng)格
this->setWindowFlags(Qt::Dialog |Qt::WindowCloseButtonHint);
}
2.登錄功能實(shí)現(xiàn)
2.1驗(yàn)證郵箱地址
首先判斷輸入的賬號(hào)是否符合郵箱格式 ,如果符合則進(jìn)行登錄驗(yàn)證,否則提示格式錯(cuò)誤

void LoginDialog::on_loginButton_clicked()
{
//首先通過(guò)正則表達(dá)式判斷賬號(hào)是否是一個(gè)合法的郵箱格式
//^:表示規(guī)則字符串開(kāi)始、$:表示規(guī)則字符串的結(jié)束
//+:表示匹配次數(shù)≥1次、*:表示匹配任意次數(shù)(可為0次) {n,m}表示匹配次數(shù)最少n次 最多m次
QRegExp rx("^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z]{2,6}$");//初始化時(shí)指定規(guī)則字符串
bool res = rx.exactMatch(ui->accountEdit->text());//對(duì)用戶(hù)輸入的賬號(hào)進(jìn)行匹配
if(res){//匹配成功
QMessageBox::information(this,"提示","歡迎登錄科目一考試科目系統(tǒng)");
}else{//匹配不成功
QMessageBox::information(this,"提示","非法郵箱地址!請(qǐng)您重新輸入");
ui->accountEdit->clear();//清空賬號(hào)輸入框
ui->codeEdit->clear();//清空密碼輸入框
ui->accountEdit->setFocus();//賬號(hào)輸入框聚焦
return ;
}
}2.2賬號(hào)密碼登錄
當(dāng)賬號(hào)格式合法后,讀取保存賬號(hào)和密碼的文檔進(jìn)行匹配

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

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

3.考試界面開(kāi)發(fā)
3.1考試用時(shí)

首先添加一個(gè)考試對(duì)話框類(lèi);在考試對(duì)話框類(lèi)中添加QTimer和int屬性用于表示計(jì)時(shí)器和已用時(shí);設(shè)定計(jì)時(shí)器的時(shí)間間隔為1s,通過(guò)connect函數(shù)將計(jì)時(shí)器與已用時(shí)顯示信號(hào)槽連接起來(lái)
examDialog.h
#ifndef EXAMDIALOG_H
#define EXAMDIALOG_H
#include<QDialog>
#include<QTimer>
class ExamDialog : public QDialog
{
Q_OBJECT//使用信號(hào)槽
public:
ExamDialog(QWidget* parent=0);
void initTimer();
private:
QTimer*m_timer;//計(jì)時(shí)器
int m_timeGo;//考試已用時(shí)
private slots: //私有槽方法
void freshTime();
};
#endif // EXAMDIALOG_H
examDialog.cpp
#include "examdialog.h"
ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
setWindowTitle("考試已用時(shí):0分0秒");
initTimer();
}
void ExamDialog::initTimer()
{
m_timeGo=0;
m_timer=new QTimer(this);
m_timer->setInterval(1000);//設(shè)置計(jì)時(shí)器時(shí)間間隔1s
m_timer->start();//啟動(dòng)計(jì)時(shí)器
//通過(guò)connect方法,連接信號(hào)槽。m_timer每發(fā)送timeout()信號(hào)時(shí),由this執(zhí)行槽方法freshTime()
connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime()));
}
void ExamDialog::freshTime()
{
//刷新考試用時(shí)
m_timeGo++;
QString min=QString::number(m_timeGo/60);//計(jì)算分鐘,將整數(shù)轉(zhuǎn)QString
QString sec=QString::number(m_timeGo%60);
setWindowTitle("考試已用時(shí):"+min+"分"+sec+"秒");
}
3.2題目布局

添加屬性以及初始化方法
public:
void initLayout(); //初始化布局管理器
bool initTextEdit();//初始化文本編輯器
void initButton(); //初始化按鈕及標(biāo)簽
private:
QTextEdit*m_textEdit; //考試題庫(kù)顯示
QLabel*m_titleLabels[10]; //題目標(biāo)簽
QRadioButton *m_radioBtns[32];//單選按鈕
QCheckBox *m_checkBtn[4]; //多選題按鈕
QRadioButton *m_radioA; //判斷題A選項(xiàng)
QRadioButton *m_radioB; //判斷題B選項(xiàng)
QGridLayout*m_layout; //布局管理器
QStringList m_answerList; //答案
在initLayout函數(shù)中,設(shè)置當(dāng)前窗口為為管理器父窗口,規(guī)定控件間的距離以及控件和窗體間的距離
void ExamDialog::initLayout()
{
//以當(dāng)前窗口作為父窗口
m_layout=new QGridLayout(this);
m_layout->setSpacing(10);//設(shè)置控件之間的間距
m_layout->setMargin(10);//設(shè)置窗體與控件鍵的邊距
}
在initTextEdit函數(shù)中,讀取文本中的題目信息并將答案行單獨(dú)存儲(chǔ),將讀取到的題目信息顯示在控件中,并將控件交給布局管理器在窗體上布局。
bool ExamDialog::initTextEdit()
{
QString strLine;//保存文件答案行數(shù)據(jù)
QStringList strList;//保存讀取到的答案行
QString fileName("../exam.txt");
QFile file(fileName);
QTextStream stream(&file);//文本類(lèi)型文件流
stream.setCodec("UTF-8");//指定編碼
if(file.open(QIODevice::ReadOnly|QIODevice::Text)){
//以當(dāng)前窗口作為父窗口
m_textEdit=new QTextEdit(this);
m_textEdit->setReadOnly(true);//設(shè)置文本只讀
QString strText;//用于保存顯示到文本編輯器的數(shù)據(jù)
int nLines = 0;
while(!stream.atEnd()){
if(nLines==0){//過(guò)濾首行
stream.readLine();
nLines++;
continue;
}else if((nLines%6==0&&nLines>=6&&nLines<=6*9)||nLines==6*9+4){//過(guò)濾答案行
strLine = stream.readLine();
strList=strLine.split(" ");//通過(guò)空格分割出答案行的答案
m_answerList.append(strList.at(1));//獲得答案
strText+="\n";
nLines++;
continue;
}
strText+= stream.readLine();//讀取一行
strText+="\n";
nLines++;
}
//顯示文本內(nèi)容
m_textEdit->setText(strText);
//把控件添加到布局管理器中
m_layout->addWidget(m_textEdit,0,0,1,10);
file.close();
return true;//讀取完
}else{
return false;
}
}在初始化函數(shù)中對(duì)窗體背景和字體進(jìn)行一些設(shè)置
ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
//設(shè)置字體大小
QFont font;
font.setPointSize(12);
setFont(font);//設(shè)置當(dāng)前窗口字體
//設(shè)置窗體背景顏色
setPalette(QPalette(QColor(209,215,255)));
setWindowTitle("考試已用時(shí):0分0秒");
setWindowFlags(Qt::Dialog|Qt::WindowCloseButtonHint);
resize(800,900);//設(shè)置窗體大小
initTimer();
initLayout();
if(initTextEdit()){
}else{
//讀取失敗
QMessageBox::information(this,"提示","初始化題庫(kù)數(shù)據(jù)文件失?。?);
//當(dāng)前應(yīng)用程序立刻響應(yīng)槽方法quit
QTimer::singleShot(0,qApp,SLOT(quit()));
}
}3.3按鈕布局

布局方法就是先將控件初始化,然后交給布局管理器進(jìn)行布局。但要注意的是單選按鈕的分組:每個(gè)單選題的四個(gè)按鈕為一組,判斷題的兩個(gè)按鈕為一組
新添加QbuttonGroup屬性
private:
QButtonGroup* m_btnGroups[9];//單選按鈕分組
在初始換按鈕函數(shù)中
void ExamDialog::initButton()
{
QStringList strList={"A","B","C","D"};
for(int i=0;i<10;++i){
//題目標(biāo)簽
m_titleLabels[i]=new QLabel(this);//當(dāng)前窗口作為父窗口初始化
m_titleLabels[i]->setText("第"+QString::number(i+1)+"題");
m_layout->addWidget(m_titleLabels[i],1,i);//交給布局管理器,默認(rèn)是占據(jù)一行一列
//判斷題
if(i==9){
m_radioA=new QRadioButton(this);
m_radioB=new QRadioButton(this);
m_radioA->setText("正確");
m_radioB->setText("錯(cuò)誤");
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提交分?jǐn)?shù)


首先將提交按鈕與信號(hào)槽連接
connect(submitBtn,SIGNAL(clicked(bool)),this,SLOT(getScore()));
在計(jì)算分?jǐn)?shù)前先判斷題目是否全部完成,然后根據(jù)讀取的答案計(jì)算分?jǐn)?shù)
bool ExamDialog::hasNoSelect()
{
int radioSelects=0;
//統(tǒng)計(jì)單選題完成數(shù)量
for(int i=0;i<8;++i){
if(m_btnGroups[i]->checkedButton()){
radioSelects++;
}
}
//判斷單選題是否全部完成
if(radioSelects!=8){
return true;
}
//統(tǒng)計(jì)多選題選擇數(shù)量
int checkSelect=0;
for(int i=0;i<4;++i){
if(m_checkBtns[i]->isChecked()){
checkSelect++;
}
}
//多選題未選或只選了一個(gè)也算未完成
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,"提示","您有未完成的題目!請(qǐng)完成考試","是");
return ;
}else{
//開(kāi)始統(tǒng)分
int scores =0;
for(int i=0;i<10;++i){
//單選題統(tǒng)分
if(i<8){
//判斷選中的按鈕與答案的是否一致
if(m_btnGroups[i]->checkedButton()->text()==m_answerList.at(i)){
scores+=10;
}
}
//多選題統(tǒng)分
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;
}
}
//判斷題統(tǒng)分
if(i==9){
if(m_btnGroups[8]->checkedButton()->text()==m_answerList.at(i)){
scores+=10;
}
}
}
int res = QMessageBox::information(this,"提示","您所得分?jǐn)?shù)為:"+QString::number(scores)+"分。是否重新考試?",QMessageBox::Yes|QMessageBox::No);
if(res==QMessageBox::Yes){
//重新考試
return;
}else{
//不想重新考試
close();
}
}
}3.5窗口交互
實(shí)現(xiàn)登錄窗口與考試窗口的連接
當(dāng)用戶(hù)登錄成功后通過(guò)done函數(shù)發(fā)送一個(gè)Accepted,當(dāng)用戶(hù)點(diǎn)擊取消時(shí)發(fā)送一個(gè)Rejected,然后在主函數(shù)中進(jìn)行判斷
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
LoginDialog loginDialog;
int res = loginDialog.exec(); //以模態(tài)方式運(yùn)行
if(res==QDialog::Accepted){
ExamDialog examDialog;
return a.exec();
}else{
return 0;
}
return a.exec();
}
4.發(fā)布項(xiàng)目
4.1更改編譯路徑
將當(dāng)前編譯路徑由debug轉(zhuǎn)為當(dāng)前文件所在路徑


4.2設(shè)置圖標(biāo)
在項(xiàng)目文件中通過(guò) RC_ICONS加載圖標(biāo)
RC_ICONS += examsys.ico


圖標(biāo)已經(jīng)更改過(guò)來(lái)了
4.3通過(guò)dos進(jìn)行項(xiàng)目打包
將項(xiàng)目由DeBug模式改為Release模式,并編譯

建立一個(gè)文件夾作為發(fā)布文件,將Release下生成的.exe文件和需要的文檔拷貝進(jìn)來(lái)

進(jìn)入要發(fā)布文件夾路徑,然后輸入windeployqt 文件名.exe,點(diǎn)擊回車(chē)

打包完成

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


到此這篇關(guān)于基于Qt實(shí)現(xiàn)駕??颇靠荚囅到y(tǒng)的示例代碼的文章就介紹到這了,更多相關(guān)Qt駕??颇靠荚囅到y(tǒng)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
VSCode搭建STM32開(kāi)發(fā)環(huán)境的方法步驟
當(dāng)我們的工程文件比較大的時(shí)候,編譯一次代碼需要很久可能會(huì)花費(fèi)到四五分鐘,但是我們用vscode編寫(xiě)和編譯的話時(shí)間就會(huì)大大縮減,本文就介紹一下VSCode搭建STM32開(kāi)發(fā)環(huán)境,感興趣的可以了解一下2021-07-07
C++生成隨機(jī)浮點(diǎn)數(shù)的示例代碼
在C++11之前,我們通常采用rand函數(shù)來(lái)生成隨機(jī)數(shù),但rand函數(shù)對(duì)一些情況顯得難以處理。本文將介紹如何利用C++生成隨機(jī)浮點(diǎn)數(shù),需要的可以參考一下2022-04-04
C/C++的浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式分析及實(shí)例
這篇文章主要介紹了C/C++的浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式分析及實(shí)例的相關(guān)資料,需要的朋友可以參考下2016-11-11

