基于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() { //首先通過正則表達(dá)式判斷賬號(hào)是否是一個(gè)合法的郵箱格式 //^:表示規(guī)則字符串開始、$:表示規(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à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ào) QString strCode;//用戶輸入密碼 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);//文本類型文件流 //指定只讀方式打開,指定文件類型式文本類型 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)){ //賬號(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.考試界面開發(fā)
3.1考試用時(shí)
首先添加一個(gè)考試對(duì)話框類;在考試對(duì)話框類中添加QTimer和int屬性用于表示計(jì)時(shí)器和已用時(shí);設(shè)定計(jì)時(shí)器的時(shí)間間隔為1s,通過connect函數(shù)將計(jì)時(shí)器與已用時(shí)顯示信號(hào)槽連接起來
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í)器 //通過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; //考試題庫顯示 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);//文本類型文件流 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){//過濾首行 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++; } //顯示文本內(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,"提示","初始化題庫數(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{ //開始統(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)用戶登錄成功后通過done函數(shù)發(fā)送一個(gè)Accepted,當(dāng)用戶點(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)目文件中通過 RC_ICONS加載圖標(biāo)
RC_ICONS += examsys.ico
圖標(biāo)已經(jīng)更改過來了
4.3通過dos進(jìn)行項(xiàng)目打包
將項(xiàng)目由DeBug模式改為Release模式,并編譯
建立一個(gè)文件夾作為發(fā)布文件,將Release下生成的.exe文件和需要的文檔拷貝進(jìn)來
進(jìn)入要發(fā)布文件夾路徑,然后輸入windeployqt 文件名.exe,點(diǎn)擊回車
打包完成
如果提示 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開發(fā)環(huán)境的方法步驟
當(dāng)我們的工程文件比較大的時(shí)候,編譯一次代碼需要很久可能會(huì)花費(fèi)到四五分鐘,但是我們用vscode編寫和編譯的話時(shí)間就會(huì)大大縮減,本文就介紹一下VSCode搭建STM32開發(fā)環(huán)境,感興趣的可以了解一下2021-07-07C++生成隨機(jī)浮點(diǎn)數(shù)的示例代碼
在C++11之前,我們通常采用rand函數(shù)來生成隨機(jī)數(shù),但rand函數(shù)對(duì)一些情況顯得難以處理。本文將介紹如何利用C++生成隨機(jī)浮點(diǎn)數(shù),需要的可以參考一下2022-04-04C/C++的浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式分析及實(shí)例
這篇文章主要介紹了C/C++的浮點(diǎn)數(shù)在內(nèi)存中的存儲(chǔ)方式分析及實(shí)例的相關(guān)資料,需要的朋友可以參考下2016-11-11