C/C++ 基于QT实现粗糙的学生管理系统

下载地址:https://download.csdn.net/download/GameStrategist/12717944

简略说明:这不能算作一个可以放到简历上的项目
核心:利用 help 帮助手册查看预设函数,感觉英语好上手会很快;
机制:信号与槽
设计模式:模型 - 视图 - 控制器(MVC)(实际应用开发会分工,不会一个人全做)

  • 模型:应用程序对象。
  • 视图:屏幕演示。
  • 控制器:定义了用户界面响应用户输入的方式。

一.完成添加学生的功能界面

  • 1.+New Project,记得设置名称和文件目录等都不要出现中文字样
    设置类名为addStu,且继承 QDialog(QDialog类是对话框窗口的基类)
    在这里插入图片描述

  • 2.界面参数设置。(小项目 ui 界面直接设置,也可以利用坐标函数来设置)

2.1 ui 界面 geometry控件 宽度350 高度480 (界面是以像素点为单位)
2.2 ui 界面 选择控件如下所示

Display Widgets: Label      		 	七个 (欢迎标题,姓名,学号,性别,年龄,院系,兴趣,)
Input Widgets:  Line Edit  		 	两个(姓名,学号)
单选按钮 Buttons:Radio Button 		 	两个(性别)
下拉列表Input Widgets:Conmbo Box 	 	两个(年龄,院系)
多选按钮 Buttons:Check Box 			 	四个 (兴趣)
确定按钮 取消按钮  Buttons:Push Button 	两个

目前随意摆放,有个大概样子就可以了。

在这里插入图片描述
2.3 优化界面 通过两个控件 Layouts 和 Spacers(原则:由小至大,逐个布局)
如上图所示,每个小布局 水平布局 构成一个一个小的 layout (有关联的按住 Ctrl 点击就行)
“兴趣”右侧四个按钮需要先 栅格布局 再和 “兴趣” 进行水平布局
全部布局完成后,点击 垂直布局,此时结果如下:
在这里插入图片描述
现在的界面的对比度还是有问题,比如 文字 和 输入框 一个短一个长 很别扭
点击类似姓名这一小的 layout 注意是 layout
点击右侧会出现如下图所示,我们要做的就是修改 layoutStretch (控件按比例扩大缩小)
在这里插入图片描述
修改控件比例也可以选择右上角的侧面栏入手
在这里插入图片描述
layout 的参数大致为 1,8 和 1,4,4 觉得长了就用一个弹簧来纠正一下
在这里插入图片描述
简单运行一下,发现的确与想象中还是有差距的
在这里插入图片描述
原因是现在的 “添加学生”控件 是独立的,可以理解为会自适应界面大小

解决方案:1.将“添加学生”控件,也就是 label 中的 sizePollcy 中的垂直策略修改为 Fixed
(label 的高度无法改变,这样就能正常显示了)
在这里插入图片描述
接下来修改一下 label 字体的显示 (QLabel )
在这里插入图片描述
字大点(QWidget),笔者用styleSheet比较多
在这里插入图片描述
目前基本界面就可以确定了,然后开始修改 “各个控件” 的名称,要开始利用信号与槽机制了
在这里插入图片描述

姓名: le_name
学号:le_id
男:rbtn_male
女:rntn_fmale
年龄:cbb_age
院系:cbb_yx

二.细化界面,完成事件驱动

什么是事件驱动? 你点击一个按钮触发一个事件,这就是事件驱动。
(所有的事件结束后,需要点击 “确定按钮” 保存,所以确定就是事件驱动)

如何从控件中获取信息,首先先看控件有没有text,有就获取。(text内容属于QString)

还是利用 help手册,学习我们会用到的窗口。(QMessageBox消息对话框)
不想看英文,直接翻到下面看这种有代码的 demo,理解起来会很快。
在这里插入图片描述
我们的目的是给用户一个选择

// 1.新建对象
QMessageBox msgBox;

// 2.配置文件
//设置输出信息
msgBox.setText("The document has been modified.");
msgBox.setInformativeText("Do you want to save your changes?");
//利用预设宏 设置消息框的按钮
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
//设置默认按钮
msgBox.setDefaultButton(QMessageBox::Save);

// 3.显示并返回一个值 可以知道是哪个按钮点击的
int ret = msgBox.exec();

现象如下图所示在这里插入图片描述
稍加修改

msgBox.setText("请确认信息.");
msgBox.setInformativeText(name+'\n'+ id);
msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);

得到如下图所示结构
在这里插入图片描述
但是 ret 这个返回值是干什么的?
答 : 可以利用switch case来判断是哪个按钮

switch (ret) {
case QMessageBox::Save:
            // Save was clicked
            break;
case QMessageBox::Discard:
            // Don't Save was clicked
            break;
case QMessageBox::Cancel:
            // Cancel was clicked
            break;
default:
            // should never be reached
            break;
      }

下图为help手册的demo:
在这里插入图片描述
但现在这个还不符合我们的需求,我们想要的是带有中文字样的按钮。
那么如何设置按钮为中文呢 ?(如上使用的按钮名称是预设的默认静态标准按钮)
直接修改成中文,编译会报错;
所以我们需要添加新的按钮,查询help手册,开头就是 addButton 函数

但是要中文与按钮的信息同步。(这里实质是做了一次绑定)
类似 确定按钮对应AccpetRole 或者 取消按钮对应RejectRole
代码如下:

msgBox.setText("请确认信息.");
msgBox.setInformativeText(name+'\n'+ id);
msgBox.addButton("确定",QMessageBox::AccpetRole);
msgBox.addButton("取消",QMessageBox::RejectRole);

效果如下图所示
在这里插入图片描述
依旧可以设置默认按钮

//利用返回值设置一个默认按钮
QPushButton* cbtn = msgBox.addButton("取消",QMessageBox::RejectRole);
msgBox.setDefaultButton(cbtn);

在这里插入图片描述
注意:如上是介绍 QMessageBox 能够帮助我们做什么。

但是 通常我们会利用 QT 已经设置好的按钮来更好的完成项目。
所以进入help 手册 查看静态成员(图片模糊不要打我啊!)
在这里插入图片描述
简单的测试能更好的体验到效果。
这是一种预定义的按钮,比之前的更加简单,注意参数配置就行。

 QMessageBox::aboutQt(this,"鸣谢");

在这里插入图片描述
此时利用中文按钮就更加简单了,直接输入就可以了

QMessageBox::information(this,"请确认信息",name+'\n'+id,"确认","取消");

测试图如下
在这里插入图片描述
这几个预定义的按钮参数配置都是类似的,不同点在提示图案样式。(不过还是要区分使用场景)

简单了解一下应用场景 顺便注意使用的语境是否对应正确的图形

aboutQt 用到qt,感谢一下qt, 用这个,不用也行,不过通常可以利用这一栏写出创作者信息(nice)
剩下就不说了,然后我们直接使用 information 或者 critical 就行了
为了避免输入的参数过长,最好声明新属性来代替,仍然是有返回值的,int ret 可以利用来确认按钮

 QString content = name + '\n' + id;
 int ret = QMessageBox::critical(this,"请确认信息",content,"确认","取消");

在这里插入图片描述

Line Edit 优化

在此之上进行细节的优化,由 ui界面 设置姓名后的 Line Edit

maxLength 输入最大长度
echoMode 是输出模式,通常选择最后一个;也可以自行查看
clearButtonEnabled 设置按钮 后可以清空输入
placeholderText 占位等候文本  

在这里插入图片描述
在这里插入图片描述
界面最上端中间名 QWidget 中的如下所示
在这里插入图片描述

qline 的 Signals (搜索help手册)

一个控件可以绑定多个信号,所以可以多测试一下几个信号 (转到槽就能看到)
在这里插入图片描述

然后我们需要对 qline 进行判断,比如 姓名为空 或者 学号为空

QString content = name + '\n' + id;
if(name.length() < 1 || id.length() < 1)
{
    QMessageBox::critical(this,"错误","信息填写不完整,请重新检查","确定");
}
else
{
    int ret = QMessageBox::question(this,"请确认信息",content,"确认","取消","不知道");
}

年龄和院系的下拉框的设置,先来到ui界面,直接双击下拉框就能弹出这个
在这里插入图片描述
添加就行了。
QComboBox 属性如下
在这里插入图片描述
界面显示的代码如下

QString age = this->ui->cbb_age->currentText();
QString dev = this->ui->cbb_yx->currentText();
QString content = name + '\n' + id + '\n' + sex + '\n' + age + '\n' + dev+ '\n' + ins; 

单选按钮 多选按钮 设置

性别只有 男 女,为两个单选按钮,单选就意味着只能按一个 所以只需要判断 checked
然后搜索 help 手册 qradio 中的 checked,函数返回的是 bool 类型
假设点击 男 返回 true 那么 女 则 false 达成关系互斥
在这里插入图片描述
设置一个按钮组后,但没有和其它的按钮互斥,所以其它的也要设置按钮组
目的是为了区分 和 避免 多个单选按钮是不同按钮组
利用 Ctrl 键选中 男 女 然后右击 会出现按钮组 然后新建按钮组
在这里插入图片描述
在右侧栏最下面会生成新的按钮组
在这里插入图片描述
可以通过对此属性修改是单选 还是 多选
在这里插入图片描述
但是我们现在显示的信息是局部的 需要逐个的去写代码。
这是最笨的办法,而且每次都需要去判断很麻烦。
QT应该先我们一步想到了,所以我们应该可以利用预设的函数来解决

qbut (help 手册 搜索 QButtonGroup)
在这里插入图片描述
性别 男 单选按钮 点击了checked 变成默认选项 (单选也最好设置一个默认)
在这里插入图片描述
单选多选还有一个区别 如下:
在这里插入图片描述
注意:一旦有按钮组 那么必须将所有的按钮都建组或者分好组

那么如何获取 多选按钮 被选中的兴趣呢
方案一
笨办法:依次判断 checked 的bool 类型,但是条目多了 这个方法实现就变得更难了。
方案二
如上图的功能函数中 发现有一个返回容器的函数,能够接收多个信息
在这里插入图片描述

QList<QAbstractButton *> ins_list = this->ui->hbGroup->buttons();
QString ins;
for(int i = 0;i<ins_list.length();i++)
{
    QAbstractButton * che = ins_list.at(i);
    if(che->isChecked())//相当于数组下标 代替迭代器
    {
        ins += che->text() + ",";
    }
}

这里需要添加几个头文件

#include <QList>
#include <QAbstractButton>

上面介绍的内容主要还是按钮组的使用。
当完成界面后,只能完成一次输入,正常我们会多次输入。
不过先给单次输入简单收尾。

当点击确定后,说明这一次已经结束,所以根据确定按钮来完成事件驱动。(清空)
setText(" ") 函数 或者 使用QT预设的 clear函数

清除界面函数如下:

void addStu::clearUserInterface()//清除用户界面
{
    this->ui->le_name->clear();
    this->ui->le_id->clear();
    this->ui->rbtn_male->setChecked(true);//性别回到男
    this->ui->cbb_age->setCurrentIndex(0);//回到数组0下标
    this->ui->cbb_yx->setCurrentIndex(0);//同上
    //如下是设置较为麻烦的多选按钮
    QList<QAbstractButton *> ins_list = this->ui->hbGroup->buttons();

    for(int i = 0;i<ins_list.length();i++)
    {
        QAbstractButton* box = ins_list.at(i);
        box->setChecked(false);
    }
    //在如上步骤结束后,光标是回到了学号与理想不符,应设置回到最上栏
    //焦点 如何让一个控件获取焦点
    this->ui->le_name->setFocus();
}

完成文件保存

  • help手册 搜索 QFile ,建议从详细描述看起
    在这里插入图片描述
    点击就会出现一些含有代码demo的界面。
    在这里插入图片描述
    如下代码完成写入操作示例:
QFile file("out.txt");
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    return;
QTextStream out(&file);
out << "The magic number is: " << 49 << "\n";

应用在本系统的完整的文件写入函数如下。(在确定按钮按下后调用此函数)

void addStu::writeToFile(QString cnt)
{
    //要注意当前路径,至少要知道产生的文件在哪里
    QFile file("stu.txt");
    //如果使用WriteOnly 会清空
    //if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
    if(!file.open(QIODevice::Append | QIODevice::Text))
    {
        QMessageBox::critical(this,"错误","文件打开失败,信息没有保存!","确定");
        return ;
    }
    QTextStream out(&file);
    out << cnt;
}
  • 该界面最后的一个按钮:取消按钮 (作用;按下取消按钮 关闭当前界面 )

help 手册 搜索 QDialog 查询 Public Slots 查看槽函数
方案一
尽量不用如此使用,能直接调用成员函数的槽 直接调用 基类的槽函数利用方法二就好

//取消按钮 直接转到槽 调用close();
void addStu::on_btn_cancel_clicked()
{
    this->close();
}

方案二

connect(this->ui->btn_cancel,SIGNAL(clicked(bool)),this,SLOT(close()));

方案三
在这里插入图片描述

Signals & Slots Editor 信号与槽编辑器 在ui界面可以直接编写,(QT中间下面位置)
但只支持系统预设的函数,不过我个人感觉没必要这样做,应该将 mvc 各司其职 分开来

方案四
在这里插入图片描述
x 号左侧两个按钮也可以进行 信号与槽的绑定 可以自己试试,拉拽完成,可以设置自己的函数。

三.完成菜单选择窗口

需要添加新的 ui 界面
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
一直往下按 完成创建即可。
在这里插入图片描述
点开,然后首先设置一下QWidget 参数 宽度458 高度314(可以随意修改)
在这里插入图片描述
拖拽一个 Display Widgets 中的 Label 然后通过右上角centralwidget 进行水平布局
修改字体大小 颜色 之前已经介绍过,通过右下角的 styleSheet 就行了
在这里插入图片描述
但是程序运行 还是没有主窗口 更加无法实现我们想象中的从主窗口进入副窗口
我们先在主界面的左上角添加一些功能,怎么改,不着急
ui 界面的左上角“在这里输入”,输入你想实现的功能名称然后回车 就可以创建功能窗口了。
在这里插入图片描述
完成如下就可以继续下一步了,挺简单的
在这里插入图片描述
现在我们要让其选项有正常功能,也就是要利用信号与槽机制。
但先要找到它
查看右侧属性,发现bojectName,能拿到名字就能绑定,
在这里插入图片描述
但是没有半发直接转到槽,但是中间下方的 信号与槽 还在,不过只能设定系统预定的槽函数
此时我们点击Action Editor ,
在这里插入图片描述
再右击addstu 却能发现一个转到槽
在这里插入图片描述
对于菜单而言,触发就行 不需要点击
在这里插入图片描述
这样我们就完成了一个 信号与槽的绑定
在这里插入图片描述
包含addStu头文件,创建其对象,写出如下函数,但是执行却没有反应
因为局部变量的周期结束,直接销毁。
所以我们需要添加一个循环,死循环当然不可取
在这里插入图片描述
使用QT预设的exec()函数,它的作用相当于阻塞程序结束 可以看作一个死循环
如果仍然要使用show函数那么一定要保证对象不会销毁

方案一

void MainWindow::on_actionaddStu_triggered()
{
    addStu a;
    a.show();
    a.exec();//模态视图
}

方案二
声明一个类内成员,去使用槽函数。
在这里插入图片描述
总结:
1.exec(); 确保对象不会被销毁
2.通过组合的方式声明类内对象调用show函数

添加新窗口完成查找功能

创建方式如上,这次不选择mainwindow,选择dialog with button
修改了名称为 queryStu
简单设置参数 宽度650 高度450

往ui界面拖拉控件

Input Widgets : 			1个Conbo Box 和 1个Line Edit
Buttons:					1个PushButton
上三个水平布局,layout 2,6,2 名称修改自拟

Item Views (Model-Based):	1个Table View
整体layout 垂直布局

Conbo Box 双击就可以添加功能。
在这里插入图片描述
我们的目的是在主页面触发功能时能弹出窗口
在这里插入图片描述
还是在中间下端 右击queryStu 转到槽,这样就绑定好了。
在这里插入图片描述
方法一
创建对象,调用show函数,并用 exec()函数阻塞
方法二

void MainWindow::on_actionaddStu_triggered()
{
    addStu a;
    a.exec();//组合
}

void MainWindow::on_actionqueryStu_triggered()
{
    QueryStu q;
    q.exec();
}

设置好后就能够弹出了。但是新的窗口没有功能。
对查询功能的步骤应该是

  • 1.将文件中的内容读取出来保存在系统中
  • 2.完成查询

help帮助手册 查询 QFile,
在这里插入图片描述
点击进入就是
在这里插入图片描述
读取文件数据函数

int QueryStu::readFromFile()
{
    QFile file("stu.txt");
    if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        return -1;
    }
    QTextStream in(&file);

    while(!in.atEnd())//返回文件末尾
    {
        QString line = in.readLine();
        stu_lines.append(line);
    }
    file.close();
    /* //写好代码,后台测试 能否在界面开启时读入数据成功
    for(int i = 0;i < stu_lines.length();i++)
    {
        qDebug()<<stu_lines.at(i);
    }
    */
    //函数写完后要想 在什么时候调用
    //最好的方式是 当搜索功能窗口弹出时文件已经读出成功
    return 0;
}

调用函数时机
在这里插入图片描述
然后我们要在界面上实现搜索功能

  • 1.绑定槽
    在这里插入图片描述

  • 2.搜索按钮

绑定槽函数, 选择的查询功能以及最后查询的数据。
槽函数的代码如下, switch是用来测试是否读取了数据。
并且利用了另一个函数来辅助实现功能。

void QueryStu::on_btn_search_clicked()
{
    //1.获取用户选取的方式
    int index = this->ui->cbb_method->currentIndex();
    QString cnt = this->ui->le_cnt->text();
    doQuert(index,cnt);

}
void QueryStu::doQuert(int index,QString cnt)
{
    //需要分割出系统所需的数据,遍历
    for(int i = 0; i < stu_lines.length();i++)
    {
        //取出每行内容 //此时可以查询QString类中是否有分割函数
        //如何搜索help手册 可以从返回值考虑 这样的函数还真有 共四种重载
        //没兴趣看英文 直接看代码也行
        QString line = stu_lines.at(i);
        //之前数据存储按空格分割
        line = line.trimmed();//开头或者结尾的空白 去除
        QStringList subs = line.split(" ");
        switch (index)
        {
        case 1:
            if(cnt == subs.at(0))
            {
                qDebug()<<line;
            }
            break;
        case 2:
            if(cnt == subs.at(1))
            {
                qDebug() << line;
            }
            break;
        case 3:
            if(cnt == subs.at(4))
            {
                qDebug() << line;
            }
            break;
        default:
            QMessageBox::critical(this,"严重错误","文件打开失败,请重试");
            this->close();//界面关闭
            break;
        }
    }
}

利用help手册搜索的内容 如下
在这里插入图片描述
如上完成了查询的功能, 下面要做的就是让内容显示到 Table view
重点:如何构造 Model

搜索 help手册 QTableView
但实际使用的是
在这里插入图片描述
首先在 QueryStu 类中声明了一个对象指针,在构造函数中new创建
在这里插入图片描述
然后写成函数.利用如上图所示的help手册中的函数去生成表格。

void QueryStu::setMyModel()
{
    this->model = new QStandardItemModel;//生成一个表格
    //设置表头  内容model管,外观Item管
    this->model->setHorizontalHeaderItem(0,new QStandardItem("姓名"));
    this->model->setHorizontalHeaderItem(1,new QStandardItem("学号"));
    this->model->setHorizontalHeaderItem(2,new QStandardItem("性别"));
    this->model->setHorizontalHeaderItem(3,new QStandardItem("年龄"));
    this->model->setHorizontalHeaderItem(4,new QStandardItem("院系"));
    this->model->setHorizontalHeaderItem(5,new QStandardItem("兴趣"));
    //将当前表头与model绑定
    this->ui->tableView->setModel(model);
    //设置表格数据的宽度
    this->ui->tableView->setColumnWidth(0,100);
    this->ui->tableView->setColumnWidth(1,150);
    this->ui->tableView->setColumnWidth(2,50);
    this->ui->tableView->setColumnWidth(3,50);
    this->ui->tableView->setColumnWidth(4,100);
    this->ui->tableView->setColumnWidth(5,150);
}

然后写显示函数,基本就没了

void QueryStu::doQuert(int index,QString cnt)
{
    //需要分割出系统所需的数据,遍历
    for(int i = 0,row = 0; i < stu_lines.length();i++)
    {

        //取出每行内容 //此时可以查询QString类中是否有分割函数
        //如何搜索help手册 可以从返回值考虑 这样的函数还真有 共四种重载
        //没兴趣看英文 直接看代码也行
        QString line = stu_lines.at(i);
        //之前数据存储按空格分割
        line = line.trimmed();//开头或者结尾的空白 去除
        QStringList subs = line.split(" ");
        switch (index)
        {
        case 1:
            if(cnt == subs.at(0))
            {
                display(row++,subs);
            }
            break;
        case 2:
            if(cnt == subs.at(1))
            {
                display(row++,subs);
            }
            break;
        case 3:
            if(cnt == subs.at(2))
            {
                display(row++,subs);
            }
            break;
        case 4:
            if(cnt == subs.at(3))
            {
                display(row++,subs);
            }
            break;
        case 5:
            if(cnt == subs.at(4))
            {
                 display(row++,subs);
            }
            break;
        default:
            break;
        }
    }
}
//传参 列 与 行
void QueryStu::display(int row,QStringList subs)
{
    for(int i = 0;i<5;i++)
    {
        this->model->setItem(row,i,new QStandardItem(subs.at(i)));
    }
    QString ins;
    for(int i = 5; i<subs.length();i++)
    {
        if(i==subs.length() || i==subs.length()-1)
        {
            ins += subs.at(i);
        }
        else
        {
            ins += subs.at(i) + ",";
        }
    }
    this->model->setItem(row,5,new QStandardItem(ins));
}

猜你喜欢

转载自blog.csdn.net/GameStrategist/article/details/108046388