I Create project
Create a new project:
1. Create - > Application - > QT widgets application
2. Give the project a name: ExamSys
3. Select component: MinGW 32bit
4. Select type information:
Class name: LoginDialog
Base class: qdialog (dialog class)
II Login interface
Control interface
First, in design mode:
Add two labels, two buttons and two lines, and set their Text to if Text.
background
1. Put the picture to be loaded into the folder of the project,
2. Switch to edit mode, right-click the ExamSys project and select add new file
3. Select QT - > QT resource file to create an image
4. After the prefix is established, enter only one /, and then click add file to load the file
5. In the design mode, add a label, select pixmap in Qlabel, put the picture in and put it at the back
6. Adjust the size between the picture, label and dialog box:
Picture and dialog adjustment:
In logindialog cpp:
ui->imgLabel->setScaledContents(true); //Fill the picture this->resize(ui->imgLabel->width(),ui->imgLabel->height()); //Set the size of the window to the size of the picture
Picture and label adjustment:
In design mode: set X and Y to 0 in QWidget
Title Block
this->setWindowTitle("Driving school subject 1 test login"); //Set the title this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); //There is only one close button left
III Verify account and password
Login button
Right click the login button - > go to slot - > clicked (), and then it will create a method
verification
1. Put the file storing data in the project folder (this program adds a file named "account.txt")
2. Use regular expressions to check whether the account format is correct
3. If correct, judge whether the account password entered by the user is in the file
//You need to include the following two header files #include "QFile" #include "QTextStream" void LoginDialog::on_LoginButton_clicked() { QRegExp rx("^[A-Za-z0-9]+([_\\.][A-Za-z0-9]+)*@([A-Za-z0-9\\-]+\\.)+[A-Za-z]{2,6}$"); /*The initial user name must be a letter and more than one, so it matches multiple times * There may be in the user name_ Or So the match can be 0 times * The @ in the middle must exist * The domain name will be underlined with letters or numbers * Then there must be The last paragraph won't be too long, so match 2-6 times ({2,6} is for the last one) */ bool res = rx.exactMatch(ui->accountEdit->text()); if(!res){ QMessageBox::information(this,"Tips","Illegal email address,Please re-enter!"); ui->accountEdit->clear(); //Clear one line of account data ui->codeEdit->clear(); //Clear one line of password data ui->accountEdit->setFocus(); //Refocus the cursor on the account line return; }else{ QString filename; //Account password data file QString strAccInput;//Account number entered by the user QString strCode; //Password entered by the user QString strLine; //A line of data in a file QStringList strList; //Split a row of read data (string linked list) filename = "../account.txt"; strAccInput = ui->accountEdit->text(); strCode = ui->codeEdit->text(); QFile file(filename); //Assign a file to a file object QTextStream stream(&file); //Insert a stream into the file object /* Use the open attribute of file object to open it in the form of text read-only Constantly loop through each line of data in the file, followed by the end Compare the account number and password of a line of data in two sections Why if(strAccInput == strList.at(0)) does not have else Because the account needs to traverse all the data in the file to know whether there is one, it is determined that the account is not established until the end of the cycle has not been found The password matches the account one-to-one, so if the account is correct, the password is the line of account data. There is no need to traverse all, so there is else */ if(file.open(QIODevice::ReadOnly | QIODevice::Text)){ while(!stream.atEnd()){ strLine = stream.readLine(); strList = strLine.split(","); //Separate the string into a character array and split it with if(strAccInput == strList.at(0)){ if(strCode == strList.at(1)){ QMessageBox::information(this,"Tips","Welcome to the subject one examination system!"); file.close(); return; }else{ QMessageBox::information(this,"Tips","Password input error,Please re-enter"); ui->codeEdit->clear(); ui->codeEdit->setFocus(); file.close(); return; } } } QMessageBox::information(this,"Tips","The account number you entered is incorrect,Please re-enter!"); ui->accountEdit->clear(); ui->codeEdit->clear(); ui->accountEdit->setFocus(); file.close(); return; }else{ QMessageBox::information(this,"Tips","File read failed"); return; } } }
IV Test timing
First create an examination window class:
Right click the project name - > files and classes - > C + ± > C + + class
Class name: examdialog | baseclass: QDialog
examdialog.h
#ifndef EXAMDIALOG_H #define EXAMDIALOG_H #include<QDialog> #include<QTimer> class ExamDialog : public QDialog { Q_OBJECT public: ExamDialog(QWidget* parent = 0);//Constructor void initTimer(); //Initialization timer private: QTimer *m_timer; //timer int m_timeGO; //Exam time used private slots: void freshTime(); }; #endif // EXAMDIALOG_H
examdialog.cpp
#include "examdialog.h" ExamDialog::ExamDialog(QWidget *parent):QDialog(parent) { setWindowTitle("Exam time used: 0 Minute 0 second"); initTimer(); } void ExamDialog::initTimer() { m_timeGO =0; m_timer = new QTimer(this); m_timer->setInterval(1000); m_timer->start(); //Connect signal and slot connect (sender, sender, responder, slot method of response) connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime())); } void ExamDialog::freshTime() { m_timeGO++; QString min = QString::number(m_timeGO/60); QString sec = QString::number(m_timeGO%60); setWindowTitle("Exam time used: "+min+"branch"+sec+"second"); }
main.cpp
#include "logindialog.h" #include <QApplication> #include <examdialog.h> int main(int argc, char *argv[]) { #if(QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) //Support automatic scaling of high score screen QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QApplication a(argc, argv);//The application class creates an object // LoginDialog w; // Login window object // w.show(); // display ExamDialog w; w.show(); return a.exec(); } example:
V Initialize question bank
Add an "exam.txt" file to the folder
examdialog. Add in H
Header file:
#include<QTextEdit> #include<QLabel> #include<QRadioButton> #include<QCheckBox> #include<QGridLayout>
method:
void initLayout(); //Initialize layout manager bool initTextEdit();//Initialize text compiler
Field:
QTextEdit *m_textEdit; //Test question bank display QLabel *m_titleLabels[10];//Title label QRadioButton *m_radioBtns[32];//Radio button QCheckBox *m_checkBtns[4];//Multiple choice button QRadioButton *m_radioA; //True or false A option QRadioButton *m_radioB; //True or false B option QGridLayout *m_layout; //Layout manager QStringList m_answerList; //answer
examdialog. In CPP
Header file added:
#include<QFile> #include<QTextStream> #include<QMessageBox> #include<QApplication>
Method implementation:
void ExamDialog::initLayout() { m_layout = new QGridLayout(this); m_layout->setSpacing(10); //Sets the spacing between controls m_layout->setMargin(10); //Sets the gap between the form and the control } bool ExamDialog::initTextEdit() { QString strLine; //Save a line of data read from the file QStringList strList; //Save the read answer line 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;//Used to save data displayed to the text compiler int nLines = 0; while(!stream.atEnd()){ //Filter first line if(nLines == 0){ stream.readLine(); nLines++; continue; } //Filter answer lines if((nLines>=6 && nLines<=6*9&&(nLines %6 == 0)) ||(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; } } //And update the constructor ExamDialog::ExamDialog(QWidget *parent):QDialog(parent) { //Set font size QFont font; font.setPointSize(12); setFont(font); //Set form background color setPalette(QPalette(QColor(209,215,255))); setWindowTitle("Exam time used: 0 Minute 0 second"); setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); resize(800,900); initTimer(); initLayout(); if(!initTextEdit()){ QMessageBox::information(this,"Tips","Failed to initialize the question bank data file"); QTimer::singleShot(0,qApp,SLOT(quit())); } }
effect:
Vi Button layout
examdialog. Add in H
Header file: #include < qbuttongroup >
method:
void initButtons(); // Initialization button and label
Field:
QButtonGroup *m_btnGroups[9]; // Single button grouping
examdialog. Add in CPP
Header file: #include < QPushButton >
S
void ExamDialog::initButtons() { QStringList strList ={"A","B","c","D"}; for(int i=0;i<10;i++){ //Title label m_titleLabels[i] = new QLabel(this); m_titleLabels[i]->setText("The first"+QString::number(i+1)+"topic"); m_layout->addWidget(m_titleLabels[i],1,i); //Judgment question if(i==9){ m_radioA = new QRadioButton(this); m_radioB = new QRadioButton(this); m_radioA->setText("correct"); m_radioB->setText("error"); 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); break; } if(i<8) m_btnGroups[i] = new QButtonGroup(this); //choice question for(int j=0;j<4;j++){ if(i == 8){//Multiple choice m_checkBtns[j] = new QCheckBox(this); m_checkBtns[j]->setText(strList.at(j)); m_layout->addWidget(m_checkBtns[j],2+j,8); }else{//Multiple choice m_radioBtns[4*i+j] = new QRadioButton(this); m_radioBtns[4*i+j]->setText(strList.at(j)); m_layout->addWidget(m_radioBtns[4*i+j],2+j,i); m_btnGroups[i]->addButton(m_radioBtns[4*i+j]); } } } QPushButton *submitBtn = new QPushButton(this); submitBtn->setText("Submit"); submitBtn->setFixedSize(100,35); m_layout->addWidget(submitBtn,6,9); }
Illustration:
VII Submit topic
Add slot method in void ExamDialog::initButtons()
examdialog. Add in H
method:
bool hasNoSelect(); // Judge whether there are unfinished questions
Slot method:
void getScore();
examdialog. Add in CPP
bool ExamDialog::hasNoSelect() { int radioSelects = 0; for(int i=0;i<8;i++){ if(m_btnGroups[i]->checkedButton())//Judge whether there are selected in a group radioSelects++; } //There are unfinished questions in single choice questions if(radioSelects!=8) return true; int checkSelects=0; for(int i=0;i<4;i++){ if(m_checkBtns[i]->isChecked()) checkSelects++; } //Multiple choice questions have unfinished if(checkSelects==0) return true; //There are unfinished questions in the judgment questions if(!m_radioA->isChecked() &&!m_radioB->isChecked()) return true; return false; } void ExamDialog::getScore() { if(hasNoSelect()){ QMessageBox::information(this,"Tips","You have unfinished questions,Please complete the exam!","yes"); return; } int scores=0; for(int i=0;i<10;i++){ //Single choice scoring if(i<8) if(m_btnGroups[i]->checkedButton()->text() == m_answerList.at(i)) scores+=10; //Multiple choice scoring if(i==8){ QString answer = m_answerList.at(i); bool hasA =false; bool hasB =false; bool hasC =false; bool hasD =false; if(answer.contains("A")) hasA = true; if(answer.contains("B")) hasB = true; if(answer.contains("C")) hasC = true; if(answer.contains("D")) hasD = true; 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) continue; if(hasB!=checkB) continue; if(hasC!=checkC) continue; if(hasD!=checkD) continue; scores+=10; } //Judgment scoring if(i==9){ if(m_btnGroups[8]->checkedButton()->text() == m_answerList.at(i)){ scores+=10; } } } QString str = "Your score is:"+QString::number(scores) +"branch,Do you want to retest?"; int res = QMessageBox::information(this,"Tips",str,QMessageBox::Yes| QMessageBox::No); if(res == QMessageBox::Yes) return; else close(); }
VIII Window interaction
. exec() is in a state of waiting for events in a loop, and then waits to receive and process messages from users and systems, which includes the so-called signal slot mechanism
First, operate in the login class lodDialog window. If the password and account are correct after clicking OK,
Then use done() to close the window and return to the state in an accepted manner,
Then create a ExamDialog class window (the constructor calls the show method) and enter the test interface.
If you click Cancel, done will close the current window and return in the user rejected status, it is over
1. Create a slot method for the Cancel button
In method
void LoginDialog::on_cannelButton_clicked() { done(Rejected);//Close the current window and return in user rejected status }
2. On_ loginBtn_ Add a sentence to clicked():
Main function:
int main(int argc, char *argv[]) { #if(QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) //Support automatic scaling of high score screen QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QApplication a(argc, argv);//The application class creates an object LoginDialog lodDialog; //Login window object int res = lodDialog.exec(); //display if(res == QDialog::Accepted) { ExamDialog *examDialog; examDialog = new ExamDialog; }else{ return 0; } //ExamDialog w; //w.show(); return a.exec(); }
IX release
1. First delete the Debug in the running working directory
2.
3. Prepare an icon, usually icon suffix
Add it to examsys In pro file
4. Establish a "subject examination system" on the desktop, drag the executable file and data file into it, and then drag several link libraries from the Qt file
However, this release mode can only be used in QT environment
X All codes
ExamSys.pro
#------------------------------------------------- # # Project created by QtCreator 2021-05-29T08:13:05 # #------------------------------------------------- QT += core gui RC_ICONS +=login.ico greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = ExamSys TEMPLATE = app # The following define makes your compiler emit warnings if you use # any feature of Qt which has been marked as deprecated (the exact warnings # depend on your compiler). Please consult the documentation of the # deprecated API in order to know how to port your code away from it. DEFINES += QT_DEPRECATED_WARNINGS # You can also make your code fail to compile if you use deprecated APIs. # In order to do so, uncomment the following line. # You can also select to disable deprecated APIs only up to a certain version of Qt. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ main.cpp \ logindialog.cpp \ examdialog.cpp HEADERS += \ logindialog.h \ examdialog.h FORMS += \ logindialog.ui RESOURCES += \ image.qrc
examdialog.h
#ifndef EXAMDIALOG_H #define EXAMDIALOG_H #include<QDialog> #include<QTimer> #include<QTextEdit> #include<QLabel> #include<QRadioButton> #include<QCheckBox> #include<QGridLayout> #include<QButtonGroup> class ExamDialog : public QDialog { Q_OBJECT public: ExamDialog(QWidget* parent = 0); void initTimer(); //Initialization timer void initLayout(); //Initialize layout manager bool initTextEdit();//Initialize text compiler void initButtons(); //Initialization button and label bool hasNoSelect(); //Judge whether there are unfinished questions private: QTimer *m_timer; //timer int m_timeGO; //Exam time used QTextEdit *m_textEdit; //Test question bank display QLabel *m_titleLabels[10];//Title label QRadioButton *m_radioBtns[32];//Radio button QCheckBox *m_checkBtns[4];//Multiple choice button QRadioButton *m_radioA; //True or false A option QRadioButton *m_radioB; //True or false B option QGridLayout *m_layout; //Layout manager QStringList m_answerList; //answer QButtonGroup *m_btnGroups[9]; //Single button grouping private slots: void freshTime(); void getScore(); }; #endif // EXAMDIALOG_H
logindialog.h
#ifndef LOGINDIALOG_H #define LOGINDIALOG_H #include <QDialog> namespace Ui { class LoginDialog; } class LoginDialog : public QDialog { Q_OBJECT public: explicit LoginDialog(QWidget *parent = 0); ~LoginDialog(); private slots: void on_LoginButton_clicked(); void on_cannelButton_clicked(); private: Ui::LoginDialog *ui; }; #endif // LOGINDIALOG_H
examdialog.cpp
#ifndef LOGINDIALOG_H #define LOGINDIALOG_H #include <QDialog> namespace Ui { class LoginDialog; } class LoginDialog : public QDialog { Q_OBJECT public: explicit LoginDialog(QWidget *parent = 0); ~LoginDialog(); private slots: void on_LoginButton_clicked(); void on_cannelButton_clicked(); private: Ui::LoginDialog *ui; }; #endif // LOGINDIALOG_H
logindialog.cpp
#include "logindialog.h" #include "ui_logindialog.h" #include"QMessageBox" #include "QFile" #include "QTextStream" LoginDialog::LoginDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LoginDialog) { ui->setupUi(this);//Initialization interface ui->imgLabel->setScaledContents(true); //Fill the picture this->resize(ui->imgLabel->width(),ui->imgLabel->height()); setFixedSize(width(),height()); //Fixed window size this->setWindowTitle("Driving school subject 1 test login"); //Set the title this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); } LoginDialog::~LoginDialog()//Natural recycling { delete ui; } void LoginDialog::on_LoginButton_clicked() { QRegExp rx("^[A-Za-z0-9]+([_\\.][A-Za-z0-9]+)*@([A-Za-z0-9\\-]+\\.)+[A-Za-z]{2,6}$"); /*The initial user name must be a letter and more than one, so it matches multiple times * There may be in the user name_ Or So the match can be 0 times * The @ in the middle must exist * The domain name will be underlined with letters or numbers * Then there must be The last paragraph won't be too long, so match 2-6 times ({2,6} is for the last one) */ bool res = rx.exactMatch(ui->accountEdit->text()); if(!res){ QMessageBox::information(this,"Tips","Illegal email address,Please re-enter!"); ui->accountEdit->clear(); //Clear one line of account data ui->codeEdit->clear(); //Clear one line of password data ui->accountEdit->setFocus(); //Refocus the cursor on the account line return; }else{ QString filename; //Account password data file QString strAccInput;//Account number entered by the user QString strCode; //Password entered by the user QString strLine; //A line of data in a file QStringList strList; //Split a row of read data (string linked list) filename = "account.txt"; strAccInput = ui->accountEdit->text(); strCode = ui->codeEdit->text(); QFile file(filename); //Assign a file to a file object QTextStream stream(&file); //Insert a stream into the file object /* Use the open attribute of file object to open it in the form of text read-only Constantly loop through each line of data in the file, followed by the end Compare the account number and password of a line of data in two sections Why if(strAccInput == strList.at(0)) does not have else Because the account needs to traverse all the data in the file to know whether there is one, it is determined that the account is not established until the end of the cycle has not been found The password matches the account one-to-one, so if the account is correct, the password is the line of account data. There is no need to traverse all, so there is else */ if(file.open(QIODevice::ReadOnly | QIODevice::Text)){ while(!stream.atEnd()){ strLine = stream.readLine(); strList = strLine.split(","); //Separate the string into a character array and split it with if(strAccInput == strList.at(0)){ if(strCode == strList.at(1)){ QMessageBox::information(this,"Tips","Welcome to the subject one examination system!"); file.close(); done(Accepted);//Closes the current form and returns in the specified manner (status) return; }else{ QMessageBox::information(this,"Tips","Password input error,Please re-enter"); ui->codeEdit->clear(); ui->codeEdit->setFocus(); file.close(); return; } } } QMessageBox::information(this,"Tips","The account number you entered is incorrect,Please re-enter!"); ui->accountEdit->clear(); ui->codeEdit->clear(); ui->accountEdit->setFocus(); file.close(); return; }else{ QMessageBox::information(this,"Tips","File read failed"); return; } } } void LoginDialog::on_cannelButton_clicked() { done(Rejected);//Close the current window and return in user rejected status }
mian.cpp
#include "logindialog.h" #include <QApplication> #include <examdialog.h> int main(int argc, char *argv[]) { #if(QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) //Support automatic scaling of high score screen QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QApplication a(argc, argv);//The application class creates an object LoginDialog lodDialog; //Login window object int res = lodDialog.exec(); //display if(res == QDialog::Accepted) { ExamDialog *examDialog; examDialog = new ExamDialog; }else{ return 0; } //ExamDialog w; //w.show(); return a.exec(); }