基于Qt實現(xiàn)駕??颇靠荚囅到y(tǒng)的示例代碼
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.登錄功能實現(xiàn)
2.1驗證郵箱地址
首先判斷輸入的賬號是否符合郵箱格式 ,如果符合則進行登錄驗證,否則提示格式錯誤

void LoginDialog::on_loginButton_clicked()
{
//首先通過正則表達式判斷賬號是否是一個合法的郵箱格式
//^:表示規(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}$");//初始化時指定規(guī)則字符串
bool res = rx.exactMatch(ui->accountEdit->text());//對用戶輸入的賬號進行匹配
if(res){//匹配成功
QMessageBox::information(this,"提示","歡迎登錄科目一考試科目系統(tǒng)");
}else{//匹配不成功
QMessageBox::information(this,"提示","非法郵箱地址!請您重新輸入");
ui->accountEdit->clear();//清空賬號輸入框
ui->codeEdit->clear();//清空密碼輸入框
ui->accountEdit->setFocus();//賬號輸入框聚焦
return ;
}
}2.2賬號密碼登錄
當賬號格式合法后,讀取保存賬號和密碼的文檔進行匹配

if(res){//匹配成功
//QMessageBox::information(this,"提示","歡迎登錄科目一考試科目系統(tǒng)");
QString filename;//文件路徑
QString AccInput;//用戶輸入賬號
QString strCode;//用戶輸入密碼
QString strLine;//每次讀取一行數(shù)據(jù)
QStringList strList;//分割讀取一行數(shù)據(jù)
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,"提示","歡迎進入科目一考試系統(tǒng)");
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.考試界面開發(fā)
3.1考試用時

首先添加一個考試對話框類;在考試對話框類中添加QTimer和int屬性用于表示計時器和已用時;設定計時器的時間間隔為1s,通過connect函數(shù)將計時器與已用時顯示信號槽連接起來
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每發(fā)送timeout()信號時,由this執(zhí)行槽方法freshTime()
connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime()));
}
void ExamDialog::freshTime()
{
//刷新考試用時
m_timeGo++;
QString min=QString::number(m_timeGo/60);//計算分鐘,將整數(shù)轉(zhuǎn)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函數(shù)中,設置當前窗口為為管理器父窗口,規(guī)定控件間的距離以及控件和窗體間的距離
void ExamDialog::initLayout()
{
//以當前窗口作為父窗口
m_layout=new QGridLayout(this);
m_layout->setSpacing(10);//設置控件之間的間距
m_layout->setMargin(10);//設置窗體與控件鍵的邊距
}
在initTextEdit函數(shù)中,讀取文本中的題目信息并將答案行單獨存儲,將讀取到的題目信息顯示在控件中,并將控件交給布局管理器在窗體上布局。
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)){
//以當前窗口作為父窗口
m_textEdit=new QTextEdit(this);
m_textEdit->setReadOnly(true);//設置文本只讀
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ù)中對窗體背景和字體進行一些設置
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,"提示","初始化題庫數(shù)據(jù)文件失?。?);
//當前應用程序立刻響應槽方法quit
QTimer::singleShot(0,qApp,SLOT(quit()));
}
}3.3按鈕布局

布局方法就是先將控件初始化,然后交給布局管理器進行布局。但要注意的是單選按鈕的分組:每個單選題的四個按鈕為一組,判斷題的兩個按鈕為一組
新添加QbuttonGroup屬性
private:
QButtonGroup* m_btnGroups[9];//單選按鈕分組
在初始換按鈕函數(shù)中
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);//交給布局管理器,默認是占據(jù)一行一列
//判斷題
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提交分數(shù)


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


4.2設置圖標
在項目文件中通過 RC_ICONS加載圖標
RC_ICONS += examsys.ico


圖標已經(jīng)更改過來了
4.3通過dos進行項目打包
將項目由DeBug模式改為Release模式,并編譯

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

進入要發(fā)布文件夾路徑,然后輸入windeployqt 文件名.exe,點擊回車

打包完成

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


到此這篇關于基于Qt實現(xiàn)駕??颇靠荚囅到y(tǒng)的示例代碼的文章就介紹到這了,更多相關Qt駕??颇靠荚囅到y(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
VSCode搭建STM32開發(fā)環(huán)境的方法步驟
當我們的工程文件比較大的時候,編譯一次代碼需要很久可能會花費到四五分鐘,但是我們用vscode編寫和編譯的話時間就會大大縮減,本文就介紹一下VSCode搭建STM32開發(fā)環(huán)境,感興趣的可以了解一下2021-07-07
C/C++的浮點數(shù)在內(nèi)存中的存儲方式分析及實例
這篇文章主要介紹了C/C++的浮點數(shù)在內(nèi)存中的存儲方式分析及實例的相關資料,需要的朋友可以參考下2016-11-11

