QT学生管理系统 开发文档
目录
第一章 UI界面设计与开发
登录界面
主界面
UI美化
第二章 数据库设计与开发
数据库设计
连接数据库
数据库功能设计
sql语句设计
查询所有学生数量
查询第几页学生数据
删除学生
修改学生信息
清空学生表
添加单个用户
删除单个用户
修改用户权限
查询所有用户
查询用户是否存在
数据库函数设计
sql函数设计
学生表操作
Init()
getStuCnt()
getPageStu()
addStu()
delStu()
updateInfo()
clearStuInfo()
用户表操作
addUser()
delUser()
UpdateUserAut()
getAllUser()
isExists()
模拟数据
创建单例
增
删
查询
修改
清空学生表
优化
打包
样式打包
数据库打包
第一章 UI界面设计与开发
登录界面
第一步先做登录界面
新建一个文件,命名为Page_login.
在MainWindows.h头文件里声明一个Page_login类型的变量m_dlgloin:
先放置控件:
设置控件属性
然后我们将用户名输入和密码输入框设置成为默认显示:
将密码输入框的模式改为密码模式:
将用户名和密码输入长度限制为8位:
在MainWindows.cpp文件里调用我们我们m_dlogin窗口,并且把主窗口阻塞不显示:
初步登录界面如下:
右击按钮选择转到槽:会自动生成框架:
我们接下来登录和退出的逻辑
退出
exit(0);
登录
登录一般是在数据库查找用户名和密码,查找到了就发送一个signal显示成功了:
如果失败就提示登录失败.
在Mainwindows.cpp里写下面这段代码,表示如果主界面捕获到来自登录界面登录成功的信号,那么就跳到主界面:
主界面
主界面放置如下控件:效果图如下:
改变一下背景色
往treewidget里添加信息
需要用到的函数:
所以我们需要new一个 QTreeWidgetItem 类型对象.QTreeWidgetItem 的构造函数如下:第一个参数要为自身,第二个参数想用字符串的话只能构造一个qstringlist类型的参数
效果图:
让文字居左显示(把indentation设为小一点):
构造两个子集目录:学生管理,管理员管理
效果图如下:
数据模拟
把我们之前的stackwidget设置一个背景色,然后在stackwidget里加一个tablewidget控件,给tablewidget加几列数据,效果图如下:
UI美化
在Mainwindows.cpp里面的Widget类里面有一个keyPressEvent()键盘响应事件函数,它的声明如下:
virtual void keyPressEvent(QKeyEvent *event);
我们在Mainwindows.h文件里进行声明,然后在Mainwindows.cpp文件进行定义.定义如下:
我们通过f6键进行换肤,首先提前新建一个stucss.css文件,在里面我们要换的样式写好,然后在我们按完F6之后将其加载进我们的UI界面
void MainWindow::keyPressEvent(QKeyEvent *event)
{if(event->key()==Qt::Key_F6){QFile f;auto str=QCoreApplication::applicationDirPath(); //获取application的路径f.setFileName(str+"//"+"stucss.css"); //将路径后加上我们皮肤的路径f.open(QIODevice::ReadOnly); //以只读方式打开QString str2=f.readAll(); //读取this->setStyleSheet(str2); //设置样式m_dlgloion.setStyleSheet(str2);//采用样式}
}
stucss.css代码如下:
/* 登录界面 */
QPushButton{color:white;background-color:#34495e;border-radius:6;} /*按钮*/
QLabel{color:#34495e;} /*标签*/
QLabel#lb1{color:#34495e;font-size: 22;} /*用户名标签*/
QLabel#lb2{color:#34495e;font-size: 22;} /*密码标签*/
QLineEdit{border: 2px solid #bdc3c7; min-height:22; border-radius: 6px;}/*搜索框 *//* 主界面 */
/* Widget#background-color:#34495e; */
QLabel[lab="main"]{color:white;}
QWidget#widget[bg_title="main"]{background-color:#34495e;}
QWidget#widget_3{background-color:#34495e;}
QPushButton[btn="main"]{font-family:"微软雅黑";min-height:22px;min-width:80px;background-color: #16a085;border-radius:6; } /*主界面按钮*/
QPushButton[btn="main"]:pressed{font-family:"微软雅黑";min-height:22px;min-width:80px;background-color: #2a5d53;border-radius:6; } /*按钮按压变色*//*左侧界面样式*/
QTreeWidget{font-family:"宋体";font-size:15px;background-color: rgba(52, 73, 94, 150); color:white;} QStackedWidget{border:1px solid gray;} 边框/*右侧界面样式*/
QHeaderView::section
{ font-size:16px;font-family: "宋体";text-align:center; height:30px; color:#909399;font-weight: bold;border:1px solid gray;border-left:none;/* border-bottom-color: rgb(168, 171, 180); */
}QTableWidget::item
{font:14px "微软雅黑";color:#667483;border:none;
}
优化完之后的效果如下所示:
第二章 数据库设计与开发
数据库设计
新建两张表,sql语句如下:
学生表
CREATE TABLE "student" ("id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,"name" TEXT,"age" integer,"grade" integer,"class" integer,"studentid " integer,"phone" TEXT,"wechat" TEXT
);
用户表
CREATE TABLE "username" ("username" TEXT,"password" TEXT,"auth" TEXT
);
此时数据库里就有两张表了
创建一个新的基于OBject类的头文件,命名为stusql.cpp
在这个文件进行数据库操作
连接数据库
连接数据库的模板如下:
#include "stusql.h"
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>stusql::stusql(QObject *parent ): QObject {parent}
{// 检查是否有可用的数据库驱动if (QSqlDatabase::drivers().isEmpty()) {// 确保 stusql 类是 QObject 的子类,否则需要传递一个有效的 QWidget 指针或 nullptrQMessageBox::information(nullptr, tr("No database drivers found"),tr("This demo requires at least one Qt database driver. ""Please check the documentation how to build the ""Qt SQL plugins."));return;}QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE"); // 创建一个数据库连接db.setDatabaseName("./data.db");if (!db.open()) {qDebug() << "数据库文件加载失败: " << db.lastError().text();// 这里可能需要处理错误,比如显示一个消息框或者记录日志return; // 数据库打开失败,构造函数不应该继续执行}qDebug() << "打开数据库文件成功";
此时构建完之后控制台显示
然后我们可以向数据库里插一条数据看一下是否可以插入成功:
语句如下:
QSqlQuery q("", db);if (!q.exec("INSERT INTO student VALUES (NULL ,'张三',12,3,2,1,15518978071,'aasDASD')")) {qDebug() << "插入数据失败: " << q.lastError().text();// 这里应该处理SQL执行错误}
此时构建完之后控制台显示:
我们现在可以让插入失败的原因可视化的显示出来:
if (!q.exec("INSERT INTO student VALUES (NULL ,'张三',12,3,2,1,15518978071,'aasDASD')")) {QMessageBox::critical(nullptr, tr("Database Error"),tr("Failed to insert data: %1").arg(q.lastError().text()));// 显示具体的错误信息}
这样的话就会有一个断言:显示表不存在
我把路径换成绝对路径就可以了:
db.setDatabaseName("D:\\QTproject\\stumanger\\data.db");
现在数据库里student表就被插入一条数据了:
数据库功能设计
sql语句设计
查询所有学生数量
select count(id) from student;
查询第几页学生数据
offset代表从第几条记录之后"开始"查询,limit表示查询多少条结果
select * from student order by id limit 2 offset 1;
删除学生
delete from student where id = 1;
修改学生信息
update student set name = 'asd' where id=25;
清空学生表
delete from student
添加单个用户
INSERT INTO "username" VALUES ('admin', 111, 'admin');
删除单个用户
delete from username where username='admin';
修改用户权限
update username set auth='user';
查询所有用户
select * from username
查询用户是否存在
select *from username where username='admin';
数据库函数设计
实现基础的数据库增删查改功能,在stusql.h文件里列出以下声明:
首先创建两个结构体
在stusql.cpp文件里实现定义:
sql函数设计
学生表操作
Init()
在初始化的时候进行数据库连接
void stusql::Init()
{m_db = QSqlDatabase::addDatabase("QSQLITE"); // 创建一个数据库连接m_db.setDatabaseName("D:\\QTproject\\stumanger\\data.db");#if 0auto str=QCoreApplication::applicationDirPath(); //获取一下数据库的路径,目的是为了发布时找到数据库将其放于当前目录下qDebug()<<str;
#endifif (!m_db.open()) {QMessageBox::critical(nullptr, tr("Database Error"),tr("Failed to open database: %1").arg(m_db.lastError().text()));return; // 数据库打开失败,构造函数不应该继续执行}qDebug() << "打开数据库文件成功";
}
getStuCnt()
quint32 stusql::getStuCnt()
{QSqlQuery sql(m_db);sql.exec("select count(id) from student;");quint32 Cnt=0;while(sql.next()){Cnt=sql.value(0).toUInt();}qDebug() << "学生数量: " << Cnt;return Cnt;
}
getPageStu()
QList<StuInfo> stusql::getPageStu(quint32 page, quint32 Cnt)
{QList<StuInfo> l;QSqlQuery sql(m_db);QString strsql=QString("select * from student order by id limit %1 offset %2;").arg(Cnt).arg(page*Cnt);sql.exec(strsql);StuInfo info;while(sql.next()){info.id=sql.value(0).toUInt();info.stu_name=sql.value(1).toString();info.stu_age=sql.value(2).toUInt();info.stu_grade=sql.value(3).toUInt();info.stu_class=sql.value(4).toUInt();info.stu_id=sql.value(5).toUInt();info.stu_phone=sql.value(6).toString();info.stu_wechat=sql.value(7).toString();}l.push_back(info);// qDebug()<<l.begin()->id<<l.begin()->stu_name<<l.begin()->stu_age;return l;
}
addStu()
添加记录
bool stusql::addstu(StuInfo info)
{QSqlQuery sql(m_db);QString strsql=QString("insert into stdent values(null,'%1',%2,%3,%4,%5,'%6','%7')").arg(info.stu_name).arg(info.stu_age).arg(info.stu_grade).arg(info.stu_class).arg(info.stu_id).arg(info.stu_phone).arg(info.stu_wechat);if(!sql.exec(strsql)){QMessageBox::critical(nullptr, tr("Database Error"),tr("Failed to insert data: %1").arg(sql.lastError().text()));// 显示具体的错误信息return false;}return true;
}
delStu()
bool stusql::delStu(int id)
{QSqlQuery sql(m_db);QString strsql=QString("delete from student where id= %1;").arg(id);if(sql.exec(strsql)){return true;}else qDebug()<<"删除失败!";return false;
}
updateInfo()
修改学生信息
bool stusql::updateInfo(StuInfo info)
{QSqlQuery sql(m_db);QString strsql=QString("update student set name = '%1' where id=%2;").arg(info.stu_name).arg(info.stu_id);bool res=sql.exec(strsql);QSqlError e=sql.lastError();if(sql.isValid()){qDebug()<<e.text();}return res;
}
发现怎么修改都无法修改,后来发现是建表的问题(字段名后面有空格)
clearStuInfo()
清空学生表
void stusql::clearStuInfo()
{QSqlQuery sql(m_db);QString strsql=QString("delete from student");sql.exec(strsql);
}
在表设计视图里面把这些空格删掉就可以了
用户表操作
addUser()
//添加单个用户
bool stusql::addUser(UserInfo info)
{QSqlQuery sql(m_db);QString strsql = QString("INSERT INTO username VALUES ('%1', '%2', '%3');").arg(info.username).arg(info.passwd).arg(info.auth);if(!sql.exec(strsql)){qDebug()<<"ERROR:"<<sql.lastError();return false;}return true;
}
delUser()
bool stusql::delUser(QString userName)
{QSqlQuery sql(m_db);QString strsql =QString("delete from username where username= '%1'").arg(userName);if(!sql.exec(strsql)){qDebug()<<"ERROR:"<<sql.lastError();return false;}return true;
}
UpdateUserAut()
bool stusql::UpdateUserAut(QString str1, QString str2)
{QSqlQuery sql(m_db);// 使用参数化查询来避免SQL注入QString strsql = "UPDATE username SET auth = :auth WHERE username = :username;";// 绑定参数sql.prepare(strsql);sql.bindValue(":auth", str1);sql.bindValue(":username", str2);if (!sql.exec()) {qDebug() << "ERROR:" << sql.lastError();return false;}// 检查是否有行被更新if (sql.numRowsAffected() > 0) {return true;} else {// 没有行被更新,可能是没有找到匹配的用户名qDebug() << "No rows updated. User may not exist.";return false;}
}
getAllUser()
QList<UserInfo> stusql::getAllUser()
{QList<UserInfo> l; // 使用正确的类型QSqlQuery sql(m_db);QString strsql = "select * from username"; // 假设表名正确// 执行SQL查询if (!sql.exec(strsql)) {// 处理错误,例如打印错误信息qDebug() << "Error executing query:" << sql.lastError();return l; // 返回空列表或根据需要进行错误处理}UserInfo info; // 在循环内部初始化while (sql.next()) {info.username = sql.value("username").toString(); // 假设列名为 "username"info.passwd = sql.value("passwd").toString(); // 假设列名为 "passwd"info.auth = sql.value("auth").toString(); // 假设列名为 "auth"l.push_back(info); // 在每次迭代中将info添加到列表info = UserInfo(); // 重置info对象(如果UserInfo有默认构造函数)}auto a=l.front();qDebug()<<a.username<<a.passwd<<a.auth;return l;
}
isExists()
bool stusql::isExists(QString Name)
{QSqlQuery sql(m_db);// 使用参数化查询来避免SQL注入,并且只查询需要的列QString strsql = "SELECT COUNT(*) FROM username WHERE username = :name;";// 绑定参数sql.prepare(strsql);sql.bindValue(":name", Name);if (!sql.exec()) {qDebug() << "ERROR:" << sql.lastError();return false;}// 检查是否有结果返回if (sql.next()) {// 检查COUNT(*)是否大于0if(sql.value(0).toLongLong() > 0)qDebug()<<"用户存在";else qDebug()<<"用户不存在";}return false;
}
造一行数据,我们发现左边会有一个自增id:我们可以通过取消一个属性将其去掉:
模拟数据
创建单例
创建单例的目的:
单例模式是qt开发的一种模式.在发布的时候有两种模式,一种是怎么把资源载入exe文件当中,还有一种就是在发布的时候引入外部资源,这种模式占用内容特别少,就是单例模式.
我们在stusql.h文件里添加单利模式的声明
static stusql *ptrstuSql;static stusql *getinstance(){if(ptrstuSql==nullptr){ptrstuSql=new stusql;}return ptrstuSql;}
在stusql.cpp文件里面添加对单例的定义:
stusql *stusql::ptrstuSql=nullptr;
我们创建一个QStringList类型对象mlNames,然后将1000个名字读入到mlNames里面.
然后我们在主界面添加一个按钮命名为btn_moni,然后添加定义,定义如下:
void MainWindow::on_btn_moni_clicked()
{QString l;//制作1000条学生数据QRandomGenerator g,c;g.seed(0);c.seed(0);for(int i=0;i<mlNames.size();i++){auto rand_grade=g.bounded(7,10);auto rand_class=g.bounded(1,10);StuInfo info;info.stu_name=mlNames[i];if(i%3){info.stu_age=14;}if(i%7){info.stu_age=13;}if(i%9){info.stu_age=18;}info.stu_grade=rand_grade;info.stu_class=rand_class;info.id=i;info.stu_phone="13463464347";info.stu_wechat="sfwegewg";m_ptrStusql->addstu(info);}}
此时我们的数据库里就有了我们模拟的数据了:
接下来我们需要将这些数据展现在我们的Qtablewidget上.
我们写一个Update()函数,内容如下:
//刷新数据
void MainWindow::updateTable()
{//把自带的表头删了,我们自己来写表头ui->tableWidget_2->clear();//必须要告诉编译器有多少列才能显示表头ui->tableWidget_2->setColumnCount(8);QStringList l;//自定义表头l<<"序号"<<"姓名"<<"年龄"<<"年纪"<<"班级"<<"学号"<<"电话"<<"微信";ui->tableWidget_2->setHorizontalHeaderLabels(l); //设置显示表头ui->tableWidget_2->setSelectionBehavior(QAbstractItemView::SelectRows); //当用户点击任何一个单元格时,整个行都会被选中//显示数据内容auto cnt=m_ptrStusql->getStuCnt(); //获取记录行数ui->lb_cnt->setText(QString("数量:%1").arg(cnt)); //显示学生数量QList<StuInfo> lStudents=m_ptrStusql->getPageStu(0,cnt); //获取一共有多少页数据ui->tableWidget_2->setRowCount(cnt); //设置行数//将数据刷新到tablewidget上for(int i=0;i<lStudents.size();i++){ui->tableWidget_2->setItem(i,0,new QTableWidgetItem(QString::number(i)));ui->tableWidget_2->setItem(i,1,new QTableWidgetItem(lStudents[i].stu_name));ui->tableWidget_2->setItem(i,2,new QTableWidgetItem(QString::number(lStudents[i].stu_age)));ui->tableWidget_2->setItem(i,3,new QTableWidgetItem(QString::number(lStudents[i].stu_grade)));ui->tableWidget_2->setItem(i,4,new QTableWidgetItem(QString::number(lStudents[i].stu_class)));ui->tableWidget_2->setItem(i,5,new QTableWidgetItem(QString::number(lStudents[i].stu_id)));ui->tableWidget_2->setItem(i,6,new QTableWidgetItem(lStudents[i].stu_phone));ui->tableWidget_2->setItem(i,7,new QTableWidgetItem(lStudents[i].stu_wechat));}
}
此时我们的数据就刷新出来了:
增
接下来我们实现这几个按钮的功能:
先来实现增加按钮的功能.创建一个dlg_addstu文件,dlg_addstu.ui如下:
然后我们还有个修改操作,就不单独设计UI界面,直接用dlg_addstu.ui的界面.
我们用一个全局变量m_isAdd,如果m_isAdd为True表示当前是添加操作,为false表示当前是修改操作.
dlg_addstu.ui界面的保存按钮和取消按钮定义如下:
增加操作是我们获取一下每个输入框输入的内容,把这些信息全部传给变量info,然后再把Info作为参数传给addStu()函数执行insert SQL语句.
//保存
void Dlg_AddStu::on_btn_save_clicked()
{StuInfo info; //把所有的字段读取到info里auto ptr=stusql::getinstance();info.id=m_info.id; //传idinfo.stu_name=ui->le_name->text();info.stu_age=ui->sb_age->text().toInt();info.stu_grade=ui->le_grade->text().toInt();info.stu_class=ui->le_class->text().toInt();info.stu_id=ui->le_id->text().toUInt();info.stu_phone=ui->le_phone->text();info.stu_wechat=ui->le_wechat->text();if(m_isAdd) //为true表示当前是添加操作{ptr->addstu(info);}else{ //为false表示当前是修改操作ptr->updateInfo(info);}QMessageBox::information(nullptr,"消息","添加成功");this->hide(); //点击保存之后窗口消失
}
void Dlg_AddStu::setType(bool isAdd,StuInfo info)
{m_isAdd=isAdd;m_info=info; //把info的所有信息都给中间变量m_info,包括idui->le_name->setText(info.stu_name);ui->sb_age->setValue(info.stu_age);ui->le_grade->setText(QString::number(info.stu_grade));ui->le_class->setText(QString::number(info.stu_class));ui->le_phone->setText(QString(info.stu_phone));ui->le_wechat->setText(QString(info.stu_wechat));
}
取消按钮
//取消
void Dlg_AddStu::on_btn_cancel_clicked()
{this->hide();
}
添加按钮(调出添加输入框)
//点击添加按钮弹出添加界面
void MainWindow::on_btn_add_clicked()
{m_dlgAddstu.setType(true); //表示true代表当前是添加操作,false代表当前是修改操作m_dlgAddstu.exec(); //模态对话框 当前界面不操作完不能操作其他界面// m_dlgAddstu.show(); //非模态对话框updateTable(); //添加完成之后刷新一下界面
}
删
//删除按钮的定义如下
void MainWindow::on_btn_del_clicked()
{int i=ui->tableWidget_2->currentRow(); //获取一下鼠标点击的记录(即需要删除的记录)if(i>=0) //如果要删除的记录是合法记录 (即不是不存在的记录),那么就进行删除{int id=ui->tableWidget_2->item(i,1)->text().toUInt(); //删除需要通过id删除,这里获取idm_ptrStusql->delStu(id); //传给我们定义的delStu()函数执行删除sql语句 updateTable(); //删除完之后刷新一下界面QMessageBox::information(nullptr,"信息","删除成功");}
}
查询
//搜索
void MainWindow::on_btn_seacher_clicked()
{QString SearchFile=ui->lb_search->text(); //获取搜索输入框输入的内容//如果输入框的内容为空就退出查询 if(SearchFile.isEmpty()){QMessageBox::information(nullptr,"信息","查询为空!");updateTable();return;}//必须要告诉编译器有多少列才能显示表头ui->tableWidget_2->clear();ui->tableWidget_2->setColumnCount(9);QStringList l;//自定义表头l<<"序号"<<"id"<<"姓名"<<"年龄"<<"年纪"<<"班级"<<"学号"<<"电话"<<"微信";ui->tableWidget_2->setHorizontalHeaderLabels(l); //设置显示表头ui->tableWidget_2->setSelectionBehavior(QAbstractItemView::SelectRows); //当用户点击任何一个单元格时,整个行都会被选中//显示数据内容auto cnt=m_ptrStusql->getStuCnt(); //获取记录行数ui->lb_cnt->setText(QString("数量:%1").arg(cnt)); //显示学生数量ui->tableWidget_2->setSelectionBehavior(QAbstractItemView::SelectRows);//单击选中一行ui->tableWidget_2->setEditTriggers(QAbstractItemView::NoEditTriggers);//使记录不可被直接编辑QList<StuInfo> lStudents=m_ptrStusql->getPageStu(0,cnt); //获取一共有多少页数据int index=0;//将数据刷新到tablewidget上for(int i=0;i<lStudents.size();i++){//如果查询不到这个人就不执行下面的操作if(!lStudents[i].stu_name.contains(SearchFile)){continue;}index++;ui->tableWidget_2->setItem(i,0,new QTableWidgetItem(QString::number(index)));ui->tableWidget_2->setItem(i,1,new QTableWidgetItem(QString::number(lStudents[i].id)));ui->tableWidget_2->setItem(i,2,new QTableWidgetItem(lStudents[i].stu_name));ui->tableWidget_2->setItem(i,3,new QTableWidgetItem(QString::number(lStudents[i].stu_age)));ui->tableWidget_2->setItem(i,4,new QTableWidgetItem(QString::number(lStudents[i].stu_grade)));ui->tableWidget_2->setItem(i,5,new QTableWidgetItem(QString::number(lStudents[i].stu_class)));ui->tableWidget_2->setItem(i,6,new QTableWidgetItem(QString::number(lStudents[i].stu_id)));ui->tableWidget_2->setItem(i,7,new QTableWidgetItem(lStudents[i].stu_phone));ui->tableWidget_2->setItem(i,8,new QTableWidgetItem(lStudents[i].stu_wechat));}//最后统计一下查询出来的人数ui->tableWidget_2->setRowCount(index); //设置行数
}
修改
//修改按钮
void MainWindow::on_btn_modify_clicked()
{StuInfo info; //把当前鼠标点击的记录的每个字段添加到info里int i=ui->tableWidget_2->currentRow(); //获取鼠标点击的行(即要修改的记录)if(i>=0){info.id=ui->tableWidget_2->item(i,1)->text().toUInt(); //获取id的值并保存在Info里info.stu_name=ui->tableWidget_2->item(i,2)->text();info.stu_age=ui->tableWidget_2->item(i,3)->text().toUInt();info.stu_grade=ui->tableWidget_2->item(i,4)->text().toUInt();info.stu_class=ui->tableWidget_2->item(i,5)->text().toUInt();info.stu_id=ui->tableWidget_2->item(i,6)->text().toUInt();info.stu_phone=ui->tableWidget_2->item(i,7)->text();info.stu_wechat=ui->tableWidget_2->item(i,8)->text();m_dlgAddstu.setType(false,info);m_dlgAddstu.exec();}updateTable(); //更新完之后把界面刷新一下
}
清空学生表
//清除学生表
void MainWindow::on_btn_StuClear_clicked()
{m_ptrStusql->clearStuInfo();updateTable();
}
优化
优化一下数据模拟的加载时间
也就是优化一下add()函数
我们用QList<StuInfo> l来接收所有的添加信息,再通过循环从l里读取每条记录进行,执行添加sql语句,再把事务打开.
//添加学生
bool stusql::addstu(QList<StuInfo> l)
{QSqlQuery sql(m_db);m_db.transaction(); //开启事务for(auto info:l){QString strsql = QString("INSERT INTO student VALUES (NULL, '%1', %2, %3, %4, %5, '%6', '%7')").arg(info.stu_name).arg(info.stu_age).arg(info.stu_grade).arg(info.stu_class).arg(info.stu_id).arg(info.stu_phone).arg(info.stu_wechat);if (!sql.exec(strsql)) {QMessageBox::critical(nullptr, tr("Database Error"),tr("Failed to insert data: %1").arg(sql.lastError().text()));return false; // 返回 false 表示插入失败}}m_db.commit();return true; // 返回 true 表示插入成功
}
打包
样式打包
把我们的皮肤样式复制两份到当前目录,分别重名为dlg.css,main.css:
在dlg.css里只保留登录界面的样式,在main.css里只保留主界面的样式
在资源文件里把我们的所有资源都载入:
然后在主界面初始化的时候把我们的皮肤加载上:
数据库打包
数据库路径问题.我们把1端口打开,用当前目录下的路径,不要用绝对路径:
然后我们以debug方式打包我们的exe文件,打开QT安装目录下bin目录,在路径栏里输入"cmd",然后在dos窗户输入:"windeployqt.exe":
然后把我们的exe文件拖上去就开始打包了:
打包完成之后双击我们的exe文件发现运行不了:
这是QT的一个bug,有几个文件是不会打包的,需要我们手动打包.我们去bin目录下找到三个lib开头的文件,将其复制到打包好的exe文件同级目录下:
相关文章:

QT学生管理系统 开发文档
目录 第一章 UI界面设计与开发 登录界面 主界面 UI美化 第二章 数据库设计与开发 数据库设计 连接数据库 数据库功能设计 sql语句设计 查询所有学生数量 查询第几页学生数据 删除学生 修改学生信息 清空学生表 添加单个用户 删除单个用户 修改用户权限 查询所有用户…...

【五大海内外高校支持】2024年数字经济与计算机科学国际学术会议(DECS2024)
大会官网:www.icdecs.net 大会时间:2024年9月20-22日 大会地点:中国-厦门 截稿日期:详情见官网 支持单位 马来西亚理工大学 北京科技大学经济管理学院 南京信息工程大学 马来西亚敦胡先翁大学 大会嘉宾 大会主席 罗航…...

VS项目打包成lib库并使用
一、新建一个静态库项目 一般要把项目设为Release模式 二、添加文件 将所需要打包的头文件、源文件添加到该静态库项目中 三、生成项目 生成成功后即可在Release文件夹出现找到相应的.lib文件 四、使用静态库 将静态库文件复制到项目文件夹中,然后在项目属性设…...

社交巨头与去中心化:解析Facebook在区块链的角色
区块链技术的兴起为多个行业带来了变革,而社交平台也正在经历这一波技术浪潮。作为全球最大的社交网络之一,Facebook(现名Meta Platforms)在区块链领域的探索展示了其如何应对去中心化趋势的挑战,并利用这一技术推动自…...
MyBatis(学习记录)
一、ORM ORM是“对象关系映射”(Object-Relational Mapping)的缩写。这是一种编程技术,用于将对象模型与关系型数据库系统之间的数据进行转换。在面向对象的编程语言中,数据通常以对象的形式表示;而在关系型数据库中&a…...

QSpinbox
加载图片资源 在项目中,选择新建,QT->Qt Resource File -choose ,命名为 image ,创建完成了,会在目录下生成一个image.qrc。我们资源文件,要放在image.qrc 的同级目录或子目录中。 常用的小功能 在左下方&#x…...
分布式服务架构[原理、设计与实践]学习笔记
地震是由不可抗力导致的,而事故与之不同,任何大的生产事故在发生之前都有迹可循,而且事故的发生并不是偶然的,我们应该善于从现象中总结规律,找到发现、止损和避免的方法 海恩法则 每一起严重事故的背后,必…...

PDF发票解析并将信息回填到前端(1)后端解析PDF
文章目录 参考文章技术栈需求解析发票类型 1. 最终项目结构1.1 说明 2. 相关代码2.1 导入相应的maven依赖2.2 实体类2.3 工具类2.4 三层架构controllerservicemapper 参考文章 参考文章 技术栈 SpringBootVue 需求 本文主要是实现提取发票中的部分内容,并实现自…...

C++练习之插入删除
#include <iostream> #include <ctime> #include <cstring> #include<cstdlib> using namespace std;typedef struct bookInfo {char name[10];float price;int num; }BOOKINFO;// p: 结构体数组首元素地址 // n: 有效图书数量 void Print(const BOOKI…...

【LeetCode】238. 除自身以外数组的乘积
除自身以外数组的乘积 题目描述: 给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请…...

Excel公式与函数(运算符,计算限制,错误检查)(一)
公式 公式概念 公式 是以“”号为引导,用过运算符按照一定的顺序组合进行数据运算处理的等式,函数 则是按特定算法执行计算的产生一个或一组结果的预定义的特殊公式。 公式组成要素 公式的组成要素为“”,运算符,单元格引用&a…...

用AI助手写程序
用AI帮助写程序究竟靠不靠谱,下面来测试一下: 在文心一言中输入:写一个C Windows API串口通信程序。结果如下: #include <windows.h> #include <iostream> // 串口配置 void ConfigureCommPort(HANDLE hComm) {…...

动手学深度学习7.2 使用块的网络(VGG)-笔记练习(PyTorch)
以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:25 使用块的网络 VGG【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址:7.2. 使用…...
SolidityFoundry ERC4626
ERC4626简介 ERC4626 协议是一种用于代币化保险库的标准。 我们经常说 DeFi 是货币乐高,可以通过组合多个协议来创造新的协议; ERC4626 扩展了 ERC20 代币标准,旨在推动收益金库的标准化,它是 DeFi 乐高中的基础,它允…...

大模型时代的操作系统:融合 Rust 和大模型,打造 AI 操作系统
每次技术革命,无论是个人电脑、互联网还是移动设备,总是从硬件开始,然后演化到软件层。而操作系统是计算机系统的核心,没有它,计算机就只是一堆硬件,无法运行任何程序。 微软 CEO 萨蒂亚纳德拉曾将生成式 …...

【ML】为什么要做batch normlization,怎么做batch normlization
为什么要做batch normlization,怎么做batch normlization 1. batch normlization1.1 批量归一化是什么:1.2 为什么要做批量归一化: 2. feature normalization2.1 特征归一化是什么:2.2 为什么要做特征归一化: 3. batc…...

【C++指南】命名空间
💓 博客主页:倔强的石头的CSDN主页 📝Gitee主页:倔强的石头的gitee主页 ⏩ 文章专栏:《C指南》 期待您的关注 目录 一、命名空间的重要性 1. C语言中没有命名空间而存在的问题 2. C引入了命名空间解决的问题 3.…...

RocketMQ Dashboard安装
RocketMQ Dashboard 是一个基于 Web 的管理工具,用于监控和管理 RocketMQ 集群。它提供了一个用户友好的界面,使管理员能够轻松地查看和操作 RocketMQ 系统中的各种组件和状态。 主要功能包括: 集群管理: 监控和管理 NameServer 和 Broker …...

前端web开发HTML+CSS3+移动web(0基础,超详细)——第3天
目录 一,列表-无序和有序的定义列表 二,表格-基本使用与表格结构标签 三,合并单元格 四,表单-input标签 五,表单-下拉菜单 六,表单-文本域 七,表单-label标签 八,表单-按钮 …...
认识MySQL
目录 数据库是什么呢?MySQL 数据库是什么呢? 在我们开始学习MySQL之前,先来了解一下,什么是数据库呢?我相信此时很多人会说是管理数据的,完全正确!用数据库我们可以去存储大量的数据。我来给你…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...

安宝特方案丨船舶智造的“AR+AI+作业标准化管理解决方案”(装配)
船舶制造装配管理现状:装配工作依赖人工经验,装配工人凭借长期实践积累的操作技巧完成零部件组装。企业通常制定了装配作业指导书,但在实际执行中,工人对指导书的理解和遵循程度参差不齐。 船舶装配过程中的挑战与需求 挑战 (1…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10+pip3.10)
第一篇:Liunx环境下搭建PaddlePaddle 3.0基础环境(Liunx Centos8.5安装Python3.10pip3.10) 一:前言二:安装编译依赖二:安装Python3.10三:安装PIP3.10四:安装Paddlepaddle基础框架4.1…...
智能职业发展系统:AI驱动的职业规划平台技术解析
智能职业发展系统:AI驱动的职业规划平台技术解析 引言:数字时代的职业革命 在当今瞬息万变的就业市场中,传统的职业规划方法已无法满足个人和企业的需求。据统计,全球每年有超过2亿人面临职业转型困境,而企业也因此遭…...

云安全与网络安全:核心区别与协同作用解析
在数字化转型的浪潮中,云安全与网络安全作为信息安全的两大支柱,常被混淆但本质不同。本文将从概念、责任分工、技术手段、威胁类型等维度深入解析两者的差异,并探讨它们的协同作用。 一、核心区别 定义与范围 网络安全:聚焦于保…...
二维FDTD算法仿真
二维FDTD算法仿真,并带完全匹配层,输入波形为高斯波、平面波 FDTD_二维/FDTD.zip , 6075 FDTD_二维/FDTD_31.m , 1029 FDTD_二维/FDTD_32.m , 2806 FDTD_二维/FDTD_33.m , 3782 FDTD_二维/FDTD_34.m , 4182 FDTD_二维/FDTD_35.m , 4793...