QT -- subject 1 examination system

Posted by The Eagle on Sun, 30 Jan 2022 16:21:17 +0100

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();
}

Topics: Qt