学生管理系统

时间:2021-02-22 03:39:40
首先这个程序使用本地文件存放数据,在第一次运行的时候会在程序目录内生成一个info的目录,里面生成一些文件,这些文件即为程序所用的数据,千万不要 改文件内容或者文件名之类的,如果改了,就会导致程序崩溃(linux下为段错误,win7下为程序未响应,另外如果你装360的话,360可能会在次刻 跳出来直接把你的程序干掉,原因未知。。。 学生管理系统


如果发送这种情况,直接删掉info目录即可,程序再次启动时会重新创建,但你以前的数据也就木有了,于是你可以在正常的时候把./info目录以及目录里的文件拷贝一份,下次出问题的时候就可以用备份恢复数据了 学生管理系统


程序启动后是个登陆框,很简单

学生管理系统

这个系统我做了2种权限,一个是唯一的超级账户
账号 teacher
密码 123456
这个账户拥有这个程序的所有权限,另外的就是无数个学生账户了
登陆老师账户后学生管理系统
学生管理系统
 这里是2张表,其实这样的表模型有现成的QTableWidget,但一方面为了“练手”,另一方面由于要数据同步,所以这2张表我都是使用的自定义模型 学生管理系统,均派生QAbstractModel


这2张表数据是同步的,把成绩表中的末位学生名字改后,信息表中名字也会随之改变
删除:用于删除一整行(即一个学生)删除焦点所在的行,如果视图丢失焦点(比如你鼠 标点了别的地方,他会删除第一行,所以小心使用
添加: 在表最下方添加一行空行,用于增加学生

由于2张表(模型)数据同步,所以上面2个对某张表(模型)的操作都会同步到另一张表上

写入:在视图上修改后的数据不会立刻写进数据文件(info目录),只有点击写入后才会写入文件,这类似于一个保存的作用

然后就是自定义委托了
2个模型info和exam我各做了一个


首先是exam模型,这个主要存放学生的考试成绩,其成绩在模型内使用QString操作,所以你不用担心数据的存放问题,也不用担心往成绩栏(要求输入整数)栏里误输了个字幕而导致程序出现问题,随之而来的问题是在成绩栏你也可以输入字符。。。 学生管理系统


exam模型的自定义委托的作用是提示,如果你再成绩栏里输入的不是数字或者输入的数字不知0-100的整数,那字体就会显示为红色,用于提醒用户(老师),你的输入可能有误

学生管理系统

 info模型的自定义委托主要用于输入,性别一栏只有2个选择,学院一栏选项也不多(我假设一个学校的学院不是灰常多。。)遇到这种情况,用一个下拉菜单提供选项比让用户(老师)直接输入更为便(an)捷(quan);

info模型的自定义委托就是实现这个功能

学生管理系统

学生管理系统

 ~~~~~华丽的分割线~~~~~
此时你可能注意到了,在信息 表中,有密码 这一列,
程序设定是学生利用他的学号和密码登陆,老师可以看到/更改学生的密码,就是我开始说道的权限

然后(老师)关闭程序后,再次登陆,某位学生输入了他的账号(学号),(老师告诉他的)密码,
然后学生的登陆界面就比较简答了,既能查看自己的考试成绩(话说学生没必要查看自己性别,年龄之类的信息了吧 学生管理系统

学生登陆框的标题会提示登陆的是那位学生,学生唯一可以做的就是修改登陆密码

学生管理系统

 学生管理系统 当然,如果你忘了密码,可以去找老师,他可以帮你改密码学生管理系统

~~~~
http://pan.baidu.com/s/1nt2y9gl
注意这里文件是我在linux(ubuntu14.04)下写的文件,在win系统下编译没问题,但打开可能会出现乱码.如果有这里问题,下面有源代码(PS:源代码里没有.pro文件的源代码)
这里pro文件写好了,编译的时候记得打开编译器的c++11选择(如果你没开的话)

~~~~~以下是源代码~~~~~
buildFile.h
#ifndef BUILDFILE_H_
#define BUILDFILE_H_
#include<QDir>
#include<QFile>
void buildFile();
#endif


buildFile.cxx
#include"buildFile.h"
#include<QTextStream>
void buildFile()
{
QString infoPath = QDir::currentPath();
infoPath = infoPath + "/info";
QDir dirs;
dirs.mkpath(infoPath); //创建目录
QString name = infoPath + "/name.txt";
QString chinese = infoPath + "/chinese.txt";
QString match = infoPath + "/match.txt";
QString english = infoPath + "/english.txt";
QString history = infoPath + "/history.txt";
QString cplusplus = infoPath + "/c++.txt";
QString number = infoPath + "/number.txt";
QString passWD = infoPath + "/passWD.txt";
QString sex = infoPath + "/sex.txt";
QString age = infoPath + "/age.txt";
QString college = infoPath + "/college.txt";
QFile file;
if(!file.exists(name))
{
QFile newFile(name);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(chinese))
{
QFile newFile(chinese);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(match))
{
QFile newFile(match);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(english))
{
QFile newFile(english);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(history))
{
QFile newFile(history);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(cplusplus))
{
QFile newFile(cplusplus);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(number))
{
QFile newFile(number);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(passWD))
{
QFile newFile(passWD);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(sex))
{
QFile newFile(sex);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(age))
{
QFile newFile(age);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
if(!file.exists(college))
{
QFile newFile(college);
newFile.open(QIODevice::WriteOnly);
newFile.close();
}
//建立存放数据的文件
//程序第一次运行是的初始数据
QFile nameFile(name);
nameFile.open(QIODevice::ReadWrite);
QTextStream rn(&nameFile);
if(rn.readAll().isEmpty())
{
for(int i = 0 ; i < 5 ; ++i)
{
QString ex("模板");
ex = ex + QString::number(i);
ex = ex + "\n";
rn<<ex;
}
}
nameFile.close();
}


examDelegate.h
#ifndef EXAMDELEGATE_H_
#define EXAMDELEGATE_H_
#include<QItemDelegate>
#include<QModelIndex>
#include<QPainter>
class examDelegate:public QItemDelegate
{
public:
examDelegate(QObject* parent = 0); //用于examModel的委托,用于输入成绩时,输入的大于100或小于0的数字,或者输入不为数字是提供(红字)提醒
void paint(QPainter* , const QStyleOptionViewItem& , const QModelIndex&)const;
QWidget* createEditor(QWidget* , const QStyleOptionViewItem& ,const QModelIndex&)const;
void setEditorData(QWidget* , const QModelIndex&)const;
void setModelData(QWidget* , QAbstractItemModel* , const QModelIndex&)const;
};
#endif


examDelegate.cxx
 
#include"examDelegate.h"
#include<QDebug>
examDelegate::examDelegate(QObject* parent):QItemDelegate(parent)
{
}
void examDelegate::paint(QPainter* painter , const QStyleOptionViewItem& option , const QModelIndex& index)const
{
QPen keepPen = painter->pen(); //保存画笔
if(index.column() != 0) //examModel第一列为姓名,不需要此委托
{
bool nu = true;
QString value = index.model()->data(index,Qt::DisplayRole).toString();
int realValue = value.toInt(&nu);
if(nu == false or realValue < 0 or realValue > 100) //委托条件 输入不为整数,或者整数不在0-100区间
painter->setPen(QPen(Qt::red)); //设置字体红色
painter->drawText(option.rect,Qt::AlignRight|Qt::AlignVCenter,value);
painter->setPen(keepPen); //画笔保持原因,用于别的item
}
else
QItemDelegate::paint(painter,option,index);
}
QWidget* examDelegate::createEditor(QWidget* widget, const QStyleOptionViewItem& option , const QModelIndex& index)const
{
return QItemDelegate::createEditor(widget,option,index);
}
void examDelegate::setEditorData(QWidget* widget , const QModelIndex& index)const
{
QItemDelegate::setEditorData(widget,index);
}
void examDelegate::setModelData(QWidget* widget , QAbstractItemModel* model, const QModelIndex& index)const
{
QItemDelegate::setModelData(widget,model,index);
}


examModel.h
#ifndef EXAMMODEL_H_
#define EXAMMODEL_H_
#include<QAbstractTableModel>
#include<QModelIndex>
#include<QVariant>
#include<QList>
#include<QVector>
class examModel:public QAbstractTableModel
{
Q_OBJECT
private:
QList<QString> names;
QVector<QString> classes;
QList<QString> chinese; //存放5门课的成绩
QList<QString> match;
QList<QString> english;
QList<QString> history;
QList<QString> cplusplus;
public:
examModel(QObject* parent = 0);
int rowCount(const QModelIndex&)const;
int columnCount(const QModelIndex&)const;
QVariant data(const QModelIndex& , int)const;
bool setData(const QModelIndex& , const QVariant& , int);
QVariant headerData(int , Qt::Orientation , int)const;
Qt::ItemFlags flags(const QModelIndex&)const;
void test(const QList<QString>&);
QList<QString> realName(); //向父窗体返回修改后的姓名
signals:
void updateName(const QModelIndex& , const QVariant&);
public slots:
void writeData(); //用于将数据写入硬盘文件./info/..
void deleteData(int); //删除一个学生信息(即删除一行)
void addNewData(); //添加一个空白行
void nameChanged(const QModelIndex& , const QVariant&);
};
#endif


examModel.cxx

#include<QFile>
#include<QDir>
#include<QTextStream>
#include"examModel.h"
examModel::examModel(QObject* parent):QAbstractTableModel(parent)
{
classes.push_back("姓名");
classes.push_back("中文");
classes.push_back("数学");
classes.push_back("英语");
classes.push_back("历史");
classes.push_back("C++");
}
int examModel::rowCount(const QModelIndex&)const
{
return names.size();
}
int examModel::columnCount(const QModelIndex&)const
{
return classes.size();
}
QVariant examModel::data(const QModelIndex& index , int role)const
{
if(!index.isValid()) //索引不可用
return QVariant();
if(role == Qt::TextAlignmentRole)
return QVariant(Qt::AlignRight|Qt::AlignVCenter);
if(role == Qt::DisplayRole)
{
if(index.column() == 0)
return names.at(index.row());
if(index.column() == 1)
return chinese.at(index.row());
if(index.column() == 2)
return match.at(index.row());
if(index.column() == 3)
return english.at(index.row());
if(index.column() == 4)
return history.at(index.row());
if(index.column() == 5)
return cplusplus.at(index.row());
}
return QVariant();
}
bool examModel::setData(const QModelIndex& index , const QVariant& value , int role)
{
if(index.isValid() and role == Qt::EditRole)
{
if(index.column() == 0)
{
emit updateName(index,value); //发射信号,通知info模型,数据已经改变
*(names.begin() + index.row()) = value.toString();
}
if(index.column() == 1)
*(chinese.begin() + index.row()) = value.toString();
if(index.column() == 2)
*(match.begin() + index.row()) = value.toString();
if(index.column() == 3)
*(english.begin() + index.row()) = value.toString();
if(index.column() == 4)
*(history.begin() + index.row()) = value.toString();
if(index.column() == 5)
*(cplusplus.begin() + index.row()) = value.toString();
emit dataChanged(index,index);
return true;
}
return false;
}
QVariant examModel::headerData(int sec , Qt::Orientation ct, int role)const
{
if(ct == Qt::Horizontal and role == Qt::DisplayRole)
return classes.at(sec);
if(ct == Qt::Vertical and role == Qt::DisplayRole)
return QVariant(sec+1);
return QVariant();
}
Qt::ItemFlags examModel::flags(const QModelIndex& index)const
{
Qt::ItemFlags fg = QAbstractItemModel::flags(index);
fg |= Qt::ItemIsEditable;
return fg;
}
void examModel::test(const QList<QString>& nm) //该函数用于设置模型的(初始)数据
{
beginResetModel();
names = nm;
QString paths = QDir::currentPath();
paths = paths + "/info";
QString chinesePath = paths + "/chinese.txt";
QString matchPath = paths + "/match.txt";
QString englishPath = paths + "/english.txt";
QString historyPath = paths + "/history.txt";
QString cplusplusPath = paths +"/c++.txt"; //获取数据存放文件的文件路 径

QFile chineseFile(chinesePath);
QFile matchFile(matchPath);
QFile englishFile(englishPath);
QFile historyFile(historyPath);
QFile cplusplusFile(cplusplusPath);

chineseFile.open(QIODevice::ReadOnly);
matchFile.open(QIODevice::ReadOnly);
englishFile.open(QIODevice::ReadOnly);
historyFile.open(QIODevice::ReadOnly);
cplusplusFile.open(QIODevice::ReadOnly);

QTextStream chineseIO(&chineseFile);
QTextStream matchIO(&matchFile);
QTextStream englishIO(&englishFile);
QTextStream historyIO(&historyFile);
QTextStream cplusplusIO(&cplusplusFile);

QString de = QString::number(0);
for(int i = 0 ; i < names.size() ; ++i)
{
if(!chineseIO.atEnd())
chinese.push_back(chineseIO.readLine());
else if(chineseIO.atEnd())
chinese.push_back(de); //使用默认数据,一方面方便显示,另一方面,防止写入数据时的越界问题
if(!matchIO.atEnd())
match.push_back(matchIO.readLine());
else if(matchIO.atEnd())
match.push_back(de);
if(!englishIO.atEnd())
english.push_back(englishIO.readLine());
else if(englishIO.atEnd())
english.push_back(de);
if(!historyIO.atEnd())
history.push_back(historyIO.readLine());
else if(historyIO.atEnd())
history.push_back(de);
if(!cplusplusIO.atEnd())
cplusplus.push_back(cplusplusIO.readLine());
else if(cplusplusIO.atEnd())
cplusplus.push_back(de);
}
endResetModel();
}
QList<QString> examModel::realName()
{
return names;
}
void examModel::writeData()
{
QString paths = QDir::currentPath();
paths = paths + "/info";
QString chinesePath = paths + "/chinese.txt";
QString matchPath = paths + "/match.txt";
QString englishPath = paths + "/english.txt";
QString historyPath = paths + "/history.txt";
QString cplusplusPath = paths +"/c++.txt"; //获取数据存放文件的文件路 径

QFile chineseFile(chinesePath);
QFile matchFile(matchPath);
QFile englishFile(englishPath);
QFile historyFile(historyPath);
QFile cplusplusFile(cplusplusPath);

chineseFile.open(QIODevice::WriteOnly);
matchFile.open(QIODevice::WriteOnly);
englishFile.open(QIODevice::WriteOnly);
historyFile.open(QIODevice::WriteOnly);
cplusplusFile.open(QIODevice::WriteOnly);

QTextStream chineseIO(&chineseFile);
QTextStream matchIO(&matchFile);
QTextStream englishIO(&englishFile);
QTextStream historyIO(&historyFile);
QTextStream cplusplusIO(&cplusplusFile);

for(int i = 0 ; i < names.size() ; ++i)
{
chineseIO<<chinese.at(i)<<"\n"; //换行符号用于下次读取文件的判断
matchIO<<match.at(i)<<"\n"; //由于读取是使用了默认值,所以不必单项at()越界的问题
englishIO<<english.at(i)<<"\n";
historyIO<<history.at(i)<<"\n";
cplusplusIO<<cplusplus.at(i)<<"\n";
}
}
void examModel::deleteData(int row)
{
beginResetModel();
names.erase(names.begin() + row); //删除一行,把改行所有数据均删除
chinese.erase(chinese.begin() + row);
match.erase(match.begin() + row);
english.erase(english.begin() + row);
history.erase(history.begin() + row);
cplusplus.erase(cplusplus.begin() + row);
endResetModel();
}
void examModel::addNewData()
{
beginResetModel();
QString de = QString::number(0);
names.push_back("模板"); //增加的空行均为默认数据
chinese.push_back(de);
match.push_back(de);
english.push_back(de);
history.push_back(de);
cplusplus.push_back(de);
endResetModel();
}
void examModel::nameChanged(const QModelIndex& index, const QVariant& value)
{
beginResetModel();
*(names.begin() + index.row()) = value.toString();
endResetModel();
}


infoDelegate.h

#ifndef INFODELEGATE_H_
#define INFODELGATE_H_
#include<QStyledItemDelegate>
#include<QModelIndex>
#include<QPainter>
#include<QComboBox>
class infoDelegate:public QStyledItemDelegate
{
public:
infoDelegate(QObject* parent = 0);
QWidget* createEditor(QWidget* parent , const QStyleOptionViewItem& , const QModelIndex&)const;
void setEditorData(QWidget* , const QModelIndex&)const;
void setModelData(QWidget* , QAbstractItemModel* , const QModelIndex&)const;
};
#endif



infoDelegate.cxx

#include"infoDelegate.h"
infoDelegate::infoDelegate(QObject* parent):QStyledItemDelegate(parent)
{
}
QWidget* infoDelegate::createEditor(QWidget* parent , const QStyleOptionViewItem& option, const QModelIndex& index)const
{
if(index.column() == 3) //第三行为infoModel的性别行,这里直接采用硬编码
{
QComboBox* sexBox = new QComboBox(parent);
sexBox->addItem(tr("男"));
sexBox->addItem(tr("女"));
return sexBox;
}
else if(index.column() == 5) //第五列为info的学院列,同样直接采取硬编码
{
QComboBox* collegeBox = new QComboBox(parent);
QStringList colleges;
colleges<<tr("机电学院")<<tr("外语学院")<<tr("政法学院")<<tr("体育学院")<<tr("能源学院")<<tr("艺术学院")<<tr("计算机学院")<<tr("地理学院");
collegeBox->addItems(colleges);
return collegeBox;
}
else return QStyledItemDelegate::createEditor(parent,option,index);
}
void infoDelegate::setEditorData(QWidget* editor , const QModelIndex& index)const
{
QStyledItemDelegate::setEditorData(editor,index);
}
void infoDelegate::setModelData(QWidget* editor , QAbstractItemModel* model , const QModelIndex& index)const
{
if(index.column() == 3)
{
QComboBox* sexEdit = qobject_cast<QComboBox*>(editor);
QString sex = sexEdit->currentText();
model->setData(index,sex);
}
if(index.column() == 5)
{
QComboBox* collegeEdit = qobject_cast<QComboBox*>(editor);
QString college = collegeEdit->currentText();
model->setData(index,college);
}
else QStyledItemDelegate::setModelData(editor,model,index);
}


infoModel.h

#ifndef INFOMODEL_H_
#define INFOMODEL_H_
#include<QAbstractTableModel>
#include<QList>
#include<QVector>
#include<QVariant>
#include<QModelIndex>
#include<QTextStream>
class infoModel:public QAbstractTableModel
{
Q_OBJECT
private:
QList<QString> names;
QVector<QString> info;
QList<QString> number; //这里学号即为学生登陆的账号
QList<QString> sex;
QList<int> age;
QList<QString> college;
public:
infoModel(QObject* parent = 0);
int rowCount(const QModelIndex&)const;
int columnCount(const QModelIndex&)const;
QVariant data(const QModelIndex& , int)const;
bool setData(const QModelIndex& , const QVariant& , int);
QVariant headerData(int , Qt::Orientation , int)const;
Qt::ItemFlags flags(const QModelIndex&)const;
void test(const QList<QString>&);
signals:
void updateName(const QModelIndex& , const QVariant&);
public slots:
void writeData(); //把数据写入硬盘文件,功能与infoModel的writeData()槽完全相同
void deleteData(int);
void addNewData();
void nameChanged(const QModelIndex& , const QVariant&);
};
#endif


infoModel.cxx

#include<QDir>
#include<QTextStream>
#include<QFile>
#include"infoModel.h"
QList<QString> passWD;
infoModel::infoModel(QObject* parent):QAbstractTableModel(parent)
{
info.push_back("姓名");
info.push_back("学号");
info.push_back("密码");
info.push_back("性别");
info.push_back("年龄");
info.push_back("学院");
}
int infoModel::rowCount(const QModelIndex&)const
{
return names.size();
}
int infoModel::columnCount(const QModelIndex&)const
{
return info.size();
}
QVariant infoModel::data(const QModelIndex& index , int role)const
{
if(!index.isValid())
return QVariant();
if(role == Qt::TextAlignmentRole)
return QVariant(Qt::AlignRight|Qt::AlignVCenter);
if(role == Qt::DisplayRole)
{
if(index.column() == 0)
return names.at(index.row());
if(index.column() == 1)
return number.at(index.row());
if(index.column() == 2)
return passWD.at(index.row());
if(index.column() == 3)
return sex.at(index.row());
if(index.column() == 4)
return age.at(index.row());
if(index.column() == 5)
return college.at(index.row());
}
return QVariant();
}
bool infoModel::setData(const QModelIndex& index , const QVariant& value , int role)
{
if(index.isValid() and role == Qt::EditRole)
{
if(index.column() == 0)
{
emit updateName(index,value); //通知exam模型,姓名数据已经更改
*(names.begin() + index.row()) = value.toString();
}
if(index.column() == 1)
*(number.begin() + index.row()) = value.toString();
if(index.column() == 2)
*(passWD.begin() + index.row()) = value.toString();
if(index.column() == 3)
*(sex.begin() + index.row()) = value.toString();
if(index.column() == 4)
*(age.begin() + index.row()) = value.toInt();
if(index.column() == 5)
*(college.begin() + index.row()) = value.toString();
emit dataChanged(index,index);
return true;
}
return false;
}
QVariant infoModel::headerData(int sec , Qt::Orientation ns, int role)const
{
if(role == Qt::DisplayRole and ns == Qt::Horizontal)
return info.at(sec);
if(role == Qt::DisplayRole and ns == Qt::Vertical)
return sec+1;
return QVariant();
}
Qt::ItemFlags infoModel::flags(const QModelIndex& index)const
{
Qt::ItemFlags fg = QAbstractItemModel::flags(index);
fg |= Qt::ItemIsEditable;
return fg;
}
void infoModel::test(const QList<QString>& nm)
{
beginResetModel();
names = nm;
QString paths = QDir::currentPath();
paths = paths +"/info";
QString numberPath = paths + "/number.txt";
QString passWDPath = paths + "/passWD.txt";
QString sexPath = paths + "/sex.txt";
QString agePath = paths + "/age.txt";
QString collegePath = paths + "/college.txt"; //获得数据存放文件路径

QFile numberFile(numberPath);
QFile passWDFile(passWDPath);
QFile sexFile(sexPath);
QFile ageFile(agePath);
QFile collegeFile(collegePath);

numberFile.open(QIODevice::ReadOnly);
passWDFile.open(QIODevice::ReadOnly);
sexFile.open(QIODevice::ReadOnly);
ageFile.open(QIODevice::ReadOnly);
collegeFile.open(QIODevice::ReadOnly);

QTextStream numberIO(&numberFile);
QTextStream passWDIO(&passWDFile);
QTextStream sexIO(&sexFile);
QTextStream ageIO(&ageFile);
QTextStream collegeIO(&collegeFile);

for(int i = 0 ; i < names.size() ; ++i)
{
if(!numberIO.atEnd())
number.push_back(numberIO.readLine());
else if(numberIO.atEnd())
number.push_back("000000");
if(!passWDIO.atEnd())
passWD.push_back(passWDIO.readLine());
else if(passWDIO.atEnd())
passWD.push_back("12345");
if(!sexIO.atEnd())
sex.push_back(sexIO.readLine());
else if(sexIO.atEnd())
sex.push_back("男");
if(!ageIO.atEnd())
age.push_back(ageIO.readLine().toInt());
else if(ageIO.atEnd())
age.push_back(20);
if(!collegeIO.atEnd())
college.push_back(collegeIO.readLine());
else if(collegeIO.atEnd())
college.push_back("机电学院");
}
endResetModel();
}
void infoModel::writeData()
{
QString paths = QDir::currentPath();
paths = paths +"/info";
QString numberPath = paths + "/number.txt";
QString passWDPath = paths + "/passWD.txt";
QString sexPath = paths + "/sex.txt";
QString agePath = paths + "/age.txt";
QString collegePath = paths + "/college.txt"; //获得数据存放文件路径

QFile numberFile(numberPath);
QFile passWDFile(passWDPath);
QFile sexFile(sexPath);
QFile ageFile(agePath);
QFile collegeFile(collegePath);

numberFile.open(QIODevice::WriteOnly);
passWDFile.open(QIODevice::WriteOnly);
sexFile.open(QIODevice::WriteOnly);
ageFile.open(QIODevice::WriteOnly);
collegeFile.open(QIODevice::WriteOnly);

QTextStream numberIO(&numberFile);
QTextStream passWDIO(&passWDFile);
QTextStream sexIO(&sexFile);
QTextStream ageIO(&ageFile);
QTextStream collegeIO(&collegeFile);

for(int i = 0 ; i < names.size() ; ++i)
{
numberIO<<number.at(i)<<"\n";
passWDIO<<passWD.at(i)<<"\n";
sexIO<<sex.at(i)<<"\n";
ageIO<<age.at(i)<<"\n";
collegeIO<<college.at(i)<<"\n";
}
}
void infoModel::deleteData(int i)
{
beginResetModel();
names.erase(names.begin()+i);
number.erase(number.begin()+i);
passWD.erase(passWD.begin()+i);
sex.erase(sex.begin()+i);
age.erase(age.begin()+i);
college.erase(college.begin()+i);
endResetModel();
}
void infoModel::addNewData()
{
beginResetModel();
names.push_back("模板");
number.push_back("111111");
passWD.push_back("000000");
sex.push_back("男");
age.push_back(20);
college.push_back("机电学院");
endResetModel();
}
void infoModel::nameChanged(const QModelIndex& index , const QVariant& value)
{
beginResetModel();
*(names.begin() + index.row()) = value.toString();
endResetModel();
}


loginBox.h

#ifndef LOGINBOX_H_
#define LOGINBOX_H_
#include<QDialog>
#include<QPushButton>
#include<QLabel>
#include<QGroupBox>
#include<QLineEdit>
#include"teacherDialog.h"
#include"lookDialog.h"
class loginBox:public QDialog
{
Q_OBJECT
private:
QList<QString> number;
QList<QString> passWD;
teacherDialog* teacher;
lookDialog* looker; // :)
QGroupBox* login_group;
QLabel* account_label;
QLabel* passWD_label;
QLineEdit* account_edit;
QLineEdit* passWD_edit;
QPushButton* login_button;
QPushButton* close_button;
void getInfo(); //读取姓名和密码
public:
loginBox(QWidget* parent = 0);
signals:
void findStudent(int);
private slots:
void login();
void reLoad();
};
#endif


loginBox.cxx

#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QList>
#include<QDir>
#include<QFile>
#include<QTextStream>
#include<QMessageBox>
#include"loginBox.h"
loginBox::loginBox(QWidget* parent):QDialog(parent)
{
getInfo(); //获得姓名和密码

teacher = new teacherDialog(this);
looker = new lookDialog(this);

login_group = new QGroupBox(tr("登陆"));
account_label = new QLabel(tr("账号"));
passWD_label = new QLabel(tr("密码"));
account_edit = new QLineEdit;
passWD_edit = new QLineEdit;
passWD_edit->setEchoMode(QLineEdit::Password); //确保出入密码都显示****
login_button = new QPushButton(tr("登陆"));
close_button = new QPushButton(tr("退出"));
//布局
QHBoxLayout* account_layout = new QHBoxLayout;
account_layout->addWidget(account_label);
account_layout->addWidget(account_edit);
QHBoxLayout* passWD_layout = new QHBoxLayout;
passWD_layout->addWidget(passWD_label);
passWD_layout->addWidget(passWD_edit);
QVBoxLayout* login_layout = new QVBoxLayout;
login_layout->addLayout(account_layout);
login_layout->addLayout(passWD_layout);
login_group->setLayout(login_layout);
QHBoxLayout* button_layout = new QHBoxLayout;
button_layout->addStretch();
button_layout->addWidget(login_button);
button_layout->addWidget(close_button);
QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addWidget(login_group);
main_layout->addLayout(button_layout);
//安装布局,设置标题等
setLayout(main_layout);
setWindowIcon(QIcon(tr(":/images/read.png")));
main_layout->setSizeConstraint(QLayout::SetFixedSize);
setWindowTitle(tr("欢迎来到学生管理系统"));
//信号与槽
connect(login_button,SIGNAL(clicked()),this,SLOT(login()));
connect(close_button,SIGNAL(clicked()),this,SLOT(close()));
connect(teacher,SIGNAL(hasLeave()),this,SLOT(close()));
connect(looker,SIGNAL(hasleave()),this,SLOT(close()));
connect(this,SIGNAL(findStudent(int)),looker,SLOT(looking(int)));
}
void loginBox::getInfo()
{
QString paths = QDir::currentPath();
QString numberPath = paths + "/info/number.txt";
QString passWDPath = paths + "/info/passWD.txt";

QFile numberFile(numberPath);
QFile passWDFile(passWDPath);

QTextStream numberIO(&numberFile);
QTextStream passWDIO(&passWDFile);

numberFile.open(QIODevice::ReadOnly);
passWDFile.open(QIODevice::ReadOnly);

while(!numberIO.atEnd())
{
number.push_back(numberIO.readLine());
passWD.push_back(passWDIO.readLine());
}
}
void loginBox::login()
{
QString teachAccount("teacher");
QString teachpassWD("123456"); //先判断登陆的是不是老师
if(account_edit->text() == teachAccount and passWD_edit->text() == teachpassWD)
{
teacher->show();
hide();
return;
}
QString acc = account_edit->text();
QString pd = passWD_edit->text();
for(int i = 0 ; i < number.size() ; ++i) //学生登陆
{
if(acc == number.at(i) and pd == passWD.at(i))
{
looker->show();
hide();
emit findStudent(i);
return;
}
}
reLoad();
}
void loginBox::reLoad()
{
account_edit->clear();
passWD_edit->clear();
QMessageBox::warning(this,tr("warning"),tr("账号或密码错误"),QMessageBox::Yes);
}


lookDialog.h
#ifndef LOOKDIALOG_H_
#define LOOKDIALOG_H_
#include<QDialog>
#include<QGroupBox>
#include<QLineEdit>
#include<QPushButton>
#include<QTableWidget>
#include<QLabel>
#include<QCloseEvent>
class lookDialog:public QDialog
{
Q_OBJECT
private:
int t; //标记显示的是第几个学生
bool pd; //确定更换密码框是影藏还是显示状态
QList<QString> names;
QList<QString> passWD; //这2个用于从文件读取姓名和密码信息
QTableWidget* showInfo;
QPushButton* code_button;
QPushButton* finish_button;
QPushButton* close_button;
QGroupBox* passWD_group;
QLabel* old_label;
QLabel* new_label;
QLabel* config_label;
QLineEdit* old_edit;
QLineEdit* new_edit;
QLineEdit* config_edit;
void getInfo(); //用于读取姓名和密码
public:
lookDialog(QWidget* parent);
protected:
void closeEvent(QCloseEvent*);
signals:
void hasleave(); //关闭是发射该信号,由父窗体来关闭整个程序
private slots:
void changeCode(); //更换密码函数
void newPassWD();
void looking(int); //显示某位学生信息
};
#endif


lookDialog.cxx

#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QTableWidgetItem>
#include<QStringList>
#include<QList>
#include<QDir>
#include<QFile>
#include<QTextStream>
#include<QMessageBox>
#include"lookDialog.h"
lookDialog::lookDialog(QWidget* parent):QDialog(parent),t(-1),pd(true)
{
QStringList heads;
heads<<tr("语文")<<tr("数学")<<tr("英语")<<tr("历史")<<tr("C++");
showInfo = new QTableWidget;
showInfo->setRowCount(1);
showInfo->setColumnCount(5);
showInfo->setHorizontalHeaderLabels(heads);
showInfo->setEditTriggers(QAbstractItemView::NoEditTriggers); //禁止编辑
for(int i = 0 ; i < 5 ; ++i)
showInfo->setItem(0,i,new QTableWidgetItem); //这里使用硬编码直接获得显示课目的数量,名称等
showInfo->setFixedSize(520,100);

code_button = new QPushButton(tr("更换密码"));
finish_button = new QPushButton(tr("完成"));
close_button = new QPushButton(tr("关闭"));
passWD_group = new QGroupBox(tr("更换密码"));
old_label = new QLabel(tr("原密码"));
new_label = new QLabel(tr("新密码"));
config_label = new QLabel(tr("确认新密码"));
old_edit = new QLineEdit;
old_edit->setEchoMode(QLineEdit::Password);
new_edit = new QLineEdit;
new_edit->setEchoMode(QLineEdit::Password);
config_edit = new QLineEdit;
config_edit->setEchoMode(QLineEdit::Password);
//布局
QHBoxLayout* new_layout = new QHBoxLayout; //下部密码更换框布局
new_layout->addWidget(new_label);
new_layout->addStretch();
new_layout->addWidget(new_edit);
QHBoxLayout* old_layout = new QHBoxLayout;
old_layout->addWidget(old_label);
old_layout->addStretch();
old_layout->addWidget(old_edit);
QHBoxLayout* config_layout = new QHBoxLayout;
config_layout->addWidget(config_label);
config_layout->addStretch();
config_layout->addWidget(config_edit);

QVBoxLayout* finish_layout = new QVBoxLayout;
finish_layout->addStretch();
finish_layout->addWidget(finish_button);

QVBoxLayout* group_layout = new QVBoxLayout;
group_layout->addLayout(old_layout);
group_layout->addLayout(new_layout);
group_layout->addLayout(config_layout);

QHBoxLayout* passWD_layout = new QHBoxLayout;
passWD_layout->addLayout(group_layout);
passWD_layout->addLayout(finish_layout);
passWD_group->setLayout(passWD_layout);

QHBoxLayout* button_layout = new QHBoxLayout;
button_layout->addStretch();
button_layout->addWidget(code_button);
button_layout->addWidget(close_button);

QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addWidget(showInfo);
main_layout->addLayout(button_layout);
main_layout->addWidget(passWD_group);
passWD_group->hide();
//信号与槽
connect(code_button,SIGNAL(clicked()),this,SLOT(changeCode()));
connect(close_button,SIGNAL(clicked()),this,SLOT(close()));
connect(finish_button,SIGNAL(clicked()),this,SLOT(newPassWD()));
//安装布局,设置标题
setLayout(main_layout);
main_layout->setSizeConstraint(QLayout::SetFixedSize);

getInfo(); //从文件读取姓名,密码
}
void lookDialog::getInfo()
{
QString paths = QDir::currentPath();
QString namePath = paths + "/info/name.txt";
QString passWDPath = paths + "/info/passWD.txt";

QFile nameFile(namePath);
QFile passWDFile(passWDPath);

QTextStream nameIO(&nameFile);
QTextStream passWDIO(&passWDFile);

nameFile.open(QIODevice::ReadOnly);
passWDFile.open(QIODevice::ReadOnly);

while(!nameIO.atEnd())
{
names.push_back(nameIO.readLine());
passWD.push_back(passWDIO.readLine());
}
}
void lookDialog::closeEvent(QCloseEvent*)
{
emit hasleave();
}
void lookDialog::changeCode()
{
if(pd == true)
{
code_button->setText(tr("取消更改"));
passWD_group->show();
pd = false;
}
else if(pd == false)
{
code_button->setText(tr("修改密码"));
passWD_group->hide();
old_edit->clear();
new_edit->clear();
config_edit->clear();
pd = true;
}
}
void lookDialog::newPassWD()
{
if(passWD.at(t) != old_edit->text())
{
QMessageBox::warning(this,tr("warning"),tr("原密码错误"),QMessageBox::Yes);
return;
}
if(new_edit->text() != config_edit->text())
{
QMessageBox::warning(this,tr("warning"),tr("两次密码输入不一样"),QMessageBox::Yes);
return;
}
//确认密码更换正确后把密码写入文件
*(passWD.begin() + t) = new_edit->text();
QString paths = QDir::currentPath() + "/info/passWD.txt";
QFile newCode(paths);
newCode.open(QIODevice::WriteOnly);
QTextStream newCodeIO(&newCode);
for(int i = 0 ; i < names.size() ; ++i)
newCodeIO<<passWD.at(i)<<"\n";
//完成后清空密码输入框
old_edit->clear();
new_edit->clear();
config_edit->clear();
QMessageBox::information(this,tr("info"),tr("密码重置完成"),QMessageBox::Yes);
}
void lookDialog::looking(int pi)
{
t = pi; //这是第pi个学生
QString titles = "亲爱的";
titles +=names.at(pi);
titles += "同学";
setWindowTitle(titles);
QString paths = QDir::currentPath();

QString chinese = paths + "/info/chinese.txt"; //获取存放成绩数据 的文件路径
QString match = paths + "/info/match.txt";
QString english = paths + "/info/english.txt";
QString history = paths + "/info/history.txt";
QString cplusplus = paths + "/info/c++.txt";

QFile chineseFile(chinese);
QFile matchFile(match);
QFile englishFile(english);
QFile historyFile(history);
QFile cplusplusFile(cplusplus);

chineseFile.open(QIODevice::ReadOnly);
matchFile.open(QIODevice::ReadOnly);
englishFile.open(QIODevice::ReadOnly);
historyFile.open(QIODevice::ReadOnly);
cplusplusFile.open(QIODevice::ReadOnly);

QTextStream chineseIO(&chineseFile);
QTextStream matchIO(&matchFile);
QTextStream englishIO(&englishFile);
QTextStream historyIO(&historyFile);
QTextStream cplusplusIO(&cplusplusFile);

QString chi = "";
QString mat = "";
QString eng = "";
QString his = "";
QString cpl = "";
int i = 0;
while(1)
{
chi = chineseIO.readLine();
mat = matchIO.readLine();
eng = englishIO.readLine();
his = historyIO.readLine();
cpl = cplusplusIO.readLine();
if(i == pi)
break;
++i;
}
showInfo->item(0,0)->setText(chi);
showInfo->item(0,1)->setText(mat);
showInfo->item(0,2)->setText(eng);
showInfo->item(0,3)->setText(his);
showInfo->item(0,4)->setText(cpl);
}


teacherDialog.h

#ifndef TEACHERDIALOG_H_
#define TEACHERDIALOG_H_
#include<QDialog>
#include<QTabWidget>
#include<QPushButton>
#include<QTableView>
#include<QList>
#include<QCloseEvent>
#include"examModel.h"
#include"infoModel.h"
class teacherDialog:public QDialog
{
Q_OBJECT
private:
QList<QString> names; //存放2个模型的公用数据 姓名
QTabWidget* show_widget;
examModel* exam_model;
infoModel* info_model;
QTableView* exam_view;
QTableView* info_view;
QPushButton* add_button;
QPushButton* delete_button;
QPushButton* write_button;
QPushButton* close_button;
void getName(); //从本地文件中读取学生姓名
public:
teacherDialog(QWidget* parent = 0);
protected:
void closeEvent(QCloseEvent*);
signals:
void hasLeave();
void deleteExamData(int);
void deleteInfoData(int);
private slots:
void writeData();
void getDeleteData(); //获得当前选定的item的index
};
#endif


teacherDialog.cxx
#include<QHBoxLayout>
#include<QVBoxLayout>
#include<QDir>
#include<QFile>
#include<QTextStream>
#include<QHeaderView>
#include"teacherDialog.h"
#include"examDelegate.h"
#include"infoDelegate.h"
teacherDialog::teacherDialog(QWidget* parent):QDialog(parent)
{
getName(); //优先读取学生名字
show_widget = new QTabWidget;

exam_view = new QTableView;
exam_model = new examModel;
exam_view->setModel(exam_model);
exam_view->setItemDelegate(new examDelegate); //设置委托
exam_model->test(names);

info_view = new QTableView;
info_model = new infoModel;
info_view->setModel(info_model);
info_view->setItemDelegate(new infoDelegate); //设置委托
info_model->test(names);
//把2个视图装到QTabWidget上
QString exam("学生成绩");
QString info("学生信息");
show_widget->addTab(exam_view,exam);
show_widget->addTab(info_view,info);
show_widget->setCurrentWidget(info_view);

add_button = new QPushButton(tr("添加"));
delete_button = new QPushButton(tr("删除"));
write_button = new QPushButton(tr("写入"));
close_button = new QPushButton(tr("关闭"));

delete_button->setIcon(QIcon(tr(":/images/delete.png")));
write_button->setIcon(QIcon(tr(":/images/write.png")));
//这2个相互的信号用于同步2个模型中的姓名数据
connect(info_model,SIGNAL(updateName(const QModelIndex& , const QVariant&)),exam_model,SLOT(nameChanged(const QModelIndex& , const QVariant&)));
connect(exam_model,SIGNAL(updateName(const QModelIndex& , const QVariant&)),info_model,SLOT(nameChanged(const QModelIndex& , const QVariant&)));

connect(add_button,SIGNAL(clicked()),exam_model,SLOT(addNewData()));
connect(add_button,SIGNAL(clicked()),info_model,SLOT(addNewData()));
connect(delete_button,SIGNAL(clicked()),this,SLOT(getDeleteData()));
connect(write_button,SIGNAL(clicked()),this,SLOT(writeData()));
connect(write_button,SIGNAL(clicked()),info_model,SLOT(writeData()));
connect(write_button,SIGNAL(clicked()),exam_model,SLOT(writeData()));
connect(close_button,SIGNAL(clicked()),this,SLOT(close()));

connect(this,SIGNAL(deleteExamData(int)),exam_model,SLOT(deleteData(int)));
connect(this,SIGNAL(deleteInfoData(int)),info_model,SLOT(deleteData(int)));
//布局安装
QHBoxLayout* button_layout = new QHBoxLayout;
button_layout->addWidget(delete_button);
button_layout->addStretch();
button_layout->addWidget(add_button);
button_layout->addWidget(write_button);
button_layout->addWidget(close_button);

QVBoxLayout* main_layout = new QVBoxLayout;
main_layout->addWidget(show_widget);
main_layout->addLayout(button_layout);

setLayout(main_layout);
setFixedSize(650,600);
setWindowTitle(tr("学生详情"));
}
void teacherDialog::closeEvent(QCloseEvent*)
{
emit hasLeave();
hide();
}
void teacherDialog::getName()
{
QString paths = QDir::currentPath();
paths = paths + "/info/name.txt";
QFile nameFile(paths);
nameFile.open(QIODevice::ReadOnly);
QTextStream nameIO(&nameFile);
while(!nameIO.atEnd())
names.push_back(nameIO.readLine());
}
void teacherDialog::writeData()
{
names = exam_model->realName(); //从模型获得修改后的姓名信息
QString paths = QDir::currentPath();
paths = paths + "/info/name.txt";
QFile nameFile(paths);
nameFile.open(QIODevice::WriteOnly);
QTextStream nameIO(&nameFile);
for(int i = 0 ; i < names.size() ; ++i)
nameIO<<names.at(i)<<"\n";
}
void teacherDialog::getDeleteData()
{
int e = 0;
if(show_widget->currentIndex() == 0 and exam_view->currentIndex().isValid())
e = exam_view->currentIndex().row();
else if(show_widget->currentIndex() == 1 and info_view->currentIndex().isValid())
e = info_view->currentIndex().row();
emit deleteExamData(e);
emit deleteInfoData(e);
}


main.cxx

#include<QApplication>
#include"buildFile.h"
#include"loginBox.h"
int main(int argc , char** argv)
{
QApplication app(argc,argv);
buildFile();
loginBox A;
A.show();
return app.exec();
}


pix.qrc

<RCC>
<qresource>
<file>images/read.png</file>
<file>images/delete.png</file>
<file>images/write.png</file>
</qresource>
</RCC>