程序启动后是个登陆框,很简单
这个系统我做了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>