语言程序设计-利用Qt5实现学生选课管理系统(超详细附思路和代码)

QT安装

  • QT安装与基本操作详细内容点这里

任务要求

  • 题目要求如下:

    • 该系统需创建和管理如下信息:
    1. 学生信息:学号、姓名、班级、电话、生日、住址、选课数据集
    2. 选课信息:课程编号、课程名称、学分、学期、教室、成绩。
    • 系统功能要求如下:
    1. 创建和管理学生信息的对象;
    2. 创建和管理选课信息的对象;
    3. 增加和删除学生;
    4. 针对特定学生增加和删除选课信息 ;
    5. 基本查询功能;
    6. 数据文件读写:文件中包含所有学生信息、每个学生的选课信息等数据;
    7. 基本信息显示:1)所有学生的信息显示;2)特定学生的选课信息;
    8. 可选功能提升:特定课程的选课学生显示、成绩排名等。

项目分析

系统设计

分析设计任务可以知道, ==每个学生要包括复数个课程信息,同时复数个学生组成学生表== 进行统一管理。

  • 创建四个类,分别是课程类、课程表类、学生类、学生表类,课程表类中为课程类的列表类,学生类的成员包括课程表类,学生表类为学生类的列表;
  • 因为要针对特定学生或特定课程进行操作,所以要针对不同的信息显示界面进行选择索引的储存;
  • 作为一个界面程序,要注意因为一些操作失误或对程序不熟悉而产生的程序崩溃,尽量避免bug的出现。

功能分析

根据题目要求,程序要完成以下功能:

  • 添加/删除学生信息;
  • 对特定的学生添加/删除课程信息;
  • 对学生信息/课程信息进行查询,并在查询后可进行修改或删除操作;
  • 数据读写:可直接读取/保存到数据库中,也可打开其他文件并另存为;
  • 可查找特定课程的选课学生的信息,并可对成绩进行排序;
  • 在操作错误时可以弹出对话框提醒。

设计思路

  • 完成课程类、课程队列类、学生类、学生队列类四个类的创建:课程表类中为课程类的列表类,学生类的成员包括课程表类,学生表类为学生类的列表,数据结构如下图:


  • 界面设计,尽量简洁美观:
    通过对界面进行不同层次的布局操作让界面控件大小可以随窗口大小改变而改变,同时添加对话框中有label控件提醒,避免空文本的出现

  • 四个类与界面进行对接,通过界面可对创建类进行操作:
    调用四个类中的成员函数,获取或修改类信息,同时用m_View_kind记录目前视图类型:==0显示学生信息,1显示选课信息,2显示从0表查询,3显示从1表中查询,4显示特定课程的选课学生==,在不同视图下可以进行相应的操作,而不能进行的操作,程序会进行提醒,避免bug的出现;

  • 不同视图的显示要及时对视图种类和选中列表的索引进行刷新:
    ==学生信息视图作为最底层视图,在这层视图时所用选中索引要进行刷新,学生信息视图作为主视图,课程信息视图作为副主视图,索引的刷新在这两个视图中进行==,结构如下图;

  • 在查询时要将查询结果的索引及时储存
    方便直接对查询结果进行操作,并注意推出查询要及时刷新,==其中学生信息查询结果中的索引放入indexlist中,课程信息查询结果中的索引放入indexlist1中==,可直接在查询结果视图中对成员对象进行操作;

  • 特定课程进行学生信息显示:
    通过对所有学生进行遍历操作进行查找,将结果索引进行储存显示,成绩排序运用QList中的qSort()函数直接对结构体中的某个属性进行排序;

  • 在操作失误时会有提醒对话框:
    创建一个提醒对话框,在进行可能会导致程序崩溃的操作时弹出制止;

文件与对象描述(代码)

课程类

文件:course.h\ .cpp//课程类:
c_ID//课程编号;c_Name//课程名称;credit//学分;term//学期;c_room//教室;grade//成绩

  • course.h
#include
#include
#include
#include
#include
#include 
#include
#include
#include 
#include

class Course
{
public:
    Course();
    virtual ~Course();
    Course& operator= (const Course & course);

    void SaveCourse(QTextStream &aStream); //往流文件中写入成绩
    void ReadCourse(QTextStream &aStream); //从流文件中读成绩

    QString c_ID;      //课程编号
    QString c_Name;    //课程名称
    float credit;      //学分
    QString term;      //学期
    QString c_room;    //教室
    float grade;       //成绩
};
  • course.cpp
#include "course.h"

Course::Course()
{
    c_ID="";
    c_Name="";
    credit=0;
    term="";
    c_room="";
    grade=0;
}

Course::~Course()
{

}

Course& Course::operator=(const Course &course)
{
    c_ID=course.c_ID;
    c_Name=course.c_Name;
    credit=course.credit;
    term=course.term;
    c_room=course.c_room;
    grade=course.grade;

    return *this;
}

void Course::SaveCourse(QTextStream &aStream)
{
    aStream<>c_ID;
    aStream>>c_Name;
    aStream>>credit;
    aStream>>term;
    aStream>>c_room;
    aStream>>grade;
}

课程表类

这里课程表和后面的学生表用==QT5中的Qlist< Data >数据类型==;
文件:courseinfotable.h\ .cpp//课程队列类:
m_course//课程类列表Qlist;c_num//课程数

  • courseinfotable.h
#include"course.h"

class CourseInfoTable
{
public:
    CourseInfoTable();
    CourseInfoTable& operator= (const CourseInfoTable & course);

    void SaveCourseInfoTable(QTextStream &aStream); //往流文件中写入成绩
    void ReadCourseInfoTable(QTextStream &aStream);

    void AddCourse(Course& course);           //添加课程到课程表中
    void DelCourse(int index);                //根据列表索引删除课程
    Course& GetCourse(int index);             //根据列表索引得到课程
    int CourseNum();                          //得到课表课程数量

    QList m_course;                   //课程列表
    int c_num;                                //课程数量

};
  • courseinfotable.cpp
#include "courseinfotable.h"

CourseInfoTable::CourseInfoTable()
{
    m_course={};
    c_num=0;
}

CourseInfoTable& CourseInfoTable::operator=(const CourseInfoTable &course)
{
    m_course=course.m_course;
    c_num=course.c_num;
    return *this;
}

int CourseInfoTable::CourseNum()
{
    c_num=m_course.size();
    return this->c_num;
}

void CourseInfoTable::SaveCourseInfoTable(QTextStream &aStream)
{
    int num=CourseNum();
    aStream<>c_num;
    for(int i=0;i

学生类

文件:student.h\ .cpp//学生类:
s_ID//学号;s_Name//姓名;s_class//班级;ph_number//电话;birthday//生日;adress//地址;s_courses//课程队列类CourseInfoTable

  • student.h
class Student
{
public:
    Student();
    Student& operator= (const Student& man);
    virtual ~Student();

    void SaveStudent(QTextStream &aStream);     //保存数据
    void ReadStudent(QTextStream &aStream);     //读取数据

    bool is_courses();     //判断是否选课

    QString s_ID;          //学号
    QString s_Name;        //姓名
    QString s_class;       //班级
    QString ph_number;     //电话
    QDate birthday;        //生日
    QString adress;       //地址
    CourseInfoTable s_courses; //课程队列类
};
  • student.cpp
#include "student.h"

Student::Student()
{
    s_ID="";
    s_Name="";
    s_class="";
    ph_number="";
    birthday=QDate();
    adress="";
    s_courses=CourseInfoTable();
}

Student::~Student()
{

}

Student& Student::operator=(const Student &man)
{
    s_ID=man.s_ID;
    s_Name=man.s_Name;
    s_class=man.s_class;
    ph_number=man.ph_number;
    birthday=man.birthday;
    adress=man.adress;
    s_courses=man.s_courses;
    return *this;
}

void Student::SaveStudent(QTextStream &aStream)
{
    aStream<>s_ID;
    aStream>>s_Name;
    aStream>>s_class;
    aStream>>ph_number;
    aStream>>year;
    aStream>>month;
    aStream>>day;
    aStream>>adress;
    birthday.setDate(year,month,day);
    s_courses.ReadCourseInfoTable(aStream);
}

bool Student::is_courses()
{
    return s_courses.CourseNum()==0;
}

学生表类

文件:studentinfotable.h.cpp//学生队列类:
m_student//学生队列类QList;s_num//学生数量

  • studentinfotable.h
class StudentInfoTable
{
public:
    StudentInfoTable();
    StudentInfoTable& operator= (const StudentInfoTable & student);

    void SaveStudentInfoTable(QTextStream &aStream); //往流文件中写入数据
    void ReadCourseInfoTable(QTextStream &aStream); //从流文件中读取数据

    void AddStudent(Student& student);           //添加学生添加到学生表中
    void DelStudent(int index);                //根据列表索引删除学生
    Student& GetStudent(int index);             //根据列表索引得到学生
    int StudentNum();                          //得到学生数量

    QList m_student;  //学生表
    int s_num;   //学生数量
};
  • studentinfotable.cpp
#include "studentinfotable.h"

StudentInfoTable::StudentInfoTable()
{
   m_student=QList();
   s_num=0;
}

StudentInfoTable& StudentInfoTable::operator=(const StudentInfoTable &student)
{
    m_student=student.m_student;
    s_num=student.s_num;
    return *this;
}

void StudentInfoTable::SaveStudentInfoTable(QTextStream &aStream)
{
    int num=StudentNum();
    aStream<>s_num;

    for(int i=0;i

UI设计

创建方法:

  • 右击项目>>Add new>>Qt>>Qt设计师界面类


  • 可以选择各种不同类别的对话框和主界面


  • 创建成功后会自动生成.h .cpp和.ui文件,双击.ui文件即可对界面进行设计布局。

添加学生信息对话框

文件:inputdialog_s.h\ .cpp\ .ui//添加学生对话框类:
返回对话框中textEdit中的文本

  • inputdialog_s.ui界面设计

    ==注意==:
    • 在界面设计完后要对项目进行构建(点那个小锤子),这样在编辑.h和.cpp文件时在才会有我们添加的控件对象。
    • 选择任意一个控件右键会有转到槽的选项,比如在这个对话框中选择textEdit控件:
  • 比如我们选择textChange()函数,它就会出现在.h文件中,它表示当textEdit控件中文本发生变化时,该函数就会运行,其他槽函数可以自行查找官方文档

  • inputdialog_s.h(在创建后有一部分已经存在了,这里就直接贴过来啦

#include 
#include

namespace Ui {
class InputDialog_s;
}

class InputDialog_s : public QDialog
{
    Q_OBJECT

public:
    explicit InputDialog_s(QWidget *parent = nullptr);
    ~InputDialog_s();
    
    QString is_Error(); //
    void Show_error(const QString&tempstr);
    //得到文本编辑框中的文本内容,方便后面与主窗口对接
    QString Get_ID();
    QString Get_Name();
    QString Get_Class();
    QString Get_number();
    QDate Get_bir();
    QString Get_adress();
    
    void Label_Show();

private slots:
    void on_textEdit_selectionChanged();

    void on_textEdit_6_selectionChanged();

    void on_textEdit_2_selectionChanged();

    void on_textEdit_3_selectionChanged();

    void on_textEdit_4_selectionChanged();

    void on_dateEdit_editingFinished();

    void on_textEdit_textChanged();

    void on_textEdit_2_textChanged();

    void on_textEdit_3_textChanged();

    void on_textEdit_4_textChanged();

    void on_textEdit_6_textChanged();

private:
    Ui::InputDialog_s *ui;
};

  • inputdialog_s.cpp
#include "inputdialog_s.h"
#include "ui_inputdialog_s.h"

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

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

QString InputDialog_s::Get_ID()
{
    return ui->textEdit->toPlainText();
}

QString InputDialog_s::Get_Name()
{
    return ui->textEdit_2->toPlainText();
}

QString InputDialog_s::Get_Class()
{
    return ui->textEdit_3->toPlainText();
}

QString InputDialog_s::Get_number()
{
    return ui->textEdit_4->toPlainText();
}

QDate InputDialog_s::Get_bir()
{
    return ui->dateEdit->date();
}

QString InputDialog_s::Get_adress()
{
    return ui->textEdit_6->toPlainText();
}

QString InputDialog_s::is_Error()
{
    QString error;
    if(Get_ID().isEmpty())
    {
        error="学号";
        return error;
    }
    else if(Get_Name().isEmpty())
    {
        error="姓名";
        return error;
    }
    else if(Get_Class().isEmpty())
    {
        error="班级";
        return error;
    }
    else if(Get_number().isEmpty())
    {
        error="电话";
        return error;
    }
    else if(Get_adress().isEmpty())
    {
        error="地址";
        return error;
    }
    else
    {
        error="OK";
        return error;
    }
}

void InputDialog_s::Show_error(const QString &tempstr)
{
    ui->label_7->setText(tempstr);
    ui->label_7->setAlignment(Qt::AlignRight);
}

void InputDialog_s::Label_Show()
{
    QString error=is_Error();
    if(error=="OK")Show_error("点击OK即可添加!");
    else Show_error(QString("%1为空!请输入!!").arg(error));
}

void InputDialog_s::on_textEdit_selectionChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_6_selectionChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_2_selectionChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_3_selectionChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_4_selectionChanged()
{
    Label_Show();
}

void InputDialog_s::on_dateEdit_editingFinished()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_textChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_2_textChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_3_textChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_4_textChanged()
{
    Label_Show();
}

void InputDialog_s::on_textEdit_6_textChanged()
{
    Label_Show();
}
  • 运行效果如下:


添加选课信息对话框

  • 与添加学生信息相似

  • 文件:inputdialog_c.h\ .cpp\ .ui//添加课程对话框类:
    返回对话框中textEdit中的文本

  • inputdialog_c.ui界面设计


  • inputdialog_c.h

#include 

namespace Ui {
class InputDialog_c;
}

class InputDialog_c : public QDialog
{
    Q_OBJECT

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

    QString is_Error();      //错误类型
    void Show_error(const QString&tempstr);  //判断编辑框中内容是否为空
    
     //得到文本编辑框中的文本内容,方便后面与主窗口对接
    void Show_Label();
    QString Get_ID();
    QString Get_Name();
    float Get_Credit();
    QString Get_term();
    QString Get_room();
    float Get_grade();

private slots:
    void on_textEdit_selectionChanged();

    void on_textEdit_textChanged();

    void on_textEdit_2_selectionChanged();

    void on_textEdit_2_textChanged();

    void on_textEdit_3_selectionChanged();

    void on_textEdit_3_textChanged();

    void on_textEdit_4_selectionChanged();

    void on_textEdit_4_textChanged();

    void on_textEdit_5_selectionChanged();

    void on_textEdit_5_textChanged();

    void on_textEdit_6_textChanged();

    void on_textEdit_6_selectionChanged();

private:
    Ui::InputDialog_c *ui;
};
  • inputdialog_c.cpp
#include "inputdialog_c.h"
#include "ui_inputdialog_c.h"

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

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

QString InputDialog_c::Get_ID()
{
    return ui->textEdit->toPlainText();
}

QString InputDialog_c::Get_Name()
{
    return ui->textEdit_2->toPlainText();
}

float InputDialog_c::Get_Credit()
{
    return ui->textEdit_3->toPlainText().toFloat();
}

QString InputDialog_c::Get_term()
{
    return ui->textEdit_4->toPlainText();
}

QString InputDialog_c::Get_room()
{
    return ui->textEdit_5->toPlainText();
}

float InputDialog_c::Get_grade()
{
    return ui->textEdit_6->toPlainText().toFloat();
}

QString InputDialog_c::is_Error()
{
    QString error;
    if(Get_ID().isEmpty())
    {
        error="课程编号";
        return error;
    }
    else if(Get_Name().isEmpty())
    {
        error="课程名称";
        return error;
    }
    else if(ui->textEdit_3->toPlainText().isEmpty())
    {
        error="学分";
        return error;
    }
    else if(Get_term().isEmpty())
    {
        error="学期";
        return error;
    }
    else if(Get_room().isEmpty())
    {
        error="教室";
        return error;
    }
    else if(ui->textEdit_6->toPlainText().isEmpty())
    {
        error="成绩";
        return error;
    }
    else
    {
        error="OK";
        return error;
    }
}

void InputDialog_c::Show_error(const QString &tempstr)
{
    ui->label_7->setText(tempstr);
    ui->label_7->setAlignment(Qt::AlignRight);
}

void InputDialog_c::Show_Label()
{
    QString error=is_Error();
    if(error=="OK")Show_error("点击OK即可添加!");
    else Show_error(QString("%1为空!请输入!!").arg(error));
}

void InputDialog_c::on_textEdit_selectionChanged()
{
    Show_Label();
}


void InputDialog_c::on_textEdit_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_2_selectionChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_2_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_3_selectionChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_3_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_4_selectionChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_4_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_5_selectionChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_5_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_6_textChanged()
{
    Show_Label();
}

void InputDialog_c::on_textEdit_6_selectionChanged()
{
    Show_Label();
}

  • 运行效果如下:


信息查询对话框

==注意==:这里的查询对话框只是得到查询信息的关键词,真正的查询的运行是在主窗口(MainWindow)中。

学生信息查询

文件:selectdialog.h\ .cpp\ .ui//学生查询对话框:
可通过学号、姓名、班级三个特征进行查询

  • selectdialog.ui设计


  • selectdialog.h
#include 

namespace Ui {
class SelectDialog;
}

class SelectDialog : public QDialog
{
    Q_OBJECT

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

    QString Get_Value();//得到特征字符串
    int Get_Comboboxindex();//得到特征索引
    QString Get_Comboboxtext();//得到特征文本

private slots:
    void on_comboBox_currentIndexChanged(const QString &arg1);

private:
    Ui::SelectDialog *ui;
    int m_index;             //组合框索引
};

  • selectdialog.cpp
#include "selectdialog.h"
#include "ui_selectdialog.h"

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

    m_index=0;
}

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

QString SelectDialog::Get_Value()
{
    return ui->textEdit->toPlainText();
}

int SelectDialog::Get_Comboboxindex()
{
    return m_index;
}

void SelectDialog::on_comboBox_currentIndexChanged(const QString &arg1)
{
    if(arg1=="学号")
        m_index=0;
    else if(arg1=="姓名")
        m_index=1;
    else m_index=2;
}

QString SelectDialog::Get_Comboboxtext()
{
    if(m_index==0)return QString("学号");
    else if(m_index==1)return QString("姓名");
    else return QString("班级");
}

选课信息查询

==与学生信息查询相似==

文件:selectdialog1.h\ .cpp\ .ui//课程查询对话框:
可通过课程编号、课程名称两个特征进行查询

  • selectdialog1.ui设计


  • selectdialog1.h
#include 

namespace Ui {
class SelectDialog1;
}

class SelectDialog1 : public QDialog
{
    Q_OBJECT

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

    QString Get_Value();//得到特征字符串
    int Get_Comboboxindex();//得到特征索引
    QString Get_Comboboxtext();//得到特征文本

private slots:
    void on_comboBox_currentIndexChanged(const QString &arg1);

private:
    Ui::SelectDialog1 *ui;
    int m_index;         //组合框索引
};
  • selectdialog1.cpp
#include "selectdialog1.h"
#include "ui_selectdialog1.h"

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

    m_index=0;
}

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

QString SelectDialog1::Get_Value()
{
    return ui->textEdit->toPlainText();
}

int SelectDialog1::Get_Comboboxindex()
{
    return m_index;
}

QString SelectDialog1::Get_Comboboxtext()
{
    if(m_index==0)return QString("课程编号");
    else return QString("课程名称");
}

void SelectDialog1::on_comboBox_currentIndexChanged(const QString &arg1)
{
    if(arg1=="课程编号")
        m_index=0;
    else m_index=1;
}

提示对话框

文件:tipsdialog.h\ .cpp\ .ui//提醒对话框:
避免一些禁止操作,并提醒

  • tipsdialog.ui


  • tipsdialog.h

#include 

namespace Ui {
class TipsDialog;
}

class TipsDialog : public QDialog
{
    Q_OBJECT

public:
    explicit TipsDialog(QWidget *parent = nullptr);
    ~TipsDialog();
    void Tips_Show(const QString&tempstr);

private:
    Ui::TipsDialog *ui;
};
  • tipsdialog.cpp
#include "tipsdialog.h"
#include "ui_tipsdialog.h"

TipsDialog::TipsDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TipsDialog)
{
    ui->setupUi(this);
    setWindowTitle("提示");
}

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

void TipsDialog::Tips_Show(const QString &tempstr)
{
    ui->label->setText(tempstr);
}

主窗口设计⭐

概览

文件:mainwindow.h\ .cpp\ .ui//主窗口:
*ui//主窗口对象; *studentTableView//表格视图对象; m_students//学生队列类; m_View_kind//目前视图类型0显示学生信息,1显示选课信息,2显示从0表查询,3显示从1表中查询,4显示特定课程的选课学生; m_row//学生视图0选中索引; indexlist//记录学生信息0中查询结果索引,在查询视图可以进行删除、修改操作QList; m_row1//课程信息视图1选中索引; indexlist1//记录课程信息1中查询结果索引,在查询视图可以进行删除、修改操作QList;

  • 头文件代码如下:
#include 
#include
#include"studentinfotable.h"
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    void Show_Label1(const QString&tempstr);//数量显示
    void Show_Label2(const QString&tempstr);//进程提醒
    void Show_Label(const QString&tempstr);//名单备注

    void Show_StudentTable();         //显示学生信息(不可修改)0
    void Show_Table_s_changed();      //显示可修改

    void Show_CourseTable();          //显示选课信息(不可修改)1
    void Show_Table_c_changed();      //显示可修改

    void Show_SelectTable();          //显示查询结果(不可修改)2->0;3->1
    void Show_Table_sc_changed();     //显示可修改

    void Show_CtoSTable();            //显示特定课程的学生信息(不可修改)4

private slots:
    void on_actionOpen_triggered();   //打开文件

    void on_actionSave_triggered();   //保存数据

    void on_actionLoading_triggered(); //读取数据

    void on_actionSaveto_triggered();  //另存为

    void on_actionAdd_s_triggered();   //添加学生

    void on_actionShow_s_triggered();  //学生信息视图

    void on_tableView_clicked(const QModelIndex &index);  //获取鼠标选中表格的索引

    void on_actionDel_s_triggered();    //删除特定学生

    void on_actionAdd_c_triggered();    //为特定学生添加课程信息

    void on_actionShow_c_triggered();   //课程信息显示

    void on_actionDel_c_triggered();    //删除某个课程信息

    void on_actionSelect_triggered();   //查询

    void on_ShowInfotableView_changed();     //修改数据

    void on_actionChange_triggered();       //修改

    void on_actionChangedSave_triggered();   //保存修改(推出修改)


    void on_actionCtoS_Show_triggered();     //显示特定课程的学生信息

    void on_actionAscending_triggered();     //升序

    void on_actionDescending_triggered();    //降序

    void on_tableView_doubleClicked(const QModelIndex &index);

private:
    Ui::MainWindow *ui;                   //界面
    QStandardItemModel *studentTableView; //表格视图
    StudentInfoTable m_students;          //学生名单类

    int m_View_kind;                      //目前表格显示状态,0显示学生信息,1显示选课信息,
                                          //2显示从0表查询,3显示从1表中查询,4显示特定课程的选课学生

    int m_row;                            //0表中选中的行数
    QList indexlist;                 //记录0中查询结果索引,在查询视图可以进行删除、修改操作

    int m_row1;                           //1表中选中的行数
    QList indexlist1;                //记录1中查询结果索引,在查询视图可以进行删除、修改操作

    bool can_change;                      //是否进行修改

};

界面UI设计

直接利用添加菜单栏功能,大体设计如下:


==注意==:在添加完菜单功能时,会自动生成该Action Editor,如下图:

==右键选择转到槽后会在mainwindow.h中自动生成该对应的槽函数==,如下图:


==因为该cpp文件不少于1000行,这里就详细解释几个重要的操作,其他的可以举一反三==

构造函数

#include"readonlydelegate.h"
#include"tipsdialog.h"
#include"inputdialog_c.h"
#include"selectdialog.h"
#include"selectdialog1.h"

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

    //建立view模型
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);//单次选择
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);//选中一个item

    studentTableView=new QStandardItemModel();
    //关联
    ui->tableView->setModel(studentTableView);
    //信号与槽进行连接(后续可在tabelView中直接修改)
    connect(ui->tableView->itemDelegate(),&QAbstractItemDelegate::closeEditor,this,&MainWindow::on_ShowInfotableView_changed);
    //成员默认构造
    m_View_kind=0;
    m_row=-1;
    indexlist=QList();
    m_row1=-1;
    indexlist1=QList();
    can_change=false;
}

打开保存文件

  • 学生表类中我们已经写好了文件读取和文件保存,这里直接调用就好
//打开一个文件
void MainWindow::on_actionOpen_triggered()
{
    QString curPath = QDir::currentPath();
    QString dlgTitle = "选择一个文件";
    QString filter = "文本文件(*.txt);;所有文件(*.*)";
    QString aFileName = QFileDialog::getOpenFileName(this, dlgTitle, curPath, filter);

    if(aFileName.isEmpty())
    {

        Show_Label2("打开文件失败!");
        return;
    }

    Show_Label2("正在打开文件。。。");
    //创建成功,打开文件
    QFile aFile(aFileName);

    if(!aFile.exists()) //文件不存在
    {

        Show_Label2("打开文件失败!");
        return;
    }
    if(!aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //以文本方式打开
    {
        Show_Label2("打开文件失败!");
        return;
    }

    m_students=StudentInfoTable();//清空

    QTextStream aStream(&aFile); //用文本流读取文件
    aStream.setCodec(QTextCodec::codecForName("system")); //显示汉字

    m_students.ReadCourseInfoTable(aStream);
    aFile.close();//关闭文件
    Show_Label2("文件读取成功!");

    Show_StudentTable();
}

//保存一个文件
void MainWindow::on_actionSaveto_triggered()
{
    QString curPath = QDir::currentPath();
    QString dlgTitle = "另存为一个文件";
    QString filter = "文本文件(*.txt);;所有文件(*.*)";
    QString aFileName = QFileDialog::getSaveFileName(this, dlgTitle, curPath, filter);
    if(aFileName.isEmpty())
    {

        Show_Label2("保存文件失败!");
        return;
    }


    QFile aFile(aFileName);
    if(!aFile.open(QIODevice::WriteOnly| QIODevice::Text)) //保存为文本
    {

        Show_Label2("保存文件失败!");
        return;
    }

    QTextStream aStream(&aFile);//用文本流保存文件
    aStream.setCodec(QTextCodec::codecForName("system")); //显示汉字

    m_students.SaveStudentInfoTable(aStream);
    aFile.close();//关闭文件
    Show_Label2("文件保存成功!");
}

表格视图控件(tableView)使用⭐

  • 上面贴的头文件和构造函数里我们已经构造了表格视图对象
    QStandardItemModel *studentTableView; //表格视图
  • 下面我将介绍以下如何填充这个表格(以学生信息为例),代码如下:
void MainWindow::Show_StudentTable()
{
    //不能修改
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
    can_change=false;

    //显示学生信息
    m_View_kind=0;
    //重置选择行
    m_row=-1;
    m_row1=-1;
    Show_Label("学生信息视图");

    studentTableView->clear();
    studentTableView->setColumnCount(7); //7列

    //表头
    //学号、姓名、班级、电话、生日、地址、是否选课
    QStringList templist;
    templist<<"学号"<<"姓名"<<"班级"<<"电话"<<"生日"<<"地址"<<"是否选课";
    studentTableView->setHorizontalHeaderLabels(templist);

    int RowCnt=m_students.StudentNum();//行数(不含标题)
    studentTableView->setRowCount(RowCnt);

    //遍历插入数据
    QStandardItem *aTempItem;//临时的item
    QString tempstr;
    for(int i=0;isetItem(i,0,aTempItem);

        tempstr=temp_s.s_Name;
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,1,aTempItem);

        tempstr=temp_s.s_class;
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,2,aTempItem);

        tempstr=temp_s.ph_number;
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,3,aTempItem);

        tempstr=temp_s.birthday.toString("yyyy/MM/dd");
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,4,aTempItem);

        tempstr=temp_s.adress;
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,5,aTempItem);

        if(temp_s.is_courses())tempstr="否";
        else tempstr="是";
        aTempItem=new QStandardItem(tempstr);
        studentTableView->setItem(i,6,aTempItem);
    }
    Show_Label1(QString("学生人数:%1人").arg(m_students.StudentNum()));

    //设置内容为只读
    //ReadOnlyDelegate* readOnlyDelegate = new ReadOnlyDelegate(this);
    //ui->tableView->setItemDelegateForColumn(6, readOnlyDelegate);

}
  • 不管是选课信息的显示还是查询信息的显示都与上面的相似

得到鼠标选中的信息索引

  • 因为我们要对==特定的学生或者特定的课程==进行相关操作,所以我们在不同视图下要得到我们鼠标选中的索引,代码如下:
//为tableView控件的槽函数,函数参数为鼠标选中的表格索引
void MainWindow::on_tableView_clicked(const QModelIndex &index)
{
    if(m_View_kind==0)
    {
        m_row=index.row();
        Show_Label2(QString("已选中学号为%1 姓名为%2的学生").arg(m_students.GetStudent(m_row).s_ID).arg(m_students.GetStudent(m_row).s_Name));
    }
    else if(m_View_kind==1)
    {
        m_row1=index.row();
        Show_Label2(QString("已选中课程编号为%1 名称为%2的课程信息").arg(m_students.GetStudent(m_row).s_courses.GetCourse(m_row1).c_ID).arg(m_students.GetStudent(m_row).s_courses.GetCourse(m_row1).c_Name));
    }
    else if(m_View_kind==2)
    {
        if(indexlist.isEmpty())m_row=-1;
        else
        {
            m_row=indexlist[index.row()];
            Show_Label2(QString("已选中学号为%1 姓名为%2的学生").arg(m_students.GetStudent(m_row).s_ID).arg(m_students.GetStudent(m_row).s_Name));
        }
    }
    else if(m_View_kind==3)
    {
        if(indexlist1.isEmpty())m_row1=-1;
        else
        {
            m_row1=indexlist1[index.row()];
            Show_Label2(QString("已选中课程编号为%1 名称为%2的课程信息").arg(m_students.GetStudent(m_row).s_courses.GetCourse(m_row1).c_ID).arg(m_students.GetStudent(m_row).s_courses.GetCourse(m_row1).c_Name));
        }
    }
}
  • 既然得到了特定索引就可以实现对特定学生或对特定课程的操作,这里就不再赘述和贴代码啦。

信息查询

  • 对接查询对话框,遍历查找,代码如下:
void MainWindow::on_actionSelect_triggered()
{
    Show_Label2("正在进行查询。。。");

    //查询前清空索引列表
    indexlist.clear();
    indexlist1.clear();

    //在学生信息视图下
    if(m_View_kind==0 || m_View_kind==2)
    {
        SelectDialog sg1;
        sg1.setWindowTitle("学生信息查询");
        int ret=sg1.exec();

        if(ret==QDialog::Accepted)
        {
            int index=sg1.Get_Comboboxindex();//查询特征索引0为学号,1为姓名,2为班级
            QString tempstr=sg1.Get_Value(); //查询特征值

            //遍历数据
            for(int i=0;i

在表格视图中直接对信息进行修改(原数据也进行改变)

  • 在构造函数中我们已经链接了一个信号槽函数
    connect(ui->tableView->itemDelegate(),&QAbstractItemDelegate::closeEditor,this,&MainWindow::on_ShowInfotableView_changed); //信号与槽进行连接(后续可在tabelView中直接修改)
  • 而其中的==槽函数==MainWindow::on_ShowInfotableView_changed()代码如下:
void MainWindow::on_ShowInfotableView_changed()
{
    QModelIndex index = ui->tableView->currentIndex();
    int col=index.column();

    Student & temp_ss=m_students.GetStudent(m_row);
    QVariant data;//数据

    switch(m_View_kind)
    {
    case 0://学生信息视图
    {
        data=studentTableView->data(index);
        switch(col)
        {
        case 0: //学号
            temp_ss.s_ID=data.toString();
            break;
        case 1: //姓名
            temp_ss.s_Name=data.toString();
            break;
        case 2: //班级
            temp_ss.s_class=data.toString();
            break;
        case 3: //电话
            temp_ss.ph_number=data.toString();
            break;
        case 4: //生日
            temp_ss.birthday=data.toDate();
            break;
        case 5: //住址
            temp_ss.adress=data.toString();
            break;
        default:
            break;
        }
        Show_Table_s_changed();
        Show_Label2("修改已保存!");
        break;
    }
    case 1: //选课信息视图
    {
        Course & temp_c=temp_ss.s_courses.GetCourse(m_row1);
        data=studentTableView->data(index);
        switch(col)
        {
        case 0: //课程编号
            temp_c.c_ID=data.toString();
            break;
        case 1: //课程名称
            temp_c.c_Name=data.toString();
            break;
        case 2: //学分
            temp_c.credit=data.toFloat();
            break;
        case 3: //学期
            temp_c.term=data.toString();
            break;
        case 4: //教室
            temp_c.c_room=data.toString();
            break;
        case 5: //成绩
            temp_c.grade=data.toFloat();
            break;
        default:
            break;
        }
        Show_Table_c_changed();
        Show_Label2("修改已保存!");
        break;
    }
    case 2: //学生信息查询视图
    {
        data=studentTableView->data(index);
        switch(col)
        {
        case 0: //学号
            temp_ss.s_ID=data.toString();
            break;
        case 1: //姓名
            temp_ss.s_Name=data.toString();
            break;
        case 2: //班级
            temp_ss.s_class=data.toString();
            break;
        case 3: //电话
            temp_ss.ph_number=data.toString();
            break;
        case 4: //生日
            temp_ss.birthday=data.toDate();
            break;
        case 5: //住址
            temp_ss.adress=data.toString();
            break;
        default:
            break;
        }
        Show_Table_sc_changed();
        Show_Label2("修改已保存!");
        break;
    }
    case 3: //课程信息查询视图
    {
        Course & temp_c=temp_ss.s_courses.GetCourse(m_row1);
        data=studentTableView->data(index);
        switch(col)
        {
        case 0: //课程编号
            temp_c.c_ID=data.toString();
            break;
        case 1: //课程名称
            temp_c.c_Name=data.toString();
            break;
        case 2: //学分
            temp_c.credit=data.toFloat();
            break;
        case 3: //学期
            temp_c.term=data.toString();
            break;
        case 4: //教室
            temp_c.c_room=data.toString();
            break;
        case 5: //成绩
            temp_c.grade=data.toFloat();
            break;
        default:
            break;
        }
        Show_Table_sc_changed();
        Show_Label2("修改已保存!");
        break;
    }
    }
}
  • 到这里,我们的项目就已经完成的差不多了,我们可以再添加亿点点细节让整个系统更加完备。

功能演示

功能介绍

  • 添加/删除学生信息:
    在学生信息视图下操作,删除学生时要选中一个学生才能进行;
  • 指定学生添加/删除课程信息:
    添加操作要在学生信息视图下选定一个学生进行添加,删除操作要在选课信息视图下选定一个课程才能进行;
  • 可查询学生/课程信息,并且在查询后可直接进行修改或删除操作:
    在学生信息视图或课程信息视图下进行;
  • 保存/读取文件:
    可直接读取数据库中的文件并保存,也可打开其他文件并另存为
  • 可查看指定课程的学生信息,并可以进行成绩排序
    在特定课程学生信息视图下进行操作;
  • 在选择修改时才可进行修改,保护数据:
    点击“修改”选项后方可对数据进行修改,正常情况下不可修改

操作演示

部分操作图片:





资源获取

  • 主窗口cpp文件(mainwindow.cpp):点这里
  • 完整项目工程资源:点这里

你可能感兴趣的:(语言程序设计-利用Qt5实现学生选课管理系统(超详细附思路和代码))