观前提要: 本项目是大学学习Qt时的结课作业,发出来记录一下(博客=大型网盘),所以技术上并不适合正式使用,仅学习参考
其中的数据库内容很稀烂,全是自己瞎鼓捣的,所以非常复杂繁琐
类的使用也很稀烂,本人在做这个时没学C++,有关这些部分基本上是参考+改编
内容概览
基本功能
- 使用QSQLITE数据库完成数据库的设计。
- 注册功能:包含学生注册,教师教辅人员注册,实验室管理员注册。
- 忘记密码的功能。
- 学生和老师以及实验室管理员的分别登陆后的权限不同,进入到不同的管理页面。
- 管理员页面可以完成实验室教师信息的增删改查功能。
- 学生注册后管理员可以查看修改删除学生的信息
- 管理员界面完成实验室分布情况的增删改查功能,提供实验室可以预约的人数。
- 学生注册登录后可以实现学生信息的完善,学生只可以查看和修改自己的信息,不可删除。
- 学生端完成实验室课程的预约,每一个学生完成预约,数据库中的可预约人数相应减少一个,只到实验室人数预约满了,该实验室不可再预约。
其他花里胡哨的小功能放下一期
1.显示密码/隐藏密码
2. 将成功登录的账号加入下拉框,以便下一次登录
3.ui设计
流程图(这个很有点水,不建议看,当时为了交作业粗制滥造的)
功能实现
数据库连接
数据库连接
// 数据库连接
CreatDatabase();
bool ok = db.open();
if (ok)
{
qDebug() << "database connect is ok";
}
else
{
qDebug() << "database connect is fail";
}
createTable("CREATE TABLE admin(id INTEGER PRIMARY KEY,name TEXT,password varchar(20),role int)");
createTable("CREATE TABLE student(id INTEGER PRIMARY KEY,name TEXT,institute TEXT,password varchar(20),role int,labid int)");
createTable("CREATE TABLE teacher(id INTEGER PRIMARY KEY,name TEXT,password varchar(20),role int)");
createTable("CREATE TABLE lab(id INTEGER PRIMARY KEY,name TEXT,total int,num int)");
创建数据库函数
// 创建数据库函数
void login::CreatDatabase()
{
// 创建一个数据库连接,指定数据库驱动
db = QSqlDatabase::addDatabase("QSQLITE");
// 数据库连接需要设置的信息
db.setHostName("127.0.0.1"); // 数据库服务器IP,我用的是本地电脑
db.setDatabaseName("Labsys.db");// 数据库名
db.setUserName("root");// 用户名
db.setPassword("123456");// 密码
db.setPort(3306);// 端口号
}
建表函数
// 建表函数
void login::createTable(QString SQLcreateTable)
{
// 创建一个表
QString sql = SQLcreateTable;
// 实例化QSqlQuery,用于执行sql语句
QSqlQuery sq;
if(sq.exec(sql)){ //执行SQL的成功or失败
qDebug()<<"建表成功!";
}else{
qDebug()<<sq.lastError().text(); //输出错误信息
}
}
注册页面(signup)
(数据库在登录页面)
- 通过对comboBox_ide的检索,判断注册的身份
- 用3个if分别插入数据库(每个if里insert的表不同,和随机生成的学工号长度不同)
- 用随机数生成学工号长度,管理员为2位,教师为4位,学生为7位
- 注册成功弹出新窗口,上面通过父窗口向子窗口传值的方法(getLastWindow函数)将随机生成的学工号和用户输入的姓名密码显示在新窗口(succeed)上,实现反馈效果
参考:父窗口向子窗口传值
注册功能:包含学生注册,教师教辅人员注册,实验室管理员注册。
// 注册功能
void signup::on_pbt_signup_clicked()
{
int flag1 = ui->comboBox_ide->currentIndex();
if(flag1 == 0){
int role = 0;
int id = generateRandomNumber(1,99); //在1到99内生成一个数
QString name = ui->lineEdit_name->text();
QString password = ui->lineEdit_password->text();
if(name == "")
QMessageBox::warning(this,"","学工号不能为空!");
else if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = insertadmin(db,id,name,password,role);
if(flag){
succeed *page_succeed = new succeed();
page_succeed->getLastWindow(role,id,name,password);
page_succeed->show();
this->hide();
connect(page_succeed,&succeed::back,[=](){
page_succeed->close();
this->show();
emit this->back();
});
}else
QMessageBox::information(this,tr("提示"),tr("注册失败!"));
}
}else if(flag1 == 1){
int role = 1;
int id = generateRandomNumber(1001,9999);//在1001到9999内生成一个数
QString name = ui->lineEdit_name->text();
QString password = ui->lineEdit_password->text();
if(name == "")
QMessageBox::warning(this,"","学工号不能为空!");
else if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = insertteach(db,id,name,password,role);
if(flag){
succeed *page_succeed = new succeed();
page_succeed->getLastWindow(role,id,name,password);
page_succeed->show();
this->hide();
connect(page_succeed,&succeed::back,[=](){
page_succeed->close();
this->show();
emit this->back();
});
}
else
QMessageBox::information(this,tr("提示"),tr("注册失败!"));
}
}else if(flag1 == 2){
int role = 2;
int id = generateRandomNumber(1000001,9999999);//在1000001到9999999内生成一个数
QString name = ui->lineEdit_name->text();
QString password = ui->lineEdit_password->text();
if(name == "")
QMessageBox::warning(this,"","学工号不能为空!");
else if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = insertstud(db,id,name,password,role);
if(flag){
succeed *page_succeed = new succeed();
page_succeed->getLastWindow(role,id,name,password);
page_succeed->show();
this->hide();
connect(page_succeed,&succeed::back,[=](){
page_succeed->close();
this->show();
emit this->back();
});
}
else
QMessageBox::information(this,tr("提示"),tr("注册失败!"));
}
}
}
相关函数
// 插入注册信息到数据库
int signup::insertadmin(QSqlDatabase db,const int &userid, QString &name,const QString &password,int &role)
{
QSqlQuery query(db);
query.prepare("INSERT INTO admin (id,name,password,role) VALUES (:id,:name,:password,:role)");
query.bindValue(":id", userid);
query.bindValue(":name", name);
query.bindValue(":password",password);
query.bindValue(":role",role);
query.exec();
}
// 生成随机数
int signup::generateRandomNumber(int min,int max) //在min和max内生成一个随机数
{
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()));
int num = qrand()%(max-min)+min;
qDebug()<<num;
return num;
}
找回密码(re_pwd)
1.通过检测输入框和数据库信息匹对,如果成功就将数据库内密码更新为新密码
这个功能非常半成品,检测什么都没做,如果要完善的话可以加一个验证邮箱或者验证密保(数据库里面又要加一栏了)。还可以结合网络通信搞个验证码验证(我不会)
修改密码
// 修改密码
bool re_pwd::MatchData()
{
int flag1 = ui->comboBox_ide->currentIndex();
QSqlQuery query;
int userid = ui->lineEdit_id->text().toUInt();
QString password = ui->lineEdit_password->text();
bool found = false;
if(flag1 == 0){
if(QString::number(userid) == "")
QMessageBox::warning(this,"","学工号不能为空!");
else
if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = updateadmin(db,userid, password);
if(flag){
QMessageBox::information(this,"","密码修改成功!");
}else
QMessageBox::warning(this,"","学工号信息不匹配!");
}
}else if(flag1 == 1){
if(QString::number(userid) == "")
QMessageBox::warning(this,"","学工号不能为空!");
else
if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = updateteach(db,userid, password);
if(flag){
QMessageBox::information(this,"","密码修改成功!");
}else
QMessageBox::warning(this,"","学工号信息不匹配!");
}
}else if(flag1 == 2){
if(QString::number(userid) == "")
QMessageBox::warning(this,"","学工号不能为空!");
else
if(password == "")
QMessageBox::warning(this,"","密码不能为空!");
else{
bool flag = updatestud(db,userid, password);
if(flag){
QMessageBox::information(this,"","密码修改成功!");
}else
QMessageBox::warning(this,"","学工号信息不匹配!");
}
}
}
相关函数:
// 更新数据(修改数据)
bool re_pwd::updatestud(QSqlDatabase db, const int &userid, const QString &password)
{
QSqlQuery query(db);
query.prepare("UPDATE admin SET password=:password WHERE id=:id");
query.bindValue(":id", userid);
query.bindValue(":password",password);
query.exec();
}
登录(login)
老师和管理员登录:判断id输入的长度,然后到相应数据库表里面检索,若成功则跳转对应页面(3个if语句)。用getLastWindow函数(注册页面里面也用了)将对应的名字显示到下一个页面里(这里用学生登录里面的ini文件一样实现,并且更简单)
学生登录:通过ini配置文件的读写, 每次登录的时候通过输入的id号查找数据库,再将数据库里面数据写入配置文件,新页面加载后对配置文件进行读取,实现两个页面对应数据传递
// 因为登录后有修改信息的步骤,需要一个ini作为过渡文件方便检测是谁在登录,这是后面写到这一步的时候出现的问题,以至于和前面老师和管理员的写法不同
管理员页面 (admin) 增删改查
显示表格:tableWidget
对表格clear(防止重复出现和删除不掉)然后从对应表格中SELECT 全部(分别对学生,老师,实验室建了3个检索函数)
通过CountRowTch函数查找对应表行数的,通过对tableWidget 填入数据之前先setRowCount(设置行数)来实现每次表格长度根据被查表格总数据数量进行自动增长
建学生表(老师和实验室类似)
// 建表
ui->stackedWidget->setCurrentIndex(0);
//学生表
ui->tableWidget->setRowCount(10);//设置行数
ui->tableWidget->setColumnCount(3);//设置列数
ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"学号"<< "姓名"<< "密码");//设置表头
ui->tableWidget->setColumnWidth(0,130);//设置列宽
ui->tableWidget->setColumnWidth(1,130);
ui->tableWidget->setColumnWidth(2,130);
ui->tableWidget->setColumnWidth(3,70);
ui->tableWidget->setColumnWidth(4,70);
ui->tableWidget->setColumnWidth(5,70);
ui->tableWidget->setColumnWidth(6,70);
//隔行变色
ui->tableWidget->setAlternatingRowColors(true);
//设置全部单元格可编辑
ui->tableWidget->setEditTriggers(QAbstractItemView::DoubleClicked);
//表格横向自适应
ui->tableWidget->horizontalHeader()->setSectionResizeMode((QHeaderView::Stretch));
将数据显示在表格中
// 显示数据
void admin::FindStu()
{
ui->tableWidget->clear();
ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"学号"<< "姓名"<< "密码");//设置表头
QSqlQuery query;
query.exec("SELECT * FROM student ORDER BY id ASC"); //data 为表名 10代表获取10条数据
int t_rowCount = CountRowStu();
ui->tableWidget->setRowCount(t_rowCount+3);
for(int i=0;i<10;i++)
{
query.next();
QString id = query.value("id").toString();
QString name = query.value("name").toString();
QString password = query.value("password").toString();
int j=0;
ui->tableWidget->setItem(i,j, new QTableWidgetItem(id));//第i行第j列
j++;
ui->tableWidget->setItem(i,j, new QTableWidgetItem(name));
j++;
ui->tableWidget->setItem(i,j, new QTableWidgetItem(password));
j++;
}
}
增:
将id和name两个输入框的值保留,进行if判断:若password为空则设置默认密码123456.不为空将输入的值保留,最后将3个值一起insert插入表格
新增数据
// 新增数据
void admin::on_pbt_insertTch_clicked()
{
QSqlQuery query;
int id = ui->Edit_idtch->text().toInt();
QString name = ui->Edit_nametch->text();
int role = 1;
if(ui->Edit_pwdtch->text().isEmpty())
{
QString pwd = QString("123456");
QString sqlInert = QString("INSERT INTO teacher(id,name,password,role) VALUES (%1,'%2','%3',%4);").arg(id)
.arg(name)
.arg(pwd)
.arg(role);
query.exec(sqlInert);
}
else
{
QString pwd = ui->Edit_pwdtch->text();
QString sqlInert = QString("INSERT INTO teacher(id,name,password,role) VALUES (%1,'%2','%3',%4);").arg(id)
.arg(name)
.arg(pwd)
.arg(role);
query.exec(sqlInert);
}
FindTch();
}
删:
对学工号进行查找,查找到后在数据库中delete删除,最后刷新一下显示的表
// 删除数据
void admin::on_pbt_deleteTch_clicked()
{
QSqlQuery query;
int id = ui->Edit_idtch->text().toInt();
if(ui->Edit_idtch->text().isEmpty())
{
QMessageBox::warning(this,"","请输入要删除的学工号");
}
else
{
QString sqlDel = QString("DELETE FROM teacher WHERE id =%1").arg(id);
query.exec(sqlDel);
}
FindTch();
}
改:
通过对3个输入框分别检索,由2个if判断对password和name进行分别更改 ,输入为空默认该值不改
// 修改数据
void admin::on_pbt_changeTch_clicked()
{
QSqlQuery query;
int id = ui->Edit_idtch->text().toInt();
QString name = ui->Edit_nametch->text();
QString pwd = ui->Edit_pwdtch->text();
if(ui->Edit_idtch->text().isEmpty())
{
QMessageBox::warning(this,"","请输入要操作的学工号");
}
else
{
if(ui->Edit_pwdtch->text().isEmpty())
{
}
else
{
QString sqlUpd = QString("UPDATE teacher SET password = '%1' WHERE id = %2 ").arg(pwd).arg(id);
query.exec(sqlUpd);
}
if(ui->Edit_nametch->text().isEmpty())
{
}
else
{
QString sqlUpd = QString("UPDATE teacher SET name = '%1' WHERE id = %2 ").arg(name).arg(id);
query.exec(sqlUpd);
}
}
FindTch();
}
查:
设置一个列表和一个指向QTableWidgetItem的指针,然后将输入的学工号传给该指针,然后获取指针的所在行,进行滑动条定位,最后将这一行设置为选中
参考: 查找并定位到指定行
// 查找指定行
void admin::on_pbt_findStu_clicked()
{
if(ui->Edit_idstu->text().isEmpty() )
{
return;
}
//一个列表和一个指向QTableWidgetItem的指针 主打一个看不懂
QList<QTableWidgetItem *> items;
QTableWidgetItem *item;
items = ui->tableWidget->findItems(ui->Edit_idstu->text(), Qt::MatchExactly);//在表格中查找数据项
//找到了这个数据项
if(items.length() > 0)
{
item = items[0];//获取到数据项
int r = item->row();//获取所在行
ui->tableWidget->verticalScrollBar()->setSliderPosition(r);//滚动条定位到数据所在位置
ui->tableWidget->setCurrentItem(item);//将这个数据所在行设置为表格的当前行
ui->tableWidget->selectRow(r);
}
}
学生页面 (student)
修改个人信息
1.需要读取登录人数据,利用ini配置文件,将登录时候的账号存入ini文件,然后在学生页面修改时直接读取ini里面存好的账号,改动其数据库信息
2.修改信息利用UPDATE语句
完善个人信息
// 完善个人信息
void student::on_pbt_sureStu_clicked()
{
ui->stackedWidget->setCurrentIndex(1);
QString name = ui->Edit_namestu->text(); //保存编辑框内的输入信息
QString inst = ui->Edit_inststu->text();
QString pwd = ui->Edit_pwdstu->text();
QSettings settings("login.ini",QSettings::IniFormat); //利用配置文件查找id(3行)
settings.setIniCodec(QTextCodec::codecForName("UTF8"));
QString id = settings.value("/nowbegin/id").toString();
QSqlQuery query(db);
if(ui->Edit_pwdstu->text().isEmpty()) //非空才修改
{}
else
{
QString sqlUpd = QString("UPDATE student SET password = '%1' WHERE id = %2 ").arg(pwd).arg(id.toInt()); //更新数据库里面内容
query.exec(sqlUpd);
}
if(ui->Edit_namestu->text().isEmpty())
{}
else
{
QString sqlUpd = QString("UPDATE student SET name = '%1' WHERE id = %2 ").arg(name).arg(id.toInt());//更新数据库里面内容
query.exec(sqlUpd);
}
if(ui->Edit_inststu->text().isEmpty())
{}
else
{
QString sqlUpd = QString("UPDATE student SET institute = '%1' WHERE id = %2 ").arg(inst).arg(id.toInt());//更新数据库里面内容
query.exec(sqlUpd);
}
changeInformationInini(id.toInt());//将数据库内容修改到ini配置文件
readInformationInini();//将ini文件里面内容显示到页面
}
void student::changeInformationInini(int id) //将数据库内容修改到ini配置文件
{
QSqlQuery query(db);
query.prepare("SELECT id,name,institute,role,labid FROM student WHERE id = :id;");
query.bindValue(":id",id);
if(query.exec()&&query.next())
{
QSettings settings("login.ini",QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("UTF8"));
settings.setValue("/nowbegin/id",query.value(0).toString());
settings.setValue("/nowbegin/name",query.value(1).toString());
settings.setValue("/nowbegin/inst",query.value(2).toString());
settings.setValue("/nowbegin/flag",query.value(3).toString());
settings.setValue("/nowbegin/labid",query.value(4).toString());
}
}
void student::readInformationInini() //将ini文件里面内容显示到页面
{
QSettings settings("login.ini",QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("UTF8"));
QString id = settings.value("/nowbegin/id").toString();
QString name = settings.value("/nowbegin/name").toString();
QString inst = settings.value("/nowbegin/inst").toString();
QString labid = settings.value("/nowbegin/labid").toString();
QString str =QString("欢迎您,%1(学生)").arg(name);
ui->label_id->setText(str);
ui->label_id->adjustSize();
ui->label_name->setText(name);
ui->label_id_2->setText(id);
ui->label_inst->setText(inst);
ui->label_lab->setText(labid);
ui->label_lab_2->setText(labid);
}
实验室功能
1.预约:新建一个实验室表,设置总数total和已经预约人数num,在按下预约按钮时进行判断人数是否超过总数,没有超过则num+1
2.为了保证一个学生不重复预约多个实验室,设置每次预约前检测对应的labid里面是否有值,若有值返回0不予预约
3.取消预约的时候将该学生的labid清空,并将对应的实验室num-1
// 预约功能
bool student::addLabNum(int id) //实验室可预约人数加一
{
QSqlQuery query(db);
query.prepare("SELECT total,num FROM lab WHERE id = :id;");
query.bindValue(":id",id);
if(query.exec()&&query.next())
{
int labtotal = query.value(0).toInt(); //读取总人数和可预约人数
int labnum = query.value(1).toInt();
if(labtotal>labnum) //总人数大于当前预约人数才进行预约(加一)
{
QString sqladd = QString("UPDATE lab SET num = num+1 WHERE id = %1 ").arg(id);
query.exec(sqladd);
return 1;
}
else return 0;
}
}
bool student::minuLabNum(int id) //实验室可预约人数减一
{
QSqlQuery query(db);
query.prepare("SELECT total,num FROM lab WHERE id = :id;");
query.bindValue(":id",id);
if(query.exec()&&query.next())
{
//int labtotal = query.value(0).toInt();
int labnum = query.value(1).toInt();
if(labnum)
{
QString sqlminu = QString("UPDATE lab SET num = num-1 WHERE id = %1 ").arg(id);
query.exec(sqlminu);
return 1;
}
else return 0;
}
}
void student::on_pbt_cancelLab_clicked() //取消预约
{
QString labid = ui->label_lab_2->text();
if(labid != NULL) //非空才进入minuLabNum函数
{
int flag =minuLabNum(labid.toInt());
if(flag)
{
QSettings settings("login.ini",QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("UTF8"));
QString id = settings.value("/nowbegin/id").toString();
QSqlQuery query(db);
QString sqlLabid = QString("UPDATE student SET labid = NULL WHERE id = %1 ")
.arg(id);
query.exec(sqlLabid);
changeInformationInini(id.toInt());
readInformationInini();
}
else QMessageBox::warning(this,"","取消预约失败");
}else QMessageBox::warning(this,"","请先预约!");
FindLab();
}
void student::on_pbt_orderLab_clicked() //确认预约按钮
{
QString labidNow = ui->label_lab_2->text();
QString labidNew = ui->Edit_idLab->text();
if(labidNow == NULL) //当前预约为空才进入下一步
{
int flag =addLabNum(labidNew.toInt());
if(flag)
{ //预约成功后更新ini文件
QSettings settings("login.ini",QSettings::IniFormat);
settings.setIniCodec(QTextCodec::codecForName("UTF8"));
QString id = settings.value("/nowbegin/id").toString();
QSqlQuery query(db);
QString sqlLabid = QString("UPDATE student SET labid = %1 WHERE id = %2 ")
.arg(labidNew)
.arg(id);
query.exec(sqlLabid);
changeInformationInini(id.toInt());
readInformationInini();
}
else QMessageBox::warning(this,"","该实验室预约人数已满!");
}else{
QMessageBox::warning(this,"","请先取消预约!");
}
FindLab(); //刷新表格
}
老师页面 (teacher)
没写什么东西,利用label放了图片qwq
// 播放图片
QMovie *movie = new QMovie(":/image/emoji/pray.gif");
ui->label_2->setMovie(movie);
movie->start();
工程文件下载
工程文件: 基于Qt的实验室管理系统的设计(作业)