Hello,大家好,我们又开始来学习新的QT小项目了,这个项目就是学生管理系统,我也是在网易云的课堂上学习的哦,如果想看效果图的直接滑到文章的最下面即可
我们首先说一下,这个项目的组成是一个WindowView和两个Dialog,首先我们来看下主页的WindowView的UI效果
可以看到这里非常的简单,只是放了一个Label,主要的功能在于左上角的菜单栏,关于菜单栏如何创建,可以看下UI上
双击即可创建菜单栏了,至于他的信号怎么发送,需要点击下面的功能框
我们选中Action Editor,然后右键对应的对象即可,所以我们来看下主页的头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include "addstuview.h"
#include "querystuview.h"
#include "aboutview.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_menu_add_stu_triggered();
void on_menu_query_stu_triggered();
void on_menu_about_triggered();
private:
Ui::MainWindow *ui;
AddStuView addView;
QueryStuView queryView;
AboutView aboutView;
};
#endif // MAINWINDOW_H
这里我只是定义了对应的添加和查询的两个功能View的对象以及三个菜单栏的槽函数
那么我们来看下我们的查询学生的View,我们先看头文件
#ifndef ADDSTUVIEW_H
#define ADDSTUVIEW_H
#include
namespace Ui {
class AddStuView;
}
class AddStuView : public QDialog
{
Q_OBJECT
public:
explicit AddStuView(QWidget *parent = 0);
~AddStuView();
public:
//初始化
void init();
//获取学员信息
void getStuViewData();
//打印信息
void print(const QString str);
//弹出提示
void showConfirmDialog(const QString str);
//检查数据合法
bool checkData(const QString name,const QString number);
//保存数据
void saveStuData();
//清空当前数据
void clearNowData();
//获取性别
QString getSex();
//获取爱好
QString getHobby();
private slots:
void on_btn_confirm_clicked();
void on_btn_cancel_clicked();
private:
Ui::AddStuView *ui;
bool isDebug = true;
QString content;
};
#endif // ADDSTUVIEW_H
头文件里,我定义了一堆的公开函数以及两个槽函数,分别是确定和取消,那么我们跟随他的构造函数一起来看看流程吧
我在构造函数中首先初始化了一些状态
void AddStuView::init()
{
//默认选中
this->ui->ck_boy->setChecked(true);
this->ui->cb_blue->setChecked(true);
}
对了,我们来看下UI吧
我们初始化的含义就是让性别和兴趣都有默认项
然后就要看下我们的确定按钮的槽函数了,因为一切的逻辑都是从这里开始的
//确定按钮
void AddStuView::on_btn_confirm_clicked()
{
this->getStuViewData();
}
为了代码的可读性我封装了一个函数getStuViewData来获取用户输入的相关信息
//获取添加学生的信息
void AddStuView::getStuViewData()
{
QString name = this->ui->et_name->text();
QString number = this->ui->et_number->text();
QString age = this->ui->cb_age->currentText();
QString school = this->ui->cb_school->currentText();
QString sex = this->getSex();
QString hobby = this->getHobby();
this -> content =
"姓名:" + name + "\n" +
"学号:" + number+ "\n" +
"性别:" + sex + "\n" +
"年龄:" + age + "\n" +
"学院:" + school + "\n" +
"爱好:" + hobby ;
this->print(this -> content);
//检测参数合法性
bool isCheck = this->checkData(name,number);
if(isCheck)
{
//弹框提示
this->showConfirmDialog(this -> content);
}
}
在这里我又创建了两个函数分别是getSex和getHobby来获取性别和兴趣,因为这些都是多选项所以不方便写一堆在一起
//获取性别
QString AddStuView::getSex()
{
QString sex = "男";
bool isCkBoy = this->ui->ck_boy->isChecked();
bool isCkGirl = this->ui->ck_girl->isChecked();
if(isCkBoy)
{
sex = "男";
}
if(isCkGirl)
{
sex = "女";
}
return sex;
}
//获取爱好
QString AddStuView::getHobby()
{
QList<QString> list;
if(this->ui->cb_blue->isChecked())
{
list.append("篮球");
}
if(this->ui->cb_voll->isChecked())
{
list.append("排球");
}
if(this->ui->cb_foot->isChecked())
{
list.append("足球");
}
if(this->ui->cb_bod->isChecked())
{
list.append("羽毛球");
}
QString hobby;
for (int i = 0; i < list.length(); ++i) {
hobby.append(list[i]);
if(i != (list.length()-1)){
hobby.append( ",");
}
}
return hobby;
}
当我们获取到相关的信息并且拼接在content变量中的时候我这里检测了一下参数的合法性,预防用户不输入导致我们程序的异常
//检查数据合法
bool AddStuView::checkData(const QString name, const QString number)
{
if(name.length() == 0)
{
//错误提示
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
if(number.length() == 0)
{
//错误提示
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
if(number.length() < 10)
{
//错误提示
QMessageBox::critical(this,"错误","学号必须大于等于十位","确定");
return false;
}
return true;
}
这里会弹出QMessageBox的提示框,这是他自带的简洁实现方法,我们在下面还有具体的实现方法,检测完合法性,我们就弹出窗口让用户去确定信息了
//显示Dialog
void AddStuView::showConfirmDialog(const QString str)
{
QMessageBox box;
box.setWindowTitle("请确定信息");
box.setText(str);
QPushButton* btnConfirm = box.addButton("确定",QMessageBox::AcceptRole);
QPushButton* btnCancel = box.addButton("取消",QMessageBox::RejectRole);
box.setDefaultButton(btnConfirm);
int ret = box.exec();
switch(ret)
{
case QMessageBox::AcceptRole:
//保存数据
this->saveStuData();
//清空当前数据
this->clearNowData();
break;
case QMessageBox::RejectRole:
box.close();
break;
}
}
这里对应的UI是这个效果
如果用户点击了确定也就触发了我们的槽,我们在这里做了两件事情
先看清空UI数据,实际上就是还原一下用户的输入,让用户可以继续录入学生信息
//清除当前数据
void AddStuView::clearNowData()
{
this->ui->et_name->setText("");
this->ui->et_number->setText("");
this->ui->ck_boy->setChecked(true);
this->ui->cb_age->setCurrentIndex(0);
this->ui->cb_school->setCurrentIndex(0);
this->ui->cb_blue->setChecked(true);
this->ui->cb_voll->setChecked(false);
this->ui->cb_foot->setChecked(false);
this->ui->cb_bod->setChecked(false);
//获取焦点
this->ui->et_name->setFocus();
}
紧接着,我们要保存数据,用到的是QFile
//保存数据
void AddStuView::saveStuData()
{
QFile file("stu.txt");
if (!file.open(QIODevice::Append | QIODevice::Text))
{
QMessageBox::critical(this,"错误","无法保存文件","确定");
return;
}
QTextStream out(&file);
//重新拼接数据,便于存储
QString cnt = this->content
.replace("\n"," ")
.remove("姓名:")
.remove("学号:")
.remove("性别:")
.remove("年龄:")
.remove("学院:")
.remove("爱好:");
this->print(cnt);
//写入
out << cnt + "\n";
}
这里我们保存数据做了很多的处理
写入之后可以在我们的build工程目录里看下相关信息
到这里我们的全部添加数据算是写完了,来看下完整代码
#include "addstuview.h"
#include "ui_addstuview.h"
#include
#include
#include
#include
#include
#include
#include
AddStuView::AddStuView(QWidget *parent) :
QDialog(parent),
ui(new Ui::AddStuView)
{
ui->setupUi(this);
this->init();
}
AddStuView::~AddStuView()
{
delete ui;
}
void AddStuView::init()
{
//默认选中
this->ui->ck_boy->setChecked(true);
this->ui->cb_blue->setChecked(true);
}
//确定按钮
void AddStuView::on_btn_confirm_clicked()
{
this->getStuViewData();
}
//取消按钮
void AddStuView::on_btn_cancel_clicked()
{
this->close();
}
//获取添加学生的信息
void AddStuView::getStuViewData()
{
QString name = this->ui->et_name->text();
QString number = this->ui->et_number->text();
QString age = this->ui->cb_age->currentText();
QString school = this->ui->cb_school->currentText();
QString sex = this->getSex();
QString hobby = this->getHobby();
this -> content =
"姓名:" + name + "\n" +
"学号:" + number+ "\n" +
"性别:" + sex + "\n" +
"年龄:" + age + "\n" +
"学院:" + school + "\n" +
"爱好:" + hobby ;
this->print(this -> content);
//检测参数合法性
bool isCheck = this->checkData(name,number);
if(isCheck)
{
//弹框提示
this->showConfirmDialog(this -> content);
}
}
//打印
void AddStuView::print(const QString str)
{
if(this->isDebug)
{
qDebug() << str;
}
}
//显示Dialog
void AddStuView::showConfirmDialog(const QString str)
{
QMessageBox box;
box.setWindowTitle("请确定信息");
box.setText(str);
QPushButton* btnConfirm = box.addButton("确定",QMessageBox::AcceptRole);
QPushButton* btnCancel = box.addButton("取消",QMessageBox::RejectRole);
box.setDefaultButton(btnConfirm);
int ret = box.exec();
switch(ret)
{
case QMessageBox::AcceptRole:
//保存数据
this->saveStuData();
//清空当前数据
this->clearNowData();
break;
case QMessageBox::RejectRole:
box.close();
break;
}
}
//检查数据合法
bool AddStuView::checkData(const QString name, const QString number)
{
if(name.length() == 0)
{
//错误提示
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
if(number.length() == 0)
{
//错误提示
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
if(number.length() < 10)
{
//错误提示
QMessageBox::critical(this,"错误","学号必须大于等于十位","确定");
return false;
}
return true;
}
//保存数据
void AddStuView::saveStuData()
{
QFile file("stu.txt");
if (!file.open(QIODevice::Append | QIODevice::Text))
{
QMessageBox::critical(this,"错误","无法保存文件","确定");
return;
}
QTextStream out(&file);
//重新拼接数据,便于存储
QString cnt = this->content
.replace("\n"," ")
.remove("姓名:")
.remove("学号:")
.remove("性别:")
.remove("年龄:")
.remove("学院:")
.remove("爱好:");
this->print(cnt);
//写入
out << cnt + "\n";
}
//清除当前数据
void AddStuView::clearNowData()
{
this->ui->et_name->setText("");
this->ui->et_number->setText("");
this->ui->ck_boy->setChecked(true);
this->ui->cb_age->setCurrentIndex(0);
this->ui->cb_school->setCurrentIndex(0);
this->ui->cb_blue->setChecked(true);
this->ui->cb_voll->setChecked(false);
this->ui->cb_foot->setChecked(false);
this->ui->cb_bod->setChecked(false);
//获取焦点
this->ui->et_name->setFocus();
}
//获取性别
QString AddStuView::getSex()
{
QString sex = "男";
bool isCkBoy = this->ui->ck_boy->isChecked();
bool isCkGirl = this->ui->ck_girl->isChecked();
if(isCkBoy)
{
sex = "男";
}
if(isCkGirl)
{
sex = "女";
}
return sex;
}
//获取爱好
QString AddStuView::getHobby()
{
QList list;
if(this->ui->cb_blue->isChecked())
{
list.append("篮球");
}
if(this->ui->cb_voll->isChecked())
{
list.append("排球");
}
if(this->ui->cb_foot->isChecked())
{
list.append("足球");
}
if(this->ui->cb_bod->isChecked())
{
list.append("羽毛球");
}
QString hobby;
for (int i = 0; i < list.length(); ++i) {
hobby.append(list[i]);
if(i != (list.length()-1)){
hobby.append( ",");
}
}
return hobby;
}
我们现在开始看下查询的代码,现在看下头文件
#ifndef QUERYSTUVIEW_H
#define QUERYSTUVIEW_H
#include
#include
#include
#include
#include
#include
namespace Ui {
class QueryStuView;
}
class QueryStuView : public QDialog
{
Q_OBJECT
public:
explicit QueryStuView(QWidget *parent = 0);
~QueryStuView();
private:
//初始化
void init();
//获取输入框数据
bool getQueryText();
//获取文件数据
void getFileData();
//解析文件数据
void parsingFileData();
//显示UI
void showUI(int row,QStringList list);
private slots:
void on_btn_query_stu_clicked();
private:
Ui::QueryStuView *ui;
QString queryText;
int index = 0;
QList list_line;
QStandardItemModel* model;
};
#endif // QUERYSTUVIEW_H
头文件里,我们注意到有一个对象QStandardItemModel,这个就是实现QTableView的重要部分了,我们先看下UI
那么我们怎么实现呢?还是按照逻辑去跟代码
void QueryStuView::init()
{
//实例化
this->model = new QStandardItemModel;
//设置表头
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("爱好"));
//设置视图
this->ui->tab_stu_view->setModel(model);
//设置列宽
this->ui->tab_stu_view->setColumnWidth(1,500);
}
可以看到,我们初始化的时候,就把QStandardItemModel的对象new出来了,然后设置了一下头部的标题
然后要看触发的槽,也就是搜索按钮了
//点击搜索
void QueryStuView::on_btn_query_stu_clicked()
{
qDebug() << "点击搜索";
this->index = this->ui->cb_conditions->currentIndex();
bool isHave = this->getQueryText();
if(isHave)
{
//开始查询文件
this->getFileData();
}
}
我们点击搜索后,获取了当前的筛选条件以及输入框内的文字
//获取输入框数据
bool QueryStuView::getQueryText()
{
//获取输入框
this-> queryText = this->ui->et_query->text();
if(this->queryText.length() == 0)
{
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
return true;
}
如果你输入有内容,我们就开始查询下我们的文件
//获取文件数据
void QueryStuView::getFileData()
{
qDebug() << "获取文件";
//清理数据
this->list_line.clear();
this->model->clear();
QFile file("stu.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::critical(this,"错误","无法打开文件","确定");
return;
}
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
this->list_line.append(line);
}
file.close();
//解析文件数据
this->parsingFileData();
}
这里我们获取到文件数据list_line后开始去解析
//解析文件数据
void QueryStuView::parsingFileData()
{
qDebug() << "解析文件";
int row = 0;
//遍历数据
for (int i = 0; i < this->list_line.length(); ++i) {
QString str = this->list_line.at(i);
//分割
QStringList list = (str.split(" "));
qDebug() << index;
//按照条件
switch(this->index)
{
//姓名
case 0:
if(this->queryText == list.at(0)){
this->showUI(row++,list);
}
break;
//学号
case 1:
if(this->queryText == list.at(1)){
this->showUI(row++,list);
}
break;
//院系
case 2:
if(this->queryText == list.at(4)){
this->showUI(row++,list);
}
break;
}
}
}
遍历后根据筛选条件来显示具体的数据
//显示UI
void QueryStuView::showUI(int row,QStringList list)
{
qDebug() << "显示UI:" << list.length();
for (int i = 0; i < list.length(); ++i) {
this->model ->setItem(row,i,new QStandardItem(list.at(i)));
}
}
嗯 ,到这里也就完成了我们的查询功能了,来看下完整的代码
#include "querystuview.h"
#include "ui_querystuview.h"
#include
#include
#include
#include
#include
QueryStuView::QueryStuView(QWidget *parent) :
QDialog(parent),
ui(new Ui::QueryStuView)
{
ui->setupUi(this);
this->init();
}
QueryStuView::~QueryStuView()
{
delete ui;
}
void QueryStuView::init()
{
//实例化
this->model = new QStandardItemModel;
//设置表头
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("爱好"));
//设置视图
this->ui->tab_stu_view->setModel(model);
//设置列宽
this->ui->tab_stu_view->setColumnWidth(1,500);
}
//点击搜索
void QueryStuView::on_btn_query_stu_clicked()
{
qDebug() << "点击搜索";
this->index = this->ui->cb_conditions->currentIndex();
bool isHave = this->getQueryText();
if(isHave)
{
//开始查询文件
this->getFileData();
}
}
//获取输入框数据
bool QueryStuView::getQueryText()
{
//获取输入框
this-> queryText = this->ui->et_query->text();
if(this->queryText.length() == 0)
{
QMessageBox::critical(this,"错误","输入框不能为空","确定");
return false;
}
return true;
}
//获取文件数据
void QueryStuView::getFileData()
{
qDebug() << "获取文件";
//清理数据
this->list_line.clear();
this->model->clear();
QFile file("stu.txt");
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QMessageBox::critical(this,"错误","无法打开文件","确定");
return;
}
QTextStream in(&file);
while (!in.atEnd()) {
QString line = in.readLine();
this->list_line.append(line);
}
file.close();
//解析文件数据
this->parsingFileData();
}
//解析文件数据
void QueryStuView::parsingFileData()
{
qDebug() << "解析文件";
int row = 0;
//遍历数据
for (int i = 0; i < this->list_line.length(); ++i) {
QString str = this->list_line.at(i);
//分割
QStringList list = (str.split(" "));
qDebug() << index;
//按照条件
switch(this->index)
{
//姓名
case 0:
if(this->queryText == list.at(0)){
this->showUI(row++,list);
}
break;
//学号
case 1:
if(this->queryText == list.at(1)){
this->showUI(row++,list);
}
break;
//院系
case 2:
if(this->queryText == list.at(4)){
this->showUI(row++,list);
}
break;
}
}
}
//显示UI
void QueryStuView::showUI(int row,QStringList list)
{
qDebug() << "显示UI:" << list.length();
for (int i = 0; i < list.length(); ++i) {
this->model ->setItem(row,i,new QStandardItem(list.at(i)));
}
}
好,最后一个关于,其实就是个UI
有兴趣的可以关注下我的公众号和加群,我就不过多打广告了
来看下实际的效果吧