《操作系统实践-基于Linux应用与内核编程》第8章-Qt实验-学生管理系统

前言:

内容参考《操作系统实践-基于Linux应用与内核编程》一书的示例代码和教材内容,所做的读书笔记。本文记录再这里按照书中示例做一遍代码编程实践加深对操作系统的理解。

引用:

《操作系统实践-基于Linux应用与内核编程》

作者:房胜、李旭健、黄玲、李哲

出版社:清华大学出版社

资源:

 教材资源

链接: https://caiyun.139.com/m/i?1A5Ch36dl1whD  提取码:jdQe

课件和电子资料源码

链接: https://caiyun.139.com/m/i?1A5CvEKY07Uzs  提取码:xyv0

参考链接:

本文参考和引用了如下参考链接中博文的大量内容,对照者链接引用文章的步骤做了实验测试,主要目的是通过实验加深对Qt 界面设计器设计GUI开发程序的理解。

Qt教程—学生管理系统(文件) - 知乎

Qt学习之路---学生成绩管理系统_使用qt框架创建学生成绩录入界面-CSDN博客

正文

一,项目设计

1、需求分析

记录并处理学生成绩信息。

  • 1)添加新的学生数据;
  • 2)根据学号对已有的学生数据进行修改;
  • 3)根据学号删除已存在的学生信息;
  • 4)根据学号查询学生信息;
  • 5)根据各门成绩与平均成绩进行排序。
2、窗口设计
  • 1)菜单窗口;
  • 2)添加学生窗口;
  • 3)修改信息窗口(包括删除信息);
  • 4)查询学生窗口
  • 5)排序窗口;
3、数据结构设计

以一个类StudentInfo储存单个学生信息,学生类中包括:
姓名(字符串)
学号(整型)
数学成绩(整型)
英语成绩(整型)
C语言程序设计成绩(整型)
平均成绩(双浮点数)

二,项目制作

1. 建立项目

打开Qt Creator,“新建项目”,“其它项目”,“空的Qt项目(Empty qmake Project)”,

2. 建立窗口

将其命名为 StudentManage,单击下一步,知道结束。创建了一个空的Qt StuengManage 学生管理项目工程,此时该项目还没有任何文件。接下来会为“学生管理系统”项目添加需要的文件。

点击项目名称,“Add New”,“Qt”,“Qt界面设计类”,模版选择"widget",点击下一步,当前创建是菜单窗口所以把文件命名为"MenuWidget"。

以同样的方式建立添加如下的窗口Widget,最终的“学生管理成绩” Qt 项目文件如下图

  • 学生窗口:AddStudentWidget
  • 修改信息窗口:ModifyWidget
  • 查询窗口:SelectWidget
  • 排序窗口:SortWidget。

我们可以看到Qt Creator 建立基类为 Widget 的设计师界面就是建立一个C++类(继承自Widget)及与其对应的ui文件,这个ui文件便是 Qt Designer 设计文件,它会在编译时生成一个 ui_xxx.h 文件,这样我们就可以以C++的方式对其进行调用。

之后打开我们的"menuwidget.h"文件,看到MenuWidget 文件中有错误语法提示,这是因为我们还没有链接到 Qt Widgets 库。

在 stuentManSystem.pro 文件中,加上如下一行,就可以解决问题。

QT += widgets

3. 实现窗口之间的互动

现在,开始实现新建立的几个窗口之间的切换问题,这里使用 QStackedLayout 实现窗口切换。

QStackedLayout 继承自 QLayouot,提供了多页切换的布局,一次只能看到一个界面,在我们的Qt5-从零开始的Hello World 教程(Qt Creator)中提到过,大部分控件都继承自 QFrame,而QFrame又继承自 QWidget,所有 QStackedLayout 完全可以实现窗口之间的切换。

我们用上一步相同的方法创建一个窗口 MainWidget。并添加一个 main.cpp 来写 main 函数。

添加 MainWidget

添加 mian.cpp 

修改main.cpp文件

//main.cpp
#include <QApplication>
#include "mainwidget.h"

int main(int argc, char *argv[]){
    QApplication app(argc, argv);

    mainWidget w;
    w.show();

    return app.exec();
}

在 mainwidget.h 中修改 MainWidget 类的定义,为其添加成员。这里添加为 public 类成员。

    MenuWidget *menuwidget;             //菜单窗口
    AddStuentWidget *addstuentwidget;   //添加学生窗口
    SelectWidget *selectwidget;         //查询窗口
    ModifyWdiget *modifywidget;         //修改窗口
    SortWidget *sortwidget;             //排序窗口
    QStackedLayout *stackedlayout;      //QStackedLayout布局

当然也要修改对应的头文件

#include <QStackedLayout>
#include "menuwidget.h"
#include "addstuentwidget.h"
#include "modifywdiget.h"
#include "sortwidget.h"
#include "selectwidget.h"

在 mainWidget.cpp 中将 MainWidget 设置为 stackayout 布局,声明我们需要的窗口,并将其假如到 stacklayout 布局中去。

在 MainWidget.cpp 中显式调用 MainWidget 构造函数。

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

在此处添加

MainWidget::MainWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    //add by dimon 2024-03-04 18:24
    menuwidget = new MenuWidget;
    addstuentwidget = new AddStuentWidget;
    selectwidget = new SelectWidget;
    modifywidget = new ModifyWdiget;
    sortwidget = new SortWidget;
    stackedlayout = new QStackedLayout;

    //把页面添加到 stackedlayout
    stackedlayout->addWidget(menuwidget);
    stackedlayout->addWidget(addstuentwidget);
    stackedlayout->addWidget(selectwidget);
    stackedlayout->addWidget(modifywidget);
    stackedlayout->addWidget(sortwidget);

    //设置布局 layout
    setLayout(stackedlayout);

    //连接 信号和槽 ,当点击相应按钮发出信号时,跳转到对应的页面
    connect(menuwidget, &MenuWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(addstudentwidget, &AddStuentWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(selectwidget, &SelectWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(modifywidget, &ModifyWdiget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(sortwidget, &SortWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);

}

之后就要使用 Qt Designer 设计页面了(当然在对应类中手动添加成员控件也没有问题)。

双击 menuwidget.ui 打开设计界面,在mwenuwidget中添加如下按钮(push button)。

以同样的方法在 addstudengwidget, selectwidget, modifywidget, sortwidget 中都添加一个返回按钮 returnButton。

为这些按钮设计点击槽函数。

// menuwidget.h
private slots:
    void on_addButton_clicked();
    void on_slectButton_clicked();
    void on_modifyButton_clicked();
    void on_sortButton_clicked();
    void on_exitButton_clicked();

还需要一个方法作为 stacklayout 切换页面的信号

// menuwidget.h
signals:
    void display(int number);

在 menuwidget.cpp 中给出槽函数的定义

//menuwidget.cpp
void MenuWidget::on_addButton_clicked(){
    emit display(1);
}

void MenuWidget::on_selectButton_clicked(){
    emit display(2);
}

void MenuWidget::on_modifyButton_clicked(){
    emit display(3);
}

void MenuWidget::on_sortButton_clicked(){
    emit display(4);
}

void MenuWidget::on_exitButton_clicked(){
    QApplication::exit();
}

emit 把信号和槽进行关联,emit 某个信号,就相当于调用了这个信号 connect 时所关联的槽函数。至于更多的emit信号,可以搜索或查看帮助文档。

之后为 addstudengwidget, selectwidget, modifywidget, sortwidget 窗口中的按钮设计信号与槽函数。

在 类名.h 中添加

signals:
    void display(int number);

private slots:
    void on_returnButton_clicked();

在  类名.cpp 中添加3. 实现窗口之间的互动

void 类名::on_returnButton_clicked(){
    emit display(0);
}

现在可以使用的只有退出按钮,跳转按钮还需要在mainwidget.cpp中用connect函数连接。

    //mainwidget.cpp

    //连接 信号和槽 ,当点击相应按钮发出信号时,跳转到对应的页面
    connect(menuwidget, &MenuWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(addstudentwidget, &AddStuentWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(selectwidget, &SelectWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(modifywidget, &ModifyWdiget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
    connect(sortwidget, &SortWidget::display, stackedlayout, &QStackedLayout::setCurrentIndex);
 4. 完善窗口设计
a) AddStudengWidget

我们需要提示标签来指明输入的数据,页数要输入框来接收用户的输入,QLable和QLineEdit可以满足我们的要求。

QLable,QLineEdit有方法 SetText(“内容”)来改变其显示的文字,有方法 setGeometry(起始恒横坐标,起始纵坐标,宽,高)来设置左上角起始位置与大小。

当然这些都可以在 Qt Designer 中直接设置。打开 addstudentwidget.ui 。

根据之前设计的数据结构,需要 nameLineEdit,idLineEdit,mathLineEdit,enLineEdit,cLineEdit 五个 QLineEdit 来接收学生的姓名,学号,数学成绩,英语成绩,C语言成绩(平均成绩有计算得出),还需要 nameLable,idLabel, mathLabel,enLable,cLable 五个 QLable 提醒用户输入数据,需要 addButton 一个 QPushButton来添加学生。

最终将 addstuentwidget 页面设计为

b) modifyWidget

我们需要 nameLineEdit,idLineEdit,mathLineEdit,enLineEdit,cLineEdit 五个 QLineEdit 接收学生的姓名,学号,数学成绩,英语成绩,C语言成绩,需要 nameLabel,idLable,mathLable,enLable,cLable五个 QLable 提醒用户输入数据,需要deleteButton,modifyButton 两个 QPushButton 来根据学号删除学生,和根据学号修改学生成绩信息。

c) selectWidget

我们需要 idLable 一个 QLable 提醒用书输入数据,需要 idLineEdit 一个 QLineEdit 接收学生的学号,之后需要 nameLabel,avgLable,mathLable,enLable,cLable 五个 QLabel提醒用户显示的数据,需要 showNameLabel,showMathLable,showEnLabel,showCLable,showAvgLable 五个QLabel来接收查询到的数据,需要 selectButton 一个 QPushButon 来提交查询。

d) SortWidget

QRadioButton 单选框可以解决我们排序根据选择问题。(当然,很多方法都可以,这里只演示QRadioButton)。

QTableWidget表格可以用来显示排序后的信息。

我们需要 mathRadioButton,enRadioButton,cRadioButton,avgRadioButton 四个 QRadioButton来选择排序根据,需要 sortButton 一个QPushButton来提交排序,需要 tableWidget 一个 QTableWidget 来宣示排序结果。

5. 完成学生类的设计

之前在数据结构设计中我们已经设计好了,一个studentInfo存储单个学生信息,学生类中包括:

  • 姓名(字符串)
  • 学号(整型)
  • 数学成绩(整型)
  • 英语成绩(整型)
  • C语言程序设计成绩(整型)
  • 平均成绩(双浮点数)

现在动手去实现它。右击项目,Add New,选择 C++,C++ Class,为它起名为 StudentInfo 之后,下一步,完成。在 studentinfo.h 为其创建对应的私有变量,及对应的 get 和 set 函数。

//studentinfo.h
#include <QString>

class StudentInfo
{
private:
    QString name;
    int id, math, english, languageC;
    double avg;

public:
    StudentInfo();
    StudentInfo(QString tname, int tid, int tmath, int tenglish, int tlanguageC){
        name = tname;
        id = tid;
        math = tmath;
        english = tenglish;
        languageC = tlanguageC;
        avg = (tmath + tenglish + tlanguageC)/3.0;
    }

    int getId(){
        return id;
    }

    QString getName(){
        return name;
    }

    int getMath(){
        return math;
    }

    int getEnglisht()
    {
        return english;
    }

    int getLanguageC()
    {
        return languageC;
    }

    int getAvg(){
        return avg;
    }

    void setId(int tid){
        id = tid;
    }

    void setName(QString tname){
        name = tname;
    }

    void setMath(int tmath){
        math = tmath;
    }

    void setEnglish(int tenglish){
        english = tenglish;
    }

    void setLanguageC(int tlanguageC){
        languageC = tlanguageC;
        avg = (math + english + languageC)/3.0;
    }
};
6. 完善添加学生信息

打开 addstudentwidget.h 为“添加”按钮设计点击槽函数,用于我们设计用文件对学生信息进行存储,所以需要引用 QFile,这里我们使用对话框来提示用户操作中的各种问题,所以需要引入 QMessageBox。

QMessageBox 中有很多类型的对话框,各种对话框的用法这里就不详细介绍了,这里我们只介绍我们即将使用的 QMessageBox:about

QMessageBox::about(NULL, "About", "About this application");

其中3个参数分别对应:父窗口对象,对话框标题,对话框内容。

在 addstudentwidget.cpp 中给给出函数的定义:

  • 在 lineEdit 中取出用户输入的数据,lineEdit 拥有方法test()方法,会返回一个 QString,而QString中又拥有 toInt(),toDouble()等各种类型转换函数,可以适应我们的大多数需求。
  • 打开数据文件,将我们刚刚获取数据追加在文件的尾部

addsudentwidget.h

#include "addstuentwidget.h"
#include "ui_addstuentwidget.h"

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

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

void AddStuentWidget::on_returnButton_clicked() //“主菜单”按钮代年级
{
    emit display(0);
}

void AddStuentWidget::on_addButton_clicked()    //“添加”按钮点击
{
    // 将用户输入的姓名从nameLineEdit中取出
    QString name = ui->nameLineEdit->text();
    //将用户输入的学号从idLineEdit中取出,并转为整型
    int id = ui->idLineEdit->text().toInt();
    //将用户输入数学成绩从mathLineEdit中取出,并转为整型
    int math = ui->mathLineEdit->text().toInt();
    int english = ui->enLineEdit->text().toInt();
    int languageC = ui->cLineEdit->text().toInt();
    if(ui->nameLineEdit->text() == "" ||
            ui->mathLineEdit->text() == "" ||
            ui->enLineEdit->text() == "" ||
            ui->cLineEdit->text() == "")
    {
        //插入的数据不能为空,否则在读取文件时会出现问题
        QMessageBox::about(NULL, "反馈","存在空项");
        return;
    }
    //实例化一个QFile file对象为我们的数据文件student.txt
    QFile file("stuent.txt");
    //open()可以打开文件,这里QIODevice::WriteOnly代表将文件以只写方式打开
    //QIODevice::Text代表打开的是文本文件,QIODevice::Text会对end-of-line 结束符进行转译
    //QIODevice::Append以追加的方式打开,新增内容将会被追加到文件末尾
    file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Append);
    if(!file.isOpen()){ //如果文件没有打开成功,弹出对话框提示用户
        QMessageBox::about(NULL, "反馈", "数据文件打开ia失败");
        return;
    }
    //QTextStream可以进行一些节本的文本读写,比如 QString , int, char 之类的数据;
    //QDataStream 可以进行如QMap,QPoint之类数据的读写
    QTextStream out(&file);
    //将我们刚刚获取到的数据写入文件
    out<<name<<" " << id << " " << math << " " << english << " " << languageC;
    file.close();
    QMessageBox::about(NULL, "反馈", "插入成功");
    //将用户输入数据清空
    ui->nameLineEdit->clear();
    ui->idLineEdit->clear();
    ui->mathLineEdit->clear();
    ui->cLineEdit->clear();
}

运行一下

显示插入成功,打开项目所在的目录 build-studentManageSysteem开头的目录,我们的数据文件会出现在这里。

打开看一看

这样我们的添加信息模块就完成了。

7. 完善信息

打开 modifywidget.h 为“删除”和“修改”按钮设计点击槽函数,在modifywidget.cpp中给出函数定义。

对于删除和修改操作,我们这里打算以文件中数据建立一个数据类型为 StudengInfo 的 QVector 容器,容器中盛放全体学生的成绩。对容器进行修改删除操作,最后以容器中的数据覆盖掉原有的数据即可。

modifywidget.h

#ifndef MODIFYWDIGET_H
#define MODIFYWDIGET_H

#include <QWidget>

namespace Ui {
class ModifyWdiget;
}

class ModifyWdiget : public QWidget
{
    Q_OBJECT

public:
    explicit ModifyWdiget(QWidget *parent = nullptr);
    ~ModifyWdiget();

signals:
    void display(int number);

private slots:
    void on_returnButton_clicked();     //点击主菜单按钮

    void on_deleteButton_clicked();     //点击删除按钮

    void on_modifyButton_clicked();     //点击修改按钮

private:
    Ui::ModifyWdiget *ui;
};

#endif // MODIFYWDIGET_H

modifywidget.cpp

#include "modifywdiget.h"
#include "ui_modifywdiget.h"
#include "studentinfo.h"
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QtDebug>

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

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

void ModifyWdiget::on_returnButton_clicked()
{
    emit display(0);
}


void ModifyWdiget::on_deleteButton_clicked()
{
    QVector<StudentInfo> allStudengInfo; //数据类型为StudengInfo的QVector容器
    if(ui->idLineEdit->text() == ""){//如果id输入栏为空则提示错误并返回
        QMessageBox::about(NULL, "反馈", "id不得为空");
        return;
    }
    QFile file("student.txt");
    file.open(QIODevice::ReadOnly|QIODevice::Text);//以只读方式打开文本文件
    if(!file.isOpen()){ //如果文件没有打开弹出错误信息提示并返回
        QMessageBox::about(NULL, "反馈", "student.txt文件打开失败");
        return;
    }

    //QIODevice::Truncate在写入时会从文件开始处写入,覆盖原有内容
    QTextStream inp(&file); //以file建立一个QT的文本流
    while(!inp.atEnd()){
        QString name;
        int id, math, english, languageC;
        //读入姓名 学号 数学成绩 英语成绩 C语言成绩
        inp>> name >> id >> math >> english >> languageC;
        //调用之前建立的构造函数实例化一个 StudentInfo对象,并将其加入到allStudentInfo
        allStudengInfo.push_back(StudentInfo(name,id,math,english,languageC));
    }
    allStudengInfo.pop_back(); //文件最会会多读入一个无用数据,将其弹出
    file.close();
    //获取用户输入的id
    int id = ui->idLineEdit->text().toInt();
    //记录是否进行过删除
    bool flag = false;
    for(QVector<StudentInfo>::iterator it = allStudengInfo.begin(); it != allStudengInfo.end(); it++){
        if(it->getId() == id){
            allStudengInfo.erase(it);
            flag = true;
        }
    }
    if(flag){ //如果进行过删除,弹出对话框并更新文件
        QMessageBox::about(NULL, "反馈", "删除成功");
        //以只写覆盖的方式打开文本文件
        file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate);
        if(!file.isOpen()){//如果文件没有打开弹出错误信息提示并返回
            QMessageBox::about(NULL,"反馈","数据文件打开失败");
            return;
        }
        QTextStream out(&file); //以file创建一个QT文本流
        for(auto i:allStudengInfo){
            out<<i.getName()<<" "<<i.getId()<<" "<<i.getMath()<<" "<<i.getEnglisht()<<" "<<i.getLanguageC()<<endl;
        }
        file.close();
    }
    else{
        //如果没有删除,弹出不存在对话框
        QMessageBox::about(NULL,"反馈","id不存在");
    }
    //关闭文件
    //清空id输入框
    ui->idLineEdit->clear();


}

void ModifyWdiget::on_modifyButton_clicked()
{
    if(ui->nameLineEdit->text()=="" || ui->idLineEdit->text()=="" || ui->mathLineEdit->text()=="" ||
            ui->enLineEdit->text()=="" || ui->cLineEdit->text()==""){
        QMessageBox::about(NULL, "反馈","存在空项");
        return;
    }
    QVector<StudentInfo> allStudentInfo; //数据类型为StudentInfo的QVector容器
    QFile file("student.txt");
    //以只读方式打开文本文件
    file.open(QIODevice::ReadOnly|QIODevice::Text);
    if(!file.isOpen()){//数据文件如果打开失败,弹出信息提示用户并返回
        QMessageBox::about(NULL,"反馈","数据文件打开失败");
        return;
    }

    qDebug()<<"deubg modify button" <<endl;

    //以file建立一个QT文本流
    QTextStream inp(&file);
    while(!inp.atEnd()){
        QString name;
        int id, math, english, languageC;
        //读入姓名 学号 数学成绩 英语成绩 C语言成绩
        inp>>name >> id >> math >> english >> languageC;
        //调用之前创建的构造函数实例化一个StudentInfo对象并将其加入allStudentInfo容器
        allStudentInfo.push_back(StudentInfo(name,id,math,english,languageC));

        qDebug()<<"name" << name << id << math << english << languageC<<endl;
    }
    allStudentInfo.pop_back(); //文件最后会多一个无用数据,将其弹出
    file.close();

    //获取用户输入的id
    int id = ui->idLineEdit->text().toInt();
    QString name = ui->nameLineEdit->text();
    int math = ui->mathLineEdit->text().toInt();
    int english = ui->enLineEdit->text().toInt();
    int languageC = ui->cLineEdit->text().toInt();

    //记录是否进行过删除
    bool flag = false;
    for(QVector<StudentInfo>::iterator it = allStudentInfo.begin(); it!= allStudentInfo.end(); it++){
        qDebug()<<"name" << it->getName() << it->getId() <<endl;

        //使用迭代器遍历allStudengInfo
        if(it->getId() == id){
            it->setName(name);
            it->setId(id);
            it->setMath(math);
            it->setEnglish(english);
            it->setLanguageC(languageC);
            flag = true;
        }
    }
    if(flag){ //如果进行过删除,弹出对话框并更新文件
        QMessageBox::about(NULL,"反馈","修改成功");
        //QIODevice::Truncate在写入时会从文件开始处写入,覆盖原有内容
        //以只写覆盖方式打开文本文件
        file.open(QIODevice::WriteOnly|QIODevice::Text|QIODevice::Truncate);
        if(!file.isOpen()){
            QMessageBox::about(NULL,"反馈","数据文件打开失败");
            return;
        }
        //以file创建一个QT文本流
        QTextStream out(&file);
        for(auto i:allStudentInfo){
            out<<i.getName()<<" " << i.getId() <<" " <<i.getMath()<<" " <<i.getEnglisht()<<" " <<i.getLanguageC()<<endl;
        }
        file.close();
    }
    else{ //如果没有修改,弹出不存在对话框
        QMessageBox::about(NULL,"反馈","id不存在");
        return;
    }
    //清空所有输入框
    ui->idLineEdit->clear();
    ui->nameLineEdit->clear();
    ui->mathLineEdit->clear();
    ui->enLineEdit->clear();
    ui->cLineEdit->clear();

}

 

8.查询模块

打开selectwidget.h为“查询”和“修改”按钮设计点击槽函数,在selectwidget.cpp中给出函数定义。

查询可以在从文件读取是判断是否会读取到id为输入id的学生,也可以像修改一样将所有学生信息读取到数据类型为 StudengInfo 的 QVector 容器中,再从容器中查询数据,这里我选择读入容器的方法。

selectwidget.h

#ifndef SELECTWIDGET_H
#define SELECTWIDGET_H

#include <QWidget>

namespace Ui {
class SelectWidget;
}

class SelectWidget : public QWidget
{
    Q_OBJECT

public:
    explicit SelectWidget(QWidget *parent = nullptr);
    ~SelectWidget();

signals:
    void display(int number);

private slots:
    void on_returnButton_clicked();

    void on_selectButton_clicked();

private:
    Ui::SelectWidget *ui;
};

#endif // SELECTWIDGET_H

selectwidget.cpp

#include "selectwidget.h"
#include "ui_selectwidget.h"
#include <QTextStream>
#include <QFile>
#include <QtDebug>
#include <QMessageBox>
#include <QVector>
#include "studentinfo.h"

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

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

void SelectWidget::on_returnButton_clicked()
{
    emit display(0);
}

void SelectWidget::on_selectButton_clicked()
{
    if(ui->idLineEdit->text() == "")
    {
        QMessageBox::about(NULL,"反馈","id不能为空");
        return;
    }
    QFile file("student.txt");
    //以只读方式打开文本文件
    file.open(QIODevice::ReadOnly|QIODevice::Text);
    if(!file.isOpen()){
        QMessageBox::about(NULL,"反馈","数据文件打开失败");
        return;
    }
    //以file作为QT文本流
    QTextStream inp(&file);
    //数据类型为StudentInfo的QVector容器
    QVector<StudentInfo> allStudentInfo;
    while(!inp.atEnd()){ //读到文件结尾
        QString name;
        int id, math, english, languageC;
        inp >> name >> id >> math >> english >> languageC;
        //调用之前建立的构造函数实例化一个StudentInfo对象并将其加入allStudentInfo容器
        allStudentInfo.push_back(StudentInfo(name,id,math,english,languageC));
    }
    allStudentInfo.pop_back();//弹出最后的无用数据
    file.close();

    int id = ui->idLineEdit->text().toInt();
    bool flag = false;
    for(auto i:allStudentInfo){
        if(i.getId() == id){
            ui->showNameLable->setText(i.getName());
            ui->showMathLable->setText(QString::number(i.getMath()));
            ui->showEnLable->setText(QString::number(i.getEnglisht()));
            ui->showCLable->setText(QString::number(i.getLanguageC()));
            ui->showAvgLabel->setText(QString::number(i.getAvg()));
            flag = true;
            break;
        }
    }
    if(!flag){
        ui->showNameLable->setText("NULL");
        ui->showMathLable->setText("NULL");
        ui->showEnLable->setText("NULL");
        ui->showCLable->setText("NULL");
        ui->showAvgLabel->setText("NULL");
        QMessageBox::about(NULL,"反馈","id不存在");
        return;
    }
    //ui->idLineEdit->clear();//清空id输入
}

9.排序模块

老样子,将数据从文件中读入数据类型为 StudengInfo的 QVector 容器后进行排序就容易很多。

我们需要排序时只能根据数学,英语,C语言,平均成绩中的一种进行排序,所以我们要做到代表着四种排序方式的 QRadioButton 有且只有一个能被选中,我们可以将其假如一个 QButtonGroup,这样便可以实现这个需求,至于显示排序后的数据我们可以显示在表格控件 QTableWidget中。

QButtonGroup 我们用到了 addButton 按钮与 checkedId 获取选中按钮的 id 两个方法,其他方法读者可以搜索文档。

QTableWidget 我们用到了 setHorizontalHeaderLabels 设置水平表头标签 horizontalHeader()->setSectionResizeMode(QHeaderView::strech);根据总宽度调整列宽;setRowCount设置行数;setitem设置单元格,其它方法读者可以自行搜索。

sortwidget.h

#ifndef SORTWIDGET_H
#define SORTWIDGET_H

#include <QWidget>
#include <QButtonGroup>
#include <QVector>
#include <QFile>
#include <QDebug>
#include <QMessageBox>
#include "studentinfo.h"

namespace Ui {
class SortWidget;
}

class SortWidget : public QWidget
{
    Q_OBJECT

public:
    explicit SortWidget(QWidget *parent = nullptr);
    ~SortWidget();

signals:
    void display(int number);

private slots:
    void on_returnButton_clicked();

    void on_sortButton_clicked();

private:
    Ui::SortWidget *ui;
    QButtonGroup *sortButtonGroup;
};

#endif // SORTWIDGET_H

sortwidget.cpp

#include "sortwidget.h"
#include "ui_sortwidget.h"

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

    //add by dimon 2024-03-05 18:30
    //实例化QButtonGroup
    sortButtonGroup = new QButtonGroup();
    //将数学单选框加入到sourtButtonGroup并将其id设为0
    //不建议使用默认id,默认id是从 -2 开始依次递减的
    sortButtonGroup->addButton(ui->mathRadioButton,0);
    sortButtonGroup->addButton(ui->enRadioButton, 1);
    sortButtonGroup->addButton(ui->cRadioButton,2);
    sortButtonGroup->addButton(ui->avgRadioButton,3);
    //平均成绩默认选中
    ui->avgRadioButton->setChecked(true);

    //QTableWidget设置操作
    ui->tableWidget->setColumnCount(6);
    //QStringList用来记录表哥表头数据
    QStringList headerLabels;
    headerLabels << tr("姓名") << tr("学号") << tr("数学") << tr("英语") << tr("C语言") << tr("平均");
    //void setHorizontalHeaderLabels(const QStringList &labels) 设置水平表头标签
    ui->tableWidget->setHorizontalHeaderLabels(headerLabels);
    //设置根据总宽度调整列宽
    ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    //设置初始行数为1行
    ui->tableWidget->setRowCount(1);
}

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

void SortWidget::on_returnButton_clicked()
{
    emit display(0);
}



//成功返回true,失败返回false
bool getSutdentInfo(QVector<StudentInfo> &allStudentInfo){
    QFile file("student.txt");
    file.open(QIODevice::ReadOnly|QIODevice::Text);
    if(!file.isOpen()){//打开文件失败
        QMessageBox::about(NULL,"反馈","打开数据文件失败");
        return false;
    }
    //以file创建QT文本流
    QTextStream inp(&file);
    while(!inp.atEnd()){
        QString name;
        int id, math, english, languageC;
        inp >> name >> id >> math >> english >> languageC;
        //使用之前创建的构造函数实例化StudengInfo对象并加入allStudengInfo容器
        allStudentInfo.push_back(StudentInfo(name,id,math,english,languageC));
    }
    allStudentInfo.pop_back();//弹出最后的无用数据
    file.close();
    return true;
}

bool cmp_math(StudentInfo a, StudentInfo b){
    return a.getMath() > b.getMath();
}

bool cmp_english(StudentInfo a, StudentInfo b){
    return a.getEnglisht() > b.getEnglisht();
}

bool cmp_languageC(StudentInfo a, StudentInfo b){
    return a.getLanguageC() > b.getLanguageC();
}

bool cmp_avg(StudentInfo a, StudentInfo b){
    return a.getAvg() > b.getAvg();
}

void SortWidget::on_sortButton_clicked()
{
    //清空除表头外的所有数据
    //如果想清空表头可使用clear()
    ui->tableWidget->clearContents();
    //取得当前单选框选中id
    int sortTag = sortButtonGroup->checkedId();
    //创建数据类型为StudengInfo的QVector容器
    QVector<StudentInfo> allStudentInfo;
    //从文件中读取数据到allStudentInfo
    if(!getSutdentInfo(allStudentInfo)){
        return; //读取失败直接返回
    }
    if(allStudentInfo.empty()){//allStudengInfo中没有数据
        QMessageBox::about(NULL,"反馈","没有学生信息");
        return;
    }
    switch(sortTag){
        case 0: //sortTag ==0 根据数学成绩排序
            std::sort(allStudentInfo.begin(),allStudentInfo.end(),cmp_math);
        break;
        case 1: //sortTag==1 根据英语成绩排序
            std::sort(allStudentInfo.begin(),allStudentInfo.end(),cmp_english);
        break;
        case 2: //sortTag==2 根据C语言成绩排序
            std::sort(allStudentInfo.begin(),allStudentInfo.end(),cmp_languageC);
        break;
        case 3: //sortTag==3 根据平均成绩排序
            std::sort(allStudentInfo.begin(), allStudentInfo.end(),cmp_avg);
        break;
    }
    //将表格行书设为与学生数量相同
    //否则setItem添加单元格不会生效
    ui->tableWidget->setRowCount(allStudentInfo.size());
    for(int i=0; i<allStudentInfo.size(); i++){
        ui->tableWidget->setItem(i, 0, new QTableWidgetItem(allStudentInfo[i].getName()));
        ui->tableWidget->setItem(i, 1, new QTableWidgetItem(QString::number(allStudentInfo[i].getId())));
        ui->tableWidget->setItem(i, 2, new QTableWidgetItem(QString::number(allStudentInfo[i].getMath())));
        ui->tableWidget->setItem(i, 3, new QTableWidgetItem(QString::number(allStudentInfo[i].getEnglisht())));
        ui->tableWidget->setItem(i, 4, new QTableWidgetItem(QString::number(allStudentInfo[i].getLanguageC())));
        ui->tableWidget->setItem(i, 4, new QTableWidgetItem(QString::number((allStudentInfo[i].getAvg()))));
    }
}

  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值