QT-学生成绩管理系统

基于QT开发的学生成绩管理系统

一.整体概述

1.任务要求

  1. 实现导入和保存表格信息。如果数据未填写,弹窗提示。

  2. 清空表格信息

  3. 插入和删除表格

  4. 对学号、数学、英语、C语言、电路分析、平均分进行升序排序,并体现在表格中

  5. 查找学号,信息打印在文本框中

  6. 点击About,展示个人信息.

2.功能展示

在这里插入图片描述

二.功能实现

1.UI实现

事实上,Qt Creator在UI实现方面可以说就像是小学生玩图形化编程一样easy。

在数据显示方面我们需要一个区域去展示数据,所以我们拖动一个table view即可。

信息打印区同理,采用了一个text Edit。

在这里插入图片描述

采集数据区根据任务要求,我们需要输入id、姓名、数学成绩、英语成绩、C语言成绩以及电路成绩,所以我们需要一共6个line Edit,以便采集数据,并采用label加以区分
在这里插入图片描述
在这里插入图片描述

在这里我们为了后续操作方便,为他们改不同的名字,这点的主要目的就如同程序中的注释,它可以不存在,但最好有。

功能区从下往上,从左往右看,首先是插入、删除、查询三个按键,其次是用以排序的条件以及排序按键。

在这里插入图片描述

注:

valueComBox如下图

在这里插入图片描述

condcomBox如下图

在这里插入图片描述

然后是工具栏,我们需要添加工具栏并且导入资源图标,这方面我们不去赘述。

它的存在更像是一个好看一点的按键,其实本质上与按键没什么区别。

在这里插入图片描述

2.头文件&&主要任务

这里我们主要看一下需要什么头文件并且根据UI去看需要完成哪些功能函数。

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDialog>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlQueryModel>
#include <QSqlError>
#include <QDebug>
#include <QMessageBox>
#include <QFileDialog>
#include <QLockFile>

QT_BEGIN_NAMESPACE

namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void createDB();                        //创建数据库

    void createTable();                     //创建表

    void queryTable();                      //显示表

    void on_insertButton_clicked();         //插入按钮槽函数

    void on_deleteButton_clicked();         //删除按钮槽函数

    void on_getButton_clicked();            //查询按钮槽函数

    void on_sortButton_clicked();           //排序按钮槽函数

    void on_actionOpen_triggered();         //导入文件

    void on_actionSave_triggered();         //保存文件

    void on_actionClear_triggered();        //全部删除

    void on_actionAbout_triggered();        //显示文件

private:
    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H

3.初始化

3.1 数据库(createDB)
3.1.1 什么是数据库

开始编写函数前,我想大家需要先了解数据库,以便后续更好的展开。

程序在运行的过程中,数据都是在内存中存储的,但是内存一旦断电就会丢失数据。因此需要持久保存的数据会转交给硬盘。

在编程领域,最常用的方式是使用数据库批量的存储大量数据到硬盘。也就是说,数据库是一种电子化的资料柜。

数据库产品非常多,主流的包括:MySQL、SQLite、Oracle…这些不同的数据库都是由不同的软件公司开发而来,每种数据库各有差别。IBM公司针对市面上各种不同厂家的数据库推出了统一的操作语言——SQL语言(语句)。

嵌入式领域中最常用的数据库产品是SQLite,本次学习的数据库就是SQLite。

SQLite是一款轻量级的数据库,只需要数兆的体积,免安装即可使用,因此很多嵌入式相关的技术框架都会内置SQLite数据库。

3.1.2 操作环境

在头文件编写完成的基础上,在.pro文件中加入这句话。

QT       += sql

同时为了观察方便,我们可以使用SQLiteSpy软件对我们的数据库进行观察修改。

在这里插入图片描述

SQLite数据库是以单文件进行存储的,一个数据库就是一个文件,文件的格式是.db或.db3,只需要使用SQLiteSpy软件打开.db或.db3文件即可。

将我们刚刚展示的程序中的.db文件打开后如下:

在这里插入图片描述

3.1.3 连接数据库
void MainWindow::createDB(){
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("student.db");     //如果本目录下没有该文件,则会在本目录下生成,否则连接该文件

    //判断是否操作成功
    if (!db.open()) {
        QMessageBox::warning(0, QObject::tr("Database Error"),
                             db.lastError().text());
    }
    else{
        ui->textEdit->setText("链接数据库成功");
    }
}
3.2 表(createTable)
3.2.1 创建一张表的语法格式:
CREATE TABLE 表名(
    列名1    类型    [DEFAULT],
    列名2    类型    [DEFAULT],
    ...,
	列名n    类型    [DEFAULT]
);
3.2.2 约束

约束是在表的数据列中增加强制执行的规则,这些约束可以保障数据表的准确性和可靠性。

一共有以下约束:

img

3.2.3 创建表
void MainWindow::createTable()
{
    QSqlQuery query;
    QString str = QString("CREATE TABLE student ("
                          "id INT PRIMARY KEY NOT NULL,"
                          "name TEXT NOT NULL,"
                          "Mathscore REAL NOT NULL,"
                          "Englishscore REAL NOT NULL,"
                          "Cscore REAL NOT NULL,"
                          "CAscore REAL NOT NULL,"
                          "Averagescore REAL NOT NULL)");

    //判断是否操作成功
    if(query.exec(str) == false){
        ui->textEdit->setText("打开数据库成功");
    }else{
        ui->textEdit->setText("创建数据库成功");
    }
}
3.3 显示表(queryTable)
3.3.1 功能概述

Qt中使用了自己的机制来避免使用SQL语句,为开发者提供了更简单的数据库操作及数据显示模型,分别是只读的QSqlQueryModel,操作单表的QSqlTableModel以及可以支持外键的QSqlRelationalTableModel。

3.3.2 显示表
 void MainWindow::queryTable(){
     QSqlQueryModel *model = new QSqlQueryModel(this);
     model->setQuery("select * from student");
     ui->tableView->setModel(model);
 }

4.槽函数(clicked)

这部分代码很简单,我们结合实际代码进行说明即可。

4.1 插入(insertButton)
void MainWindow::on_insertButton_clicked()
{
    QSqlQuery query;

    //判断输入是否正确
    int id = ui->idEdit->text().toInt();
    if(id == 0)
    {
        QMessageBox::critical(this,"ERROR","ID输入错误");
        return;
    }
    QString name = ui->nameEdit->text();
    if(name == "")
    {
        QMessageBox::critical(this,"ERROR","姓名输入错误");
        return;
    }
    double Mathscore = ui->MscoreEdit->text().toDouble();
    if(Mathscore < 0 || Mathscore >100)
    {
        QMessageBox::critical(this,"ERROR","数学成绩输入错误");
        return;
    }
    double Englishscore = ui->EscoreEdit->text().toDouble();
    if(Englishscore < 0 || Englishscore >100)
    {
        QMessageBox::critical(this,"ERROR","英语成绩输入错误");
        return;
    }
    double Cscore = ui->CscoreEdit->text().toDouble();
    if(Cscore < 0 || Cscore >100)
    {
        QMessageBox::critical(this,"ERROR","C语言成绩输入错误");
        return;
    }
    double CAscore = ui->CAscoreEdit->text().toDouble();
    if(CAscore < 0 || CAscore >100)
    {
        QMessageBox::critical(this,"ERROR","电路成绩输入错误");
        return;
    }
    //计算平均分
    double Averagescore = (Mathscore+Englishscore+Cscore+CAscore)/4;

    //插入数据
    QString str = QString("INSERT INTO student "
                          "VALUES(%1,'%2',%3,%4,%5,%6,%7)")
                      .arg(id).arg(name).arg(Mathscore).arg(Englishscore).arg(Cscore).arg(CAscore).arg(Averagescore);

    //判断是否操作成功
    if(query.exec(str) == false){
        ui->textEdit->setText(str);
        ui->textEdit->setText("插入数据失败");
    }else{
        queryTable();
        ui->textEdit->setText("插入数据成功");
    }
}

首先我们对信息进行读取:

int id = ui->idEdit->text().toInt();
QString name = ui->nameEdit->text();
double Mathscore = ui->MscoreEdit->text().toDouble();

......

然后我们对信息是否正确进行判断,如果不正确则调用QMessageBox进行弹窗提示:

    if(id == 0)
    {
        QMessageBox::critical(this,"ERROR","ID输入错误");
        return;
    }

    if(name == "")
    {
        QMessageBox::critical(this,"ERROR","姓名输入错误");
        return;
    }

    if(Mathscore < 0 || Mathscore >100)
    {
        QMessageBox::critical(this,"ERROR","数学成绩输入错误");
        return;
    }
......

然后我们进行数据的插入:

数据插入的标准格式为:

INSERT INTO 表名[(列1,列2,...)] VALUES(值1,值2,...)

所以我们进行编写:

    //插入数据
    QString str = QString("INSERT INTO student "
                          "VALUES(%1,'%2',%3,%4,%5,%6,%7)")
                      .arg(id).arg(name).arg(Mathscore).arg(Englishscore).arg(Cscore).arg(CAscore).arg(Averagescore);

最后对数据是否操作成功进行判断即可。

4.2 删除(deleteButton)
void MainWindow::on_deleteButton_clicked()
{
    QSqlQuery query;
    int id = ui->idEdit->text().toInt();
    QString str = QString("DELETE FROM student WHERE id = %1").arg(id);

    //弹窗确认操作
    if(QMessageBox::question(this,"DELETE","是否确定删除?",
                              QMessageBox::Yes|QMessageBox::No) == QMessageBox::No){
        return;
    }

    //判断操作是否成功
    if(query.exec(str) == false){
        ui->textEdit->setText(str);
        ui->textEdit->setText("删除操作失败");
    }else
    {
        ui->textEdit->setText("删除操作成功");
        queryTable();
    }
}

删除数据的语法格式如下:

DELETE FROM 表名 [WHERE 删除条件(s)]

需要注意的是,如果不写WHERE子句,代表删除所有数据!

这个小知识在我们的5.3 全部删除(Clear)中有所使用。

所以我们编写函数:

int id = ui->idEdit->text().toInt();
QString str = QString("DELETE FROM student WHERE id = %1").arg(id);

然后就是老生常谈的弹窗确认外加判断操作是否成功。

4.3 查询(getButton)
void MainWindow::on_getButton_clicked()
{
    int id = ui->idEdit->text().toInt();
    QSqlQueryModel *model = new QSqlQueryModel(this);
    QString str = QString("SELECT * FROM student "
                          "WHERE ID = %1").arg(id);
    model->setQuery(str);
    ui->tableView->setModel(model);
}

查询的语法格式如下:

SELECT [列名],[列名]... FROM [表名][WHERE 删除条件(s)];

在这里我们编写函数:

    QString str = QString("SELECT * FROM student " "WHERE ID = %1").arg(id);

利用**“*”**达到了一种模糊搜索。

4.4 排序(sortButton)
void MainWindow::on_sortButton_clicked()
{
    //获取排序列名
    QString value = ui->valueComBox->currentText();

    //获取排序方式
    QString condition;
    if(ui->condcomBox->currentIndex() == 0){
        condition = "ASC";//升序
    }else{
        condition = "DESC";//降序
    }

    QString str = QString("SELECT * FROM student ORDER BY %1 %2").arg(value).arg(condition);

    //查询和显示
    QSqlQueryModel *model = new QSqlQueryModel(this);
    model->setQuery(str);
    ui->tableView->setModel(model);
}

排序语法格式如下:

img

两种排序方式:

  • 升序ASC
  • 降序DESC

我们利用从valueComBox中得到的排序条件和从condcomBox得到的升降序条件来进行排序按键程序的编写:

QString str = QString("SELECT * FROM student ORDER BY %1 %2").arg(value).arg(condition);

5.工具栏(triggered)

5.1 导入(Open)
void MainWindow::on_actionOpen_triggered()
{

    QString buildDirPath = QCoreApplication::applicationDirPath(); // 获取应用程序的目录路径
    buildDirPath += "/../"; // 移动到上一级目录,即项目目录

    QString filePath = QFileDialog::getOpenFileName(this, "Open File Dialog", "/", "Database files (*.db)");
    if (filePath.isEmpty()) {
        return; // 用户取消操作
    }

    // 构造旧文件的完整路径
    QString oldFilePath = buildDirPath + "student.db";

    // 确保旧文件存在
    if (!QFile::exists(oldFilePath)) {
        ui->textEdit->setText("The old file does not exist.");
        return;
    }

    // 打开新旧文件
    QFile newFile(filePath);
    QFile oldFile(oldFilePath);

    if (!newFile.open(QIODevice::ReadOnly) || !oldFile.open(QIODevice::WriteOnly)) {
        ui->textEdit->setText("Failed to open files.");
        return;
    }

    // 复制内容
    QByteArray buffer;
    qint64 bytesWritten = 0;
    while (!newFile.atEnd()) {
        buffer = newFile.read(1024); // 每次读取1024字节
        bytesWritten += oldFile.write(buffer);
    }

    // 关闭文件
    newFile.close();
    oldFile.close();

    // 检查是否所有内容都被复制
    if (bytesWritten != newFile.size()) {
        ui->textEdit->setText("Failed to copy all data.");
    } else {
        ui->textEdit->setText("Data copied successfully.");
    }

    // 更新textEdit控件
    ui->textEdit->setText(oldFilePath);

}

在这里我们需要声明几点:

  1. 首先,导入的必须是.db的文件
  2. 其次,导入的.db文件中必须与我们的table具有相同的格式

我们在这里做一个小演示:

在这里插入图片描述

随后点击Open,即左上角的文件夹图标,选择目录到…\ht\build\Desktop_Qt_6_5_3_MinGW_64_bit-Debug

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

这里的student.db是我们正在展示的数据表,而里面的student-副本.db是我之前使用的另一个数据表,在这里我们直接打开副本即可。

然后点击About/排序键。

在这里插入图片描述

我们看见数据已经刷新,右下角显示数据库来源(打码是因为在使用时涉及了真实人名)。

我们可以通过前文所提的软件对student.db文件进行查看,发现果然是对副本文件内的内容进行了一次copy。

在这里插入图片描述

5.2 保存(Save)

由于我们使用的数据表已经做到了实时增删查改,所以保存键对我们可有可无,在这里我特意将其保留,反正也没什么用。

void MainWindow::on_actionSave_triggered()
{
    QMessageBox::critical(this,"ERROR","其实我会帮你保存的xixi");
}
5.3 全部删除(Clear)
void MainWindow::on_actionClear_triggered()
{
    QSqlQuery query;
    int id = ui->idEdit->text().toInt();
    QString str = QString("DELETE FROM student").arg(id);

    //弹窗确定
    if(QMessageBox::question(this,"DELETE","是否确定全部删除?",
                              QMessageBox::Yes|QMessageBox::No) == QMessageBox::No){
        return;
    }

    //判断是否操作成功
    if(query.exec(str) == false){
        ui->textEdit->setText(str);
        ui->textEdit->setText("全部删除操作失败");
    }else
    {
        ui->textEdit->setText("全部删除操作成功");
        queryTable();
    }
}

前面我们已经说过了,当WHERE条件为空时代表删除所有数据,所以这里我们直接在deleteButton的基础上进行改动即可。

5.4 显示(About)

此键用于展示作者信息。

void MainWindow::on_actionAbout_triggered()
{
	on_sortButton_clicked();

    // 创建一个QMessageBox对象,设置窗口标题和消息
    QMessageBox aboutBox;
    aboutBox.setWindowTitle("关于");
    aboutBox.setText("学生管理系统");

    // 添加作者和ID信息
    QString aboutText = QString("Author: xx\nID: xxxxxxxxx");
    aboutBox.setDetailedText(aboutText);

    // 设置图标,这里使用信息图标作为示例
    aboutBox.setIcon(QMessageBox::Information);

    // 执行弹窗并等待用户操作
    aboutBox.exec();
}

在这里插入图片描述

在这里插入图片描述

三.By the way

gitee: Htzsl (htzsl) - Gitee.com

csdn: Squirrel-Htzsl-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Squirrel-Htzsl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值