C++ QT开发 学习笔记(1)

C++ QT开发 学习笔记(1)

考试系统

创建项目

新建Qt桌面应用程序,项目名:ExamSys。

类信息:类名LoginDialog继承自QDialog

(1) ExamSys.pro

工程文件,包含当前工程的相关信息。

QDialog 是 Qt 框架中用于创建对话框的基类。对话框是一种特殊类型的窗口,通常用于短期的交互和信息交换,比如用户输入、设置选项、文件选择等。QDialog 提供了许多专为这种用途设计的特性和功能。

ExamSys.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = ExamSys
TEMPLATE = app

logindialog.h

#ifndef LOGINDIALOG_H
#define LOGINDIALOG_H

#include <QDialog>

namespace Ui {
class LoginDialog; //Ui_LoginDialog son class, use for describe the login window detail message.
}

class LoginDialog : public QDialog
{
    Q_OBJECT  //Support signal and slots

public:
    explicit LoginDialog(QWidget *parent = 0);
    ~LoginDialog();

private:
    Ui::LoginDialog *ui;
};

#endif // LOGINDIALOG_H

logindialog.cpp

#include "logindialog.h"
#include "ui_logindialog.h"

LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::LoginDialog)
{
    ui->setupUi(this);
}

LoginDialog::~LoginDialog()
{
    delete ui;
}

main.cpp

#include "logindialog.h"
#include <QApplication>
#include <examdialog.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv); //Define the apps object
    LoginDialog w;				//Define the window object
    w.show();					//Display window
    return a.exec();			//Enter APP execeute loop
}

logindialog.ui

登录窗口界面文件。

登录界面

设计模式下添加账号、密码标签,账号、密码输入框,登录、取消按钮,并修改对象名,添加资源文件imgage.qrc,给imgLabel添加图片资源做背景。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

logindialog.cpp构造函数中设置窗体标题、风格

LoginDialog::LoginDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::LoginDialog)
{
    ui->setupUi(this);
    this->resize(600,400);
    setFixedSize(width(),height());
    this->setWindowTitle("Cat Exam");
    this->setWindowFlags(Qt::Dialog| Qt::WindowCloseButtonHint);
    this->setWindowFlags(Qt::Window| Qt::WindowFullscreenButtonHint);
}

在这里插入图片描述

验证邮箱地址

给登录按钮添加响应点击信号的槽方法:

设计模式下,右键单击登录按钮,选择“转到槽”,选择点击信号clicked().

给槽方法void LoginDialog::on_loginBtn_clicked()添加如下代码:

void LoginDialog::on_login_Button_clicked()
{
    //QMessageBox::information(this,"Hint","Slot method used");
    //Verify the email address username@address   ex:123980@qq.com
    //Symbol decalration: ^string start  &string end
    //+match times>=1 *match any times(include 0 times)  {n,m}match times at least n times, at most m times.
    QRegExp rx("^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z0-9]{2,6}$");

    bool res = rx.exactMatch(ui->account_edit->text());
    if(!res)// If failed match
    {
        QMessageBox::information(this,"Hint","Invalid email address, please reenter the email address");
    }
    else
    {
        QMessageBox::information(this,"Hint","Welcome to the CAT exam!");
    }

注意:需要加上头文件 include <QMessageBox>

验证账号密码 (通过账号密码保存在文档的方式)

在logindialog.cpp添加头文件

#include <QFile>

#include <QTextStream>

这两个头文件的引入有特定的目的,主要涉及到文件处理和文本数据的流式读写

编辑 void LoginDialog::on_loginBtn_clicked()方法

void LoginDialog::on_login_Button_clicked()
{
    //QMessageBox::information(this,"Hint","Slot method used");
    //Verify the email address username@address   ex:123980@qq.com
    //Symbol decalration: ^string start  &string end
    //+match times>=1 *match any times(include 0 times)  {n,m}match times at least n times, at most m times.
    QRegExp rx("^[A-Za-z0-9]+([_\.][A-Za-z0-9]+)*@([A-Za-z0-9\-]+\.)+[A-Za-z0-9]{2,6}$");

    bool res = rx.exactMatch(ui->account_edit->text());
    if(!res)// If failed match
    {
        QMessageBox::information(this,"Hint","Invalid email address, please reenter the email address");
        ui->account_edit->clear();
        ui->code_edit->clear();
        ui->account_edit->setFocus();
        return;
    }

    else
    {
        //QMessageBox::information(this,"Hint","Welcome to the cat EXAM!");
        QString filename;       //Account & password data file
        QString strAccInput;    //User input account
        QString strCode;        //User input password
        QString strLine;        //Every line read data
        QStringList strList;    //Use for seperate the line from strLine for account and password

        filename = "../account.txt";    //According to the debug folder. so need to go previous folder get account.txt
        strAccInput = ui->account_edit->text();
        strCode = ui->code_edit->text();

        QFile file(filename);
        QTextStream stream(&file);
        if (file.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            while(!stream.atEnd())
            {
                strLine = stream.readLine();
                strList = strLine.split(",");
                    if(strAccInput == strList.at(0))
                    {
                        if(strCode == strList.at(1))
                        {
                            QMessageBox::information(this,"Hint","Welcome to the CAT Exam");
                            file.close();
                            return;
                        }
                        else
                        {
                            QMessageBox::information(this,"Hint","The password is wrong! Please reenter your password");
                            ui->code_edit->clear();
                            ui->code_edit->setFocus();
                            file.close();
                            return;
                        }
                    }
            }
            QMessageBox::information(this,"Hint","Your account is invalid to login to the Exam! Please contact admin to register you account!");
            ui->account_edit->clear();
            ui->code_edit->clear();
            ui->account_edit->setFocus();
            file.close();
            return;
        }
        else
        {
            QMessageBox::information(this, "Hint","Abnormal! Not able to read the account");
            return;
        }

    }

}
  1. QRegExp - 是一个类提供了对正则表达式的支持,使得开发者能够进行复杂的模式匹配和数据提取任务。QRegExp 已经在 Qt 5 中被标记为过时(deprecated),并在后续版本中被建议用更现代且功能更强大的 QRegularExpression 类替代。不过,对于旧代码的维护或者对性能要求极高的场合,了解 QRegExp 仍然是有意义的

  2. .exactMatch - 是 QRegExp 类中的一个方法,专门用于判断给定的字符串是否完全符合正则表达式的模式。这意味着整个字符串从头到尾需要与正则表达式完全匹配,而不是只匹配字符串中的某个部分。

  3. Ui::LoginDialog 类是由 Qt 的 uic 工具自动生成的,它定义了你在 Qt Designer 中设计的界面的布局和组件。这个类通常不包含任何业务逻辑,只是纯粹的界面布局描述。业务逻辑需要在一个相应的包装类中实现,这个类通常会使用一个 Ui::LoginDialog 对象来设置和管理界面

  4. *ui 成员指针是一种管理和访问由 Qt Designer 生成的界面元素的便捷方式。

  5. QString 是 Qt 中用于处理字符串的核心类,设计以支持多语言和高效的文本操作

QString::numberQString 类的一个静态方法,用于将各种数值类型转换为 QString 对象

​ 例子:

int myInt = 255;
QString str1 = QString::number(myInt);
  1. QStringList 是 Qt 框架中的一个类,专门用于处理字符串列表。它基本上是 QList<QString> 的一个类型别名,提供了一系列便利的方法来操作字符串数组,例如排序、搜索和合并字符串。QStringList 给常见的列表操作增加了很多针对字符串特定的功能,使得处理字符串集合更加方便。

考试时间

右键单击项目名新建C++类的考试窗口类,取名ExamDialog.

在这里插入图片描述

打开考试窗口类头文件,编辑构造方法,声明Q_OBJECT宏、初始化计时器成员方法、刷新考试时间的槽方法并定义计时器、考试时间数据。

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;    //Timer for the exam
    int m_timeGo;       //Exam used time
    
private slots:
    void freshTime();

};

#endif // EXAMDIALOG_H

编辑ExamDialog类构造函数

ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
    setWindowTitle("Exam Time already used: 0 minutes 0 second");
    initTimer();
}

定义void initTimer()方法

void ExamDialog::initTimer()
{
    m_timeGo = 0;
    m_timer = new QTimer(this);  //this represent the current class is the 'father' of the QTimer class. So when current class is deconstruct, the QTimer class will also deconstructed.
    m_timer->setInterval(1000);
    m_timer->start();
    connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime()));
}
  • m_timer = new QTimer(this); - 这里是分配了内存空间,括号里的(this)带入原因是为了让QTimer成为当前类的子类,以便当当前的类被消除的时候,QTimer类也会被销毁.

  • m_timer->setInterval(1000); - 这行代码设置定时器的触发间隔为 1000 毫秒(1 秒)。setInterval 方法接受一个以毫秒为单位的整数,定义了 timeout() 信号的发送频率。

  • connect(m_timer,SIGNAL(timeout()),this,SLOT(freshTime())); - 这行代码的作用是在 m_timer 的定时器超时并发出 timeout() 信号时,自动调用与之连接的 freshTime() 方法。这是实现定时任务的常见方法,例如更新界面、刷新数据、或执行定时检查等。

定义 void freshTimer()方法

void ExamDialog::freshTime()
{
    //Refresh the exam time
    m_timeGo++;
    QString min = QString::number(m_timeGo / 60);
    QString second = QString::number(m_timeGo %60);

    setWindowTitle("Exam Time already used: " + min + " minutes " + second + " second");
}

编辑main.cpp文件中的main方法,并添加头文件 #include <examdialog.h>

#include "logindialog.h"
#include <QApplication>
#include <examdialog.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
//    LoginDialog w;
//    w.show();
    ExamDialog w;
    w.show();

    return a.exec();
}

初始化题库

examdialog.h添加头文件

#include <QTextEdit>
#include <QLabel>
#include <QRadioButton>
#include <QCheckBox>
#include <QGridLayout>

examdialog.h添加公有成员方法及私有数据

在这里插入图片描述

examdialog.cpp添加头文件

#include <QFile>
#include <QTextStream>
#include <QMessageBox>
#include <QApplication>

编辑ExamDialog类构造方法:

ExamDialog::ExamDialog(QWidget* parent):QDialog(parent)
{
    //Setup the font size;
    QFont font;
    font.setPointSize(12);
    this->setFont(font);

    //Setup the window bg colour
    setPalette(QPalette(QColor(209,215,255)));

    setWindowTitle("Exam Time already used: 0 minutes 0 second");
    setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
    resize(800,900);

    initTimer();
    initLayout();
    if(!initTextEditor())
    {
        QMessageBox::information(this,"Hint","Initial the question list error!");
        QTimer::singleShot(0,qApp,SLOT(quit()));   //qApp = current apps.
    }
}
  • QTFont - 在 Qt 框架中,QFont 类是用于处理字体相关属性的类。它封装了与字体相关的信息,如字体家族(如 Arial、Times New Roman 等)、字体风格(如斜体、粗体)、字体大小(点数或像素)、以及其他诸如字重、下划线、删除线等属性。

  • this->setFont(font); - 应用字体

  • setPalette(QPalette(QColor(209,215,255))); - QPalette 是 Qt 中一个非常重要的类,用于定义和管理用户界面元素的颜色方案。通过合理地使用 QPalette,开发者可以提供更丰富和符合设计需求的用户界面,增强应用程序的视觉吸引力和用户体验。

  • QTimer::singleShot 是一个非常有用的静态方法,用于在指定的延迟后执行一次给定的槽函数。这行代码实现了在程序中安排一个即刻执行的操作,该操作会导致应用程序退出

其中,0是定时器延迟的时间

qApp是全局指针,指向当前的 QApplication 实例

  • SLOT(quit()):这指定了当定时器触发时要调用的槽函数。quit()QCoreApplication(和其子类 QApplication)的一个槽

void initLayout() 成员方法添加定义:

void ExamDialog::initLayout()
{
    m_layout = new QGridLayout(this);
    m_layout->setSpacing(10);   //Setup the taskbar spacing
    m_layout->setMargin(10);    //Setup the window and the taskbar spacing
}

bool initTextEdit()添加成员方法:

bool ExamDialog::initTextEditor()
{
    QString strLine;    //Save the document read row data
    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;        //Used for saving the displayed data from the editor
        int nLines = 0;
        while(!stream.atEnd())
        {
            //Filter out the first row.
            if(nLines == 0)
            {
                stream.readLine();
                nLines++;
                continue;
            }
            //Filter out the answer row
            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;
    }
}
  • setCodec("UTF-8") 方法用于指定文本流应该使用的字符编码。这是确保文本数据以正确的格式读取和写入的关键设置

  • QTextEdit 类是一个富文本编辑器部件,提供了显示和编辑格式化文本的功能。这个类是基于 QWidget,可以用来处理纯文本和富文本,如 HTML

  • m_textEdit->setReadOnly(true) - 让文本无法被修改

  • setText() 方法属于 QTextEdit(或其他文本显示控件,如 QLabelQLineEdit 等)的成员函数之一。此方法用于设置控件的文本内容。当你在 QTextEdit 上调用 setText() 方法时,它会将控件当前显示的内容替换为你提供的新字符串

  • addWidget() 用于 QGridLayout 时,它不仅指定了要添加的控件,还指定了控件在网格中的位置和它应该占据的行和列数

  • 为什么addWidget(m_textEdit,0,0,1,10); 和 addWidget(m_textEdit,0,0,1,1); 看起来窗口一样大?

    • 因为QTextEdit 控件是窗口中唯一的或主要的控件,并且没有其他控件占用额外的空间,那么窗口的大小可能主要由 QTextEdit 的内容和默认尺寸决定。如果窗口没有设置固定大小或其他控件来影响其大小,它可能自动调整大小以适应内容或维持最小可接受尺寸

布局按键

examdialog.h添加头文件、定义单选按钮分组数据、声明void initButtons()公有成员方法:

#include <QButtonGroup>

``````````````
    public:
	void initButtons();

	private:
	QButtonGroup* m_btnGroups[9]; 
  • QButtonGroup类的定义是为了把某些特定的按键加到特定的组里面,以便该组只有一个选项可选

examdialog.cpp中添加void ExamDialog::initButtons()定义。

同时添加头文件

#include <QPushButton>

`````````````````````````````
    
void ExamDialog::initButtons()
{
    QStringList strList = {"A","B","C","D"};
    for(int i=0; i<10; i++)
    {
        //Question Label
        m_titleLabels[i] = new QLabel(this);
        m_titleLabels[i]->setText("Question: " + QString::number(i+1) );
        m_layout->addWidget(m_titleLabels[i],1,i);

        if(i ==9)
        {
            m_radioA = new QRadioButton(this);
            m_radioB = new QRadioButton(this);
            m_radioA -> setText ("正确");
            m_radioB -> setText ("错误");

            //Determine Question
            m_layout->addWidget(m_radioA,2,9);
            m_layout->addWidget(m_radioB,3,9);

            m_btnGroup[8] = new QButtonGroup(this);
            m_btnGroup[8]->addButton(m_radioA);
            m_btnGroup[8]->addButton(m_radioB);
            break;
        }

        if(i<8) m_btnGroup[i] = new QButtonGroup(this);

        //Selection question
        for(int j=0; j<4; j++)
        {
            //Multiple choice question
            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
            {
                //Single choice question
                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_btnGroup[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);
}
  • 当发现程序有问题时,可以使用Debug调试方法查看问题在哪里.
    • 快捷键F9 - 设置Breakpoint
    • 快捷键F5 - Debug模式编译程序
    • 快捷键F11-进入该行程序的内部运行
    • 快捷键F10- 运行下一行程序
    • 快捷键F9(有Breakpoint时) - 删除该Breakpoint
    • CTRL+i - 快速对齐代码

提交试卷

void ExamDialog::initButtons()定义中将提交按钮的点击信号及响应的槽方法连接起来,添加红色标注的代码。

在这里插入图片描述

  • 上述的使用信号和槽机制方法和之前做UI的方式不一样,但目的都一样?为什么?

    • void LoginDialog::on_exit_Button_clicked()
      {
          done(Rejected);
      }
      
    • 上述UI方法更简洁,无需无需手动编写 connect 语句

    • 但是使用手动编写 connect() 语句连接信号与槽提供了更高的灵活性。这种方式适合于需要动态创建连接或者处理逻辑较为复杂的场景

examdialog.h声明:void getScore()槽方法、bool hasNoSelect()成员方法

public:
``````````````
    bool haveNoSelect();
private slots:
	void getScore();
  • 上述的 haveNoSelect() 我个人认为也可以写在 private slots里面

void ExamDialog::getScore()定义:

void ExamDialog::getScore()
{
    if(haveNoSelect())
    {
        QMessageBox::information(this,"Hint","You have incompleted question, please complete it!");
        return;
    }
    int scores = 0;
    for(int i=0; i<10; i++)
    {
        if(i<8)   //Single choice question score calculation
        {
            if(m_btnGroup[i]->checkedButton()->text() == m_answerList.at(i))
            {
                scores+=10;
            }
        }
        if(i==8)   //Multiple choice question score calculation
        {
            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;
        }

        if(i==9)
        {
            if(m_btnGroup[8]->checkedButton()->text() == m_answerList.at(i))
            {
                scores += 10;
            }
        }


    }
    QString str = QString::number(scores);
    int res = QMessageBox::information(this,"Hint","Your total scores is: " + str +" Do you want to retest?",QMessageBox::Yes | QMessageBox::No);
    if(res == QMessageBox::Yes)
    {
        return;
    }
    else
    {
        close();
    }

}
*  `m_btnGroup[i]->checkedButton()->text()` - 可以直接抓取该按键群组有被点击的内容
*  `answer.contains("A")` - 可以检查该answer(QString类)的内容是否含有 "A"字母
*  `int res = QMessageBox::information(this,"Hint","..........",QMessageBox::Yes | QMessageBox::No); `- 第四个参数是让这个窗口下方拥有一个互动的Yes/No按钮给用户点击. 必须注意写成这种方式的话必须返回一个结果给int.
*  `if(res == QMessageBox::Yes)` - 代表上述的用于是否点击了Yes.
  • close(); - 这属于QWidget类的方法. 主要用于关闭当前窗口.

bool ExamDialog::hasNoSelect()定义:

bool ExamDialog::haveNoSelect()
{
    int radioSelects = 0;
    for(int i=0; i<8; i++)
    {
        if(m_btnGroup[i]->checkedButton())
        {
            radioSelects++;
        }
    }

    if(radioSelects != 8)
    {
        return true;
    }

    int checkSelects = 0;
    for(int i =0; i<4; i++)
    {
        if(m_checkBtns[i]->isChecked())
        {
            checkSelects++;
        }
    }

    if(checkSelects <=1)
    {
        return true;
    }

    if(!m_radioA->isChecked() && !m_radioB->isChecked())
    {
        return true;
    }

    return false;
}

窗口交互

登录窗口设计模式下,给取消按钮添加相应点击信号的槽方法。

logindialog.h头文件会自动添加相应槽方法的声明。

private slots:
	void on_cancelBtn_clicked();

logindialog.cpp 中编辑void LoginDialog::on_loginBtn_clicked()方法,添加done方法的那一行代码。

QDialog 类中的一个方法,用于结束对话框并设置对话框的返回值void LoginDialog::on_loginBtn_clicked()
{
    ```````````````````````
    if(strCode == strList.at(1))
	{
		QMessageBox::information(this,"Hint","Welcome to the CAT Exam");
		file.close();
		done(Accepted);
		return;
    }
    ```````````````````````````````
}

  • done()是QDialog 类中的一个方法,用于结束对话框并设置对话框的返回值.

定义void on_cancelBtn_clicked()槽方法

void LoginDialog::on_exit_Button_clicked()
{
    done(Rejected);
}

编辑mainc.pp中的程序入口函数:

#include "logindialog.h"
#include <QApplication>
#include <examdialog.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    LoginDialog logDialog;
    int res = logDialog.exec();
    if(res == QDialog::Accepted)
    {
        ExamDialog* examDialog;
        examDialog = new ExamDialog;
    }
    else
    {
        return 0;
    }
    return a.exec();

}

  • 主函数里面调用.exec 和 .show 方法都用于显示窗口,但它们的行为和用途有显著的不同
    • .show() 方法用于显示窗口,但它不会阻塞程序执行。这意味着当你调用 .show() 后,程序会继续执行后面的代码而不等待该窗口关闭..show() 方法用于显示窗口,但它不会阻塞程序执行。这意味着当你调用 .show() 后,程序会继续执行后面的代码而不等待该窗口关闭
    • .exec() 方法用于模态对话框,它会显示窗口并阻塞其后的代码执行,直到关闭该窗口。这意味着应用程序的主事件循环会等待 .exec() 方法运行的对话框关闭后才继续。.exec() 还会返回一个整数,指示对话框是如何被关闭的(例如 QDialog::AcceptedQDialog::Rejected),这有助于根据用户的响应做出适当的处理.
  • 上述代码examDialog = new ExamDialog;是为了让 examDialog不会在运行时直接’'一闪而过"
    • 因为如果没有定义动态内存的话 examDialog的作用域仅在 {} 里面,一旦程序运行结束后会直接被销毁.

发布

发布之前,请大家将代码中访问数据文件的相对路径从上级目录改成当前路径,修改后再重新编译。

在这里插入图片描述

另外也在QT 的 Projects里面更改Working Directory 路径成 D:\QT\ExamSys

  1. 设置应用程序图标

    准备好login.ico文件,ExamSys.pro文件中添加如下一行的代码

    QT       += core gui
    RC_ICONS += beluga-cat-meme.ico
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    

​ 编译运行即可。

​ 注意:使用在线转icon方法

  1. 手动发布

    文件清单:

    ExamSys.exe

    account.txt、exam.txt

    Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll

    libstdc+±6.dll、libwinpthread-1.dll、libgcc_s_sjlj-1.dll、libgcc_s_dw2-1.dll

    注意:运行时提示缺少xxx库,就补上xxx库,此清单仅可用于有Qt环境的电脑上运行。

    缺少的动态库路径(根据自己的实际安装路径查找):

    在这里插入图片描述

  2. windeployqt发布

    以下为桌面建立一个exam发布文件夹,将ExamSys.exe及account.txt、exam.txt放入文件夹中。

在这里插入图片描述

解决方法:

给mingw53_32的bin目录添加环境变量(System variables->Path->Edit),然后重新打开命令窗口:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

(4)NSIS发布

  1. 在步骤(3)(windeployqt方法)发布的文件夹中添加程序安装图标、卸载图标及License.txt文件.如下图

在这里插入图片描述

注意生成图标时候像素选择大点,如256*256。License.txt文件内容可自行定义。

  1. 安装NSIS
  2. 安装脚本编辑器
  3. 运行脚本编辑器(NisEdit)
  4. 生成脚本文件

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/797486.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

大数据基础:Hadoop之MapReduce重点架构原理

文章目录 Hadoop之MapReduce重点架构原理 一、MapReduce概念 二、MapReduce 编程思想 2.1、Map阶段 2.2、Reduce阶段 三、MapReduce处理数据流程 四、MapReduce Shuffle 五、MapReduce注意点 六、MapReduce的三次排序 Hadoop之MapReduce重点架构原理 一、MapReduce概…

JavaScript中的面向对象编程

OPP在JavaScript的表现方式&#xff1a;原型 传统的OPP&#xff1a;类 ● 对象&#xff08;实例&#xff09;由类实例化&#xff0c;类的功能类似于蓝图&#xff0c;通过蓝图来实现建筑&#xff08;实例&#xff09; ● 行为&#xff08;方法&#xff09;从类复制到所有实例 …

【2-1:RPC设计】

RPC 1. 基础1.1 定义&特点1.2 具体实现框架1.3 应用场景2. RPC的关键技术点&一次调用rpc流程2.1 RPC流程流程两个网络模块如何连接的呢?其它特性RPC优势2.2 序列化技术序列化方式PRC如何选择序列化框架考虑因素2.3 应用层的通信协议-http2.3.1 基础概念大多数RPC大多自…

并查集——AcWing 239. 奇偶游戏

目录 并查集 定义 运用情况 注意事项 解题思路 AcWing 239. 奇偶游戏 题目描述 运行代码 代码思路 改进思路 并查集 定义 并查集&#xff08;Disjoint Set Union&#xff0c;简称DSU&#xff09;&#xff0c;是一种树形的数据结构&#xff0c;常用于处理一些不交集…

jvm 07 GC算法,内存池

01 垃圾判断算法 1.1引用计数算法 最简单的垃圾判断算法。在对象中添加一个属性用于标记对象被引用的次数&#xff0c;每多一个其他对象引用&#xff0c;计数1&#xff0c; 当引用失效时&#xff0c;计数-1&#xff0c;如果计数0&#xff0c;表示没有其他对象引用&#xff0c;…

一文详解DDL同步及其应用场景

目录 一、什么是DDL&#xff1f; 二、什么是DDL同步&#xff1f; 三、DDL同步的痛点 1、缺少自动DDL同步机制 2、缺少DDL变更监测预警 四、解决方案 五、应用场景及案例 案例一 案例二 案例三 在现代数据管理中&#xff0c;数据库的结构变更频繁且不可避免&#xff0c;特别是在…

计算机视觉之Vision Transformer图像分类

Vision Transformer&#xff08;ViT&#xff09;简介 自注意结构模型的发展&#xff0c;特别是Transformer模型的出现&#xff0c;极大推动了自然语言处理模型的发展。Transformers的计算效率和可扩展性使其能够训练具有超过100B参数的规模空前的模型。ViT是自然语言处理和计算…

卑微的LDAR第三方检测公司该如何应对政府强制使用LDAR系统

最近两年各个地方环保局和园区都再上LDAR管理系统&#xff0c;本来上系统是好事&#xff0c;监管企业和第三方检测公司规范开展检测业务&#xff0c;但是部分系统给第三方检测企业增加了大量的工作量&#xff0c;有的甚至由于系统不稳定&#xff0c;造成企业无法开展工作&#…

各种Attention|即插即用|适用于YoloV5、V7、V8、V9、V10(一)

摘要 本文总结了各种注意力&#xff0c;即插即用&#xff0c;方便大家将注意力加到自己的论文中。 SE import torch from torch import nn class SEAttention(nn.Module): """ SENet&#xff08;Squeeze-and-Excitation Networks&#xff09;中的注意力…

排序——交换排序

在上篇文章我们详细介绍了排序的概念与插入排序&#xff0c;大家可以通过下面这个链接去看&#xff1a; 排序的概念及插入排序 这篇文章就介绍一下一种排序方式&#xff1a;交换排序。 一&#xff0c;交换排序 基本思想&#xff1a;两两比较&#xff0c;如果发生逆序则交换…

Linux 下 redis 集群部署

目录 1. redis下载 2. 环境准备 3. redis部署 3.1 修改系统配置文件 3.2 开放端口 3.3 安装 redis 3.4 验证 本文将以三台服务器为例&#xff0c;介绍在 linux 系统下redis的部署方式。 1. redis下载 下载地址&#xff1a;Index of /releases/ 选择需要的介质下载&am…

【笔记】在虚拟中的主从数据库连接实体数据库成功后的从数据库不同步问题解决方法1

130是主数据库 131是从数据 数据可以说是一点没同步 解决方法; 重新设置主从连接 在虚拟机中mysql账号xiaoming&#xff08;主从数据库的桥梁账号&#xff09;登录 主数据要做的&#xff1a; show master status&#xff1b; 可以发现 这两个值发送了变化 从数据库mysql中…

探索4D毫米波雷达和摄像头在自动驾驶中的潜力

随着自动驾驶技术的快速发展&#xff0c;关于各种传感器的必要性&#xff0c;尤其是LiDAR&#xff08;激光雷达&#xff09;与毫米波雷达结合摄像头的作用&#xff0c;激发了激烈的讨论。在这篇博客中&#xff0c;我们将探讨4D毫米波雷达和摄像头的组合是否可能成为自动驾驶车辆…

一篇学通Axios

Axios 是一个基于 Promise 的 HTTP 客户端&#xff0c;用于浏览器和 node.js 环境。它提供了一种简单易用的方式来发送 HTTP 请求&#xff0c;并支持诸如请求和响应拦截、转换数据、取消请求以及自动转换 JSON 数据等功能。 Axios 名字的由来 Axios 的名字来源于希腊神话中的…

高校寻物平台小程序的设计

失主账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;寻物启示管理&#xff0c;失物归还管理&#xff0c;失物认领管理&#xff0c;举报投诉管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;寻物启示&#xff0c;失物招领&#xff0c;公告信息&…

eNsp公司管理的网络NAT策略搭建

实验拓扑图 实验需求&#xff1a; 7&#xff0c;办公区设备可以通过电信链路和移动链路上网(多对多的NAT&#xff0c;并且需要保留一个公网IP不能用来转换) 8&#xff0c;分公司设备可以通过总公司的移动链路和电信链路访问到Dmz区的http服务器 9&#xff0c;多出口环境基于带…

【Python】爬虫实战01:获取豆瓣Top250电影信息

本文中我们将通过一个小练习的方式利用urllib和bs4来实操获取豆瓣 Top250 的电影信息&#xff0c;但在实际动手之前&#xff0c;我们需要先了解一些关于Http 请求和响应以及请求头作用的一些知识。 1. Http 请求与响应 HTTP&#xff08;超文本传输协议&#xff09;是互联网上…

Unity中一键生成具有身体感知的虚拟人物动作

在虚拟现实(VR)和增强现实(AR)的浪潮中&#xff0c;如何让虚拟人物的动作更加自然、真实&#xff0c;已经成为一个重要课题。AI4Animation项目&#xff0c;一个由 Sebastian Starke 主导的开源框架&#xff0c;为Unity开发者提供了强大的工具集&#xff0c;以实现这一目标。本文…

threadx netxduo stm32f407上实现http server

这次用的是CubeIDE + CubeMX 要把NX_APP的mem分配的大一些,在app_azure_rtos.c中,我给的是40*1024,如果给的不够,会导致后面无法分配pool和thread等等 需要用到filex 要在CubeMX里面勾选上,还要用到http_server和dhcp netxduo/addons/auto_ip at v6.1.11_rel eclipse-th…

AI时代:探索个人潜能的新视角

文章目录 Al时代的个人发展1 AI的高速发展意味着什么1.1 生产力大幅提升1.2 生产关系的改变1.3 产品范式1.4 产业革命1.5 Al的局限性1.5.1局限一:大模型的幻觉 1.5.2 局限二&#xff1a;Token 2 个体如何应对这种改变?2.1 职场人2.2 K12家长2.3 大学生2.4 创业者 3 人工智能发…