Qt 驾校考试系统项目实现

一 登录界面

  • 创建项目的时候选择Dialog
  • 图片大小和背景框不匹配时,可以勾选scaledContents

1 正则表达式 验证用户密码和邮箱

// \\w 是为了在 C++ 字符串中正确表示正则表达式中的 \w。如果你只写
 \w,C++ 会将其解释为一个转义字符,而不是正则表达式中的 \w
//正则表达式里面表示. ,就需要使用\.,进一步的,当前正则表达式是在字符串里面,需要加一个\来进行转义
//[a-zA-Z0-9\\-]+: 匹配一个字母(a-zA-Z)、数字(0-9)或连字符(-)。连字符 - 被转义为 
\\-,以确保它被当作普通字符而不是范围符号,
//, +表示前面字符出现一次或多次, +不需要转义字符


[]

cpp 复制代码
void DialogLogin::on_pushButtonLogin_clicked()
{
    //要求必须以字母开头,6-18个字符,\w表示匹配字母数字或下划线
    // \\w 是为了在 C++ 字符串中正确表示正则表达式中的 \w。如果你只写 \w,C++ 会将其解释为一个转义字符,而不是正则表达式中的 \w
    //正则表达式里面表示. ,就需要使用\.,进一步的,当前正则表达式是在字符串里面,需要加一个\来进行转义
    //[a-zA-Z0-9\\-]+: 匹配一个字母(a-zA-Z)、数字(0-9)或连字符(-)。连字符 - 被转义为 \\-,以确保它被当作普通字符而不是范围符号,
    //, +表示前面字符出现一次或多次, +不需要转义字符

    QRegExp mail("^[a-zA-Z][\\w]{5,17}@([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,6}$");

    bool res = mail.exactMatch(ui->lineEditLogin->text());
    if(!res){  //验证邮箱的合法性
        QMessageBox::warning(this,"提示","非法邮箱,请重新输入");
        ui->lineEditLogin->clear();
        ui->lineEditLogin->setFocus();

    }else{ //验证用户和密码的一致性
        QString code = ui->lineEditCode->text();
        QString user = ui->lineEditLogin->text();

        if(code.isEmpty()){
            QMessageBox::warning(this,"提示","密码不能为空");
        }

        //QString filename = FILENAME;
        QString filename = "I:/QT_PRACTICE/myExam22/account.txt";
        if(!filename.isEmpty()){
            //把文本编辑器的内容保存到文本
            QFile qfile(filename);
            qDebug() << filename;
            if(! qfile.open(QIODevice::ReadOnly | QIODevice::Text)){
                qDebug() << "文件打开失败";
                return;
            }

            QStringList codeList;
            QStringList userList;
            QTextStream stream(&qfile);
            while (!stream.atEnd()) {
                    QString line = stream.readLine();
                    // 分割邮箱和密码
                    QStringList list = line.split(',');
                    if (list.size() == 2) {
                        QString email = list.at(0);
                        QString password = list.at(1);

                        codeList.append(password);
                        userList.append(email);
                    }
              }

            qfile.close();

            bool succeedLabel = 0;
            for(int i = 0; i< codeList.count() ; i++){
                 if(code == codeList[i] && user == userList[i]){
                    QMessageBox::information(this,"提示","成功登录");
                    succeedLabel = 1;
                    break;
                 }
            }

            if(succeedLabel == 0){
                 QMessageBox::warning(this,"提示","用户名或密码错误");
                 ui->lineEditCode->clear();
                 ui->lineEditLogin->clear();
                 ui->lineEditLogin->setFocus();
            }
        }

    }
}

2 知识点

  • 知识点1 :只有第一次调用的时候需要设置起始点,之后就不需要了,否则位置坐标不对m_layout->addWidget(m_textEdit,0,0,1,10); //起始位置 0行,0列,行宽和列宽分别是1和10,后面调用 `` m_layout->addWidget(title,1,k);,`
  • 知识点2 :自定义组件我看有两种方式,一种是在头文件定义指针之后,在函数里面使用的时候,重新new一个对象,另一种是,头文件定义指针之后,cpp文件就直接用,不再new了。啥时候要new新的对象,啥时候不需要new呢?
    (a)头文件定义类对象指针,但是并没有分配内存空间,所以后面用的时候是必须要new m_textEdit = new QTextEdit(this);来进行空间的分配的,否则就成页指针了
    (b)至于什么时候new,那取决于是整个程序只有一个组件,还是有多个组件,如果是多个组件,那么在不同地方调用的时候,都需要new一个新的内存空间,但是如果只是一个组件,那就只需要在构造函数里面进行一次空间分配,然后后面函数就可以直接使用了


  • 知识点3 :什么时候需要定义信号,当前案例里面,自定义的pushButon按钮实现考试的提交,也是属于Qt按钮

    1.只有自己写的类才需要定义自己的信号,如果调用已有的组件,是不需要自己来写信号的

    2.QT内部组件会自动发送信号,不需要手动发送信号

  • 知识点4 :什么时候需要创建c++类文件,什么时候需要创建Qt设计师界面类,.cpp类文件的情况::Graphics View组件对应的类对象是QGraphicsView,是标准类对象,无法进行修改,需要自定义一个视图,去重载该类的鼠标事件

    ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/a22cd8c5986449eaaa8a8784d0e3b392.png #pic_center =500x)

  • 知识点5 :如果要控制一个界面A运行完毕,关闭当前界面A然后打开另一个界面B,在main函数里面做如下实现,同时在界面A的相应确认打开界面B的位置添加done(Accepted);语句

  • 知识点6QVector<Question> Data; //存放题库 QVector<QButtonGroup*> btnGroup;,定义指针和不定义指针的情况有什么区别,调用的时候都是通过.来调用,而不是->,以下是查到的区别,对于动态分配内存这一点的理解是:前者调用的时候不需要使用new来为对象分配内存空间,后者需要

cpp 复制代码
private:
    QVector<Question> Data;  //存放题库
    QVector<QButtonGroup*> btnGroup;
cpp 复制代码
当前案例使用
         //判断是单选还是多选
        QButtonGroup *group = new QButtonGroup;
        if(Data[k].isSigleQuestion()){  //单选
            for(int i =0; i< Data[k].get_choiceNum(); i++){
                QRadioButton *btn = new QRadioButton;
                btn->setText(Data[k].quesChoices[i].first);
                group->addButton(btn);
                m_layout->addWidget(btn,rwoIndex + i + 1,k%eachLineShow_num);  //

            }
        }else{  //多选
            group->setExclusive(false);
            for(int i =0; i< Data[k].get_choiceNum(); i++){
                QCheckBox *checkBox = new QCheckBox;
                checkBox->setText(Data[k].quesChoices[i].first);
                group->addButton(checkBox);
                m_layout->addWidget(checkBox,rwoIndex + i + 1,k%eachLineShow_num);  //
            }
        }
        btnGroup.append(group);
bash 复制代码
            case READ_ANSER:
                if(line.at(0) == '!'){
                      line.remove(0,1);
                      //qDebug() << "答案:"<< line;
                      anse.append(line);

                      Question ques(titelLable, anse);
                      //qDebug() << "choiceLabel.size():"<< choiceLabel.size();
                      for(int i =0; i< choiceLabel.size(); i++){
                          QPair<QString, int> temp;
                            ques.quesChoices.push_back(QPair<QString, int>(choiceLabel[i],0));
                      }
                      Data.append(ques);
                }


cpp 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    DialogLogin w;

    if(w.exec() == QDialog::Accepted){
        QDialogExamUI ed;
        ed.show();
        return a.exec();
    }
    return a.exec();
}

3 代码及文件创建 add->new->cpp,选择或者填入继承QDialog类,创建.cpp文件,注意,头文件要做相应的修改

  • 效果

"dialoglogin.h"

cpp 复制代码
#ifndef DIALOGLOGIN_H
#define DIALOGLOGIN_H

#include <QDialog>

QT_BEGIN_NAMESPACE
namespace Ui { class DialogLogin; }
QT_END_NAMESPACE

class DialogLogin : public QDialog
{
    Q_OBJECT

public:
    DialogLogin(QWidget *parent = nullptr);
    ~DialogLogin();

private slots:
    void on_pushButtonLogin_clicked();

    void on_pushButtonExit_clicked();

private:
    Ui::DialogLogin *ui;
};
#endif // DIALOGLOGIN_H
  • "qdialogexamui.h"
cpp 复制代码
#ifndef QDIALOGEXAMUI_H
#define QDIALOGEXAMUI_H

#include <QDialog>
#include <QTextEdit>
#include <QGridLayout>
#include <QVector>
#include "question.h"
#include <QCheckBox>
#include <QRadioButton>
#include <QButtonGroup>
#include <QAbstractButton>  //是 QRadioButton和 QCheckBox的父类
#include <QPushButton>
enum State{
    BEGIN,
    READ_TILTE,
    READ_CHOICE,
    READ_ANSER
};

class QDialogExamUI : public QDialog
{
    Q_OBJECT
public:
    QDialogExamUI(QWidget *parent = nullptr);
    ~QDialogExamUI();


private:
    QTextEdit *m_textEdit;  //显示考试内容
    QGridLayout *m_layout;  //布局管理器

    void initUI(); //初始化组件
    void initSlot();
    void initContent();  //解析文本内容
    void initShowContent();
    double getScore();

    QVector<Question> Data;  //存放题库
    QVector<QButtonGroup*> btnGroup;
    QPushButton *m_submitBtn;
    int eachLineShow_num = 10;

private slots: //槽函数
    void on_m_submitBtn_clicked(bool clicked);
};
#endif // QDIALOGEXAMUI_H
  • "question.h"
cpp 复制代码
#ifndef QUESTION_H
#define QUESTION_H
#include <QString>
#include <QStringList>
#include <QVector>
#include <QPair>
class Question
{
public:
     Question(const QString quesIndex, const QString quesAnser);
     Question();
    ~Question();
     Question(const Question &ques);  //拷贝构造函数
//     QVector<QPair<QString,QString>> quesChoices; // <QPair <选项索引,选项内容>>  考虑到绘制题目的时候不需要选项内容
     QVector<QPair<QString,int>> quesChoices;  // <QPair <选项索引,选项是否被选中>>
     bool isSigleQuestion();  //判断是否是单选
     QString get_quesIndex();
     QStringList get_quesAnser();
     int get_choiceNum();
private:
    QString quesIndex;     //题目编号
    QString quesAnser; //题目答案
    int choiceNum;         //选项数量
    bool is_single_ques;   //1 单选,0多选
};

#endif // QUESTION_H
  • "dialoglogin.cpp"
cpp 复制代码
#include "dialoglogin.h"
#include "ui_dialoglogin.h"
#include <QDebug>
#include <QMessageBox>
#include <QFile>

#define FILENAME "account.txt"
DialogLogin::DialogLogin(QWidget *parent)
    : QDialog(parent)
    , ui(new Ui::DialogLogin)
{
    ui->setupUi(this);
    setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint); //关掉默认的右上角的叉叉
    setWindowTitle("驾校考试系统");
}

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


void DialogLogin::on_pushButtonLogin_clicked()
{
    //要求必须以字母开头,6-18个字符,\w表示匹配字母数字或下划线
    // \\w 是为了在 C++ 字符串中正确表示正则表达式中的 \w。如果你只写 \w,C++ 会将其解释为一个转义字符,而不是正则表达式中的 \w
    //正则表达式里面表示. ,就需要使用\.,进一步的,当前正则表达式是在字符串里面,需要加一个\来进行转义
    //[a-zA-Z0-9\\-]+: 匹配一个字母(a-zA-Z)、数字(0-9)或连字符(-)。连字符 - 被转义为 \\-,以确保它被当作普通字符而不是范围符号,
    //, +表示前面字符出现一次或多次, +不需要转义字符

    QRegExp mail("^[a-zA-Z][\\w]{5,17}@([a-zA-Z0-9\\-]+\\.)+[a-zA-Z]{2,6}$");

    bool res = mail.exactMatch(ui->lineEditLogin->text());
    if(!res){  //验证邮箱的合法性
        QMessageBox::warning(this,"提示","非法邮箱,请重新输入");
        ui->lineEditLogin->clear();
        ui->lineEditLogin->setFocus();

    }else{ //验证用户和密码的一致性
        QString code = ui->lineEditCode->text();
        QString user = ui->lineEditLogin->text();

        if(code.isEmpty()){
            QMessageBox::warning(this,"提示","密码不能为空");
        }

        //QString filename = FILENAME;
        QString filename = "I:/QT_PRACTICE/myExam22/account.txt";
        if(!filename.isEmpty()){
            //把文本编辑器的内容保存到文本
            QFile qfile(filename);
            qDebug() << filename;
            if(! qfile.open(QIODevice::ReadOnly | QIODevice::Text)){
                qDebug() << "文件打开失败";
                return;
            }

            QStringList codeList;
            QStringList userList;
            QTextStream stream(&qfile);
            while (!stream.atEnd()) {
                    QString line = stream.readLine();
                    // 分割邮箱和密码
                    QStringList list = line.split(',');
                    if (list.size() == 2) {
                        QString email = list.at(0);
                        QString password = list.at(1);

                        codeList.append(password);
                        userList.append(email);
                    }
              }

            qfile.close();

            bool succeedLabel = 0;
            for(int i = 0; i< codeList.count() ; i++){
                 if(code == codeList[i] && user == userList[i]){
                    QMessageBox::information(this,"提示","成功登录");
                    succeedLabel = 1;
                    done(Accepted);
                    break;
                 }
            }

            if(succeedLabel == 0){
                 QMessageBox::warning(this,"提示","用户名或密码错误");
                 ui->lineEditCode->clear();
                 ui->lineEditLogin->clear();
                 ui->lineEditLogin->setFocus();
            }
        }

    }
}

void DialogLogin::on_pushButtonExit_clicked()
{
    this->close();
}
  • "qdialogexamui.cpp"
cpp 复制代码
#include "qdialogexamui.h"
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QFont>
#include <QDebug>
#include <QLabel>
#include <QAbstractButton>
QDialogExamUI::QDialogExamUI(QWidget *parent):QDialog(parent)
{
      m_textEdit = new QTextEdit(this);
      m_layout = new QGridLayout(this);
      m_submitBtn = new QPushButton(this);

      initUI();
      initContent();
      initShowContent();
      initSlot();
}

QDialogExamUI::~QDialogExamUI()
{

}

void QDialogExamUI::initUI()
{
    //-----------------主窗体初始化----------------------------
    this->setMinimumSize(800, 600); // 设置窗体的最小大小为 800x600

    //-----------------布局管理器边界设置的初始化----------------------------
    m_layout->setMargin(10);
    m_layout->setSpacing(10);

    //-----------------文本编辑器----------------------------
//    //显示文本
//    m_textEdit->setMaximumWidth(200);
//    m_textEdit->setMaximumHeight(900);

    //设置显示文本的字体和大小
    QFont font = m_textEdit->font();  //先将字体取出来
    font.setPointSize(12); //字体
    font.setFamily("微软雅黑");
    m_textEdit->setFont(font);
    //m_layout->addWidget(m_textEdit,0,1);
    m_layout->addWidget(m_textEdit,0,0,1,10); //起始位置 0行,0列,行宽和列宽分别是1和10


}

void QDialogExamUI::initSlot()
{
    //-----------------考试提交按钮----------------------------
    connect(m_submitBtn,SIGNAL(clicked(bool)),this,SLOT(on_m_submitBtn_clicked(bool)));

}

void QDialogExamUI::initShowContent()
{
    QFont font = m_textEdit->font();  //先将字体取出来
     font.setPointSize(12); //字体
     font.setFamily("微软雅黑");
     m_textEdit->setFont(font);

    //-----------------显示题目和选项按钮----------------------------

    int maxChoiceNum =0;
    int rwoIndex =1;
    if(eachLineShow_num > Data.size()){
        eachLineShow_num = Data.size();
    }

    for(int k = 0; k < Data.size(); k++){

        if(k % eachLineShow_num == 0)
        {
            rwoIndex += maxChoiceNum +1;
        }


        //获取每行显示题目数量的最大题目数
        for(int i =0; i< eachLineShow_num; i++){
            if(Data[i].get_choiceNum() > maxChoiceNum){
                maxChoiceNum = Data[i].get_choiceNum();
            }
        }

        //显示标题
         QLabel *title = new QLabel(this);
         title->setText("第" + Data[k].get_quesIndex()+ "题");
         title->setFont(font);
//         m_layout->addWidget(title,0,0,1,k);
         m_layout->addWidget(title,rwoIndex,k%eachLineShow_num);  //

        //显示选项

         //判断是单选还是多选
        QButtonGroup *group = new QButtonGroup;
        if(Data[k].isSigleQuestion()){  //单选
            for(int i =0; i< Data[k].get_choiceNum(); i++){
                QRadioButton *btn = new QRadioButton;
                btn->setText(Data[k].quesChoices[i].first);
                group->addButton(btn);
                m_layout->addWidget(btn,rwoIndex + i + 1,k%eachLineShow_num);  //

            }
        }else{  //多选
            group->setExclusive(false);
            for(int i =0; i< Data[k].get_choiceNum(); i++){
                QCheckBox *checkBox = new QCheckBox;
                checkBox->setText(Data[k].quesChoices[i].first);
                group->addButton(checkBox);
                m_layout->addWidget(checkBox,rwoIndex + i + 1,k%eachLineShow_num);  //
            }
        }
        btnGroup.append(group);

    }


    //-----------------考试提交按钮----------------------------
    m_submitBtn->setText("提交");
    m_submitBtn->setFont(font);
    m_layout->addWidget(m_submitBtn,rwoIndex+maxChoiceNum+1,eachLineShow_num-1);
}

double QDialogExamUI::getScore()
{
    double socre = 0;
    for(int k= 0; k <Data.size(); k++){
        QList<QAbstractButton*> buttons = btnGroup[k]->buttons();
        QStringList ans = Data[k].get_quesAnser();
        //判断是单选还是多选
        if(Data[k].isSigleQuestion()){
            for(int i =0; i <buttons.size();i ++){
                if(buttons[i]->isChecked() && buttons[i]->text() == ans[0]){
                    socre += 10;
                    break;
                }
            }
        }else{
            int ans_num = ans.size();
            int counter = 0;
            for(int i =0; i <buttons.size();i ++){
                //遍历答案进行对比
                if(buttons[i]->isChecked()){
                    for(int a =0; a <ans_num;a ++){
                      //  qDebug() <<"buttons[i]->text() = " << buttons[i]->text() << ",a = " << a << ",ans[a] =  " << ans[a];
                        if(buttons[i]->text() == ans[a]){
                            counter += 1;
                            break;
                        }
                   }
              }
            }

            if(counter == ans_num){
                socre += 10;
            }
        }
    }

    return socre;
}

void QDialogExamUI::on_m_submitBtn_clicked(bool clicked)
{
    bool ret = QMessageBox::information(this,"提示","是否确认提交",QMessageBox::Ok | QMessageBox::Cancel);
    qDebug() << "ret = " << ret;
    bool done = true;
    if(ret){
        //判断是否题目没有完成
        for(int k= 0; k <Data.size(); k++){
            QAbstractButton *checkedButton = btnGroup[k]->checkedButton();
            if(!checkedButton){
                QMessageBox::warning(this,"提示","还有选项为完成!",QMessageBox::Ok);
                done = false;
                break;
            }
        }

        if(done){
            double score = getScore();
            bool ret2 =QMessageBox::information(this,"提示","您的考试分数是:" + QString::number(score) + ",是否退出考试?",QMessageBox::Ok,QMessageBox::NoButton);
            if(ret2){
                this->close();
            }
        }

    }
}

void QDialogExamUI::initContent()
{
    //当前函数,读取考题内容
    QString filename = "I:/QT_PRACTICE/myExam22/exam.txt";
    QFile file(filename);
    if(! file.open( QIODevice::ReadOnly | QIODevice::Text)){
        QMessageBox::warning(this,"警告","文件打开失败");
        return;
    }

    State currentState = State::BEGIN;
    bool readNew = true;
    QString line;
    QString titelLable;
    QStringList choiceLabel;
    QString anse;

    QTextStream stream(&file);
    stream.setCodec("UTF-8");

    while(1){
        if(!readNew){
             readNew = true;
        }else{
            if(stream.atEnd()){
                break;
            }
            line = stream.readLine();
        }

        if(line.isEmpty()) continue;
        if(line.at(0) == "#") continue;

        //状态机将题目存储进题库
            switch(currentState){
            case BEGIN:
                titelLable.clear();
                choiceLabel.clear();
                anse.clear();
                //开始状态要求必须是题目
                if(line.at(0) == 'Q'){
                    currentState = State::READ_TILTE;
                    readNew = false;
                }
                else{
                    QMessageBox::warning(this,"警告","BEGIN, 题库格式错误");
                }
                break;

            case READ_TILTE:
                if(line.at(0) == 'Q'){
                    line.remove(0,1);
                    m_textEdit->append(line);

                    titelLable.append(line.split('.').first());
                   // qDebug() << "题目:" <<line.split('.').first()<< "内容" << line;

                }else if(line.at(0) == '.'){
                    currentState = State::READ_CHOICE;
                    readNew = false;
                }else{
                    QMessageBox::warning(this,"警告","READ_TILTE, 题库格式错误");
                }
                break;

            case READ_CHOICE:
                if(line.at(0) == '.'){
                    line.remove(0,1);
                    m_textEdit->append(line);
                    choiceLabel.append(line.at(0));
                    //qDebug() << "选项:" <<line.at(0) << "内容" << line;
                }else if(line.at(0) == '!'){
                    currentState = State::READ_ANSER;
                    readNew = false;
                }else{
                    QMessageBox::warning(this,"警告","READ_CHOICE, 题库格式错误");
                }
                break;
            case READ_ANSER:
                if(line.at(0) == '!'){
                      line.remove(0,1);
                      //qDebug() << "答案:"<< line;
                      anse.append(line);

                      Question ques(titelLable, anse);
                      //qDebug() << "choiceLabel.size():"<< choiceLabel.size();
                      for(int i =0; i< choiceLabel.size(); i++){
                          QPair<QString, int> temp;
                            ques.quesChoices.push_back(QPair<QString, int>(choiceLabel[i],0));
                      }
                      Data.append(ques);
                }
                else if(line.at(0) == 'Q'){
                    currentState = State::BEGIN;
                    readNew = false;
                    m_textEdit->append("\n");
                }else{
                    QMessageBox::warning(this,"警告","READ_ANSER, 题库格式错误");
                }
                break;
            }

        }

    file.close();
}
  • "question.cpp"
cpp 复制代码
#include "question.h"

Question::Question(const QString quesIndex, const QString quesAnser)
{
    this->quesIndex = quesIndex;
    this->quesAnser = quesAnser;
    this->choiceNum = 0;
    quesChoices.clear();


    QStringList list = quesAnser.split("");
    // 移除第一个空字符串
    if (!list.isEmpty() && list.first().isEmpty())  {
        list.removeFirst();
    }
    for(int i =0; i< list.size();i ++){
        if(list[i] == "" || list[i] == " "){
            list.removeAt(i);
        }
    }


    if(list.size() > 1){
        this->is_single_ques = false;
    }else if(list.size() == 1)
    {
         this->is_single_ques = true;
    }


}

Question::Question()
{

}

Question::~Question()
{

}

Question::Question(const Question &ques)
{
    this->quesIndex = ques.quesIndex;
    this->quesAnser = ques.quesAnser;
    this->is_single_ques = ques.is_single_ques;
    this->choiceNum = ques.choiceNum;

//    // 分配足够的内存空间
//    this->quesChoices.resize(ques.quesChoices.size());
//    for(int i =0;i < ques.quesChoices.size(); i++){
//        this->quesChoices[i].first = ques.quesChoices[i].first;
//        this->quesChoices[i].second = ques.quesChoices[i].second;
//    }
    this->quesChoices = ques.quesChoices;
}

bool Question::isSigleQuestion()
{
    return is_single_ques;
}

QString Question::get_quesIndex()
{
    return quesIndex;
}

QStringList Question::get_quesAnser()
{
    QStringList list = quesAnser.split("");
    // 移除第一个空字符串
    if (!list.isEmpty() && list.first().isEmpty())  {
        list.removeFirst();
    }

    for(int i =0; i< list.size();i ++){
        if(list[i] == "" || list[i] == " "){
            list.removeAt(i);
        }
    }

    return list;
}

int Question::get_choiceNum()
{
    this->choiceNum = quesChoices.size();
    return this->choiceNum;
}
相关推荐
SNAKEpc1213823 分钟前
Qt开源控件库(qt-material-widgets)的编译及使用
c++·qt·开源
拓端研究室TRL1 小时前
R软件线性模型与lmer混合效应模型对生态学龙类智力测试数据层级结构应用
开发语言·r语言
于慨2 小时前
计算机考研C语言
c语言·开发语言·数据结构
GGGGGGGGGGGGGG.2 小时前
使用dockerfile创建镜像
java·开发语言
请为小H留灯2 小时前
Python中很常用的100个函数整理
开发语言·python
达斯维达的大眼睛3 小时前
QT小项目-简单的记事本
开发语言·qt
轩宇^_^3 小时前
C++ 类与对象的实际应用案例详解
开发语言·c++
oioihoii3 小时前
从零到多页复用:我的WPF MVVM国际化实践
开发语言·c#·wpf
Source.Liu3 小时前
【学写LibreCAD】 2.1 pdf_print_loop文件
qt·rust·pdf·cad·dxf
c7_ln3 小时前
编程视界:C++命名空间
开发语言·c++·笔记