QT学生管理系统 开发文档

news2024/11/23 14:29:08

目录

第一章 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 指针或 nullptr
        QMessageBox::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 0
    auto str=QCoreApplication::applicationDirPath();  //获取一下数据库的路径,目的是为了发布时找到数据库将其放于当前目录下
    qDebug()<<str;
#endif

    if (!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(*)是否大于0
        if(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; //传id
    info.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,包括id
    ui->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删除,这里获取id
        m_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文件同级目录下:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1987132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

常用API_2:应用程序编程接口:ArrayList

文章目录 ArrayList常用方法 案例 &#xff1a;上菜 ArrayList 常用方法 来自黑马程序员学习视频 案例 &#xff1a;上菜 待完善

只有ip没有域名怎么申请证书?

当只有IP地址而没有域名时&#xff0c;仍然可以申请SSL证书以确保通过该IP地址访问的网站或服务的安全性。以下是为IP地址申请SSL证书的一般步骤&#xff1a; 一、确认前提条件 拥有公网IP地址&#xff1a;确保你拥有的是一个公网IP地址&#xff0c;因为内网IP地址不支持签发…

强化学习之Double DQN算法与DQN算法对比学习——以倒立摆(Inverted Pendulum)环境为例

0.简介 DQN算法敲开深度强化学习大门&#xff0c;但是其存在着一些问题&#xff0c;有进一步改进的空间。因此在DQN后出现大量改进算法。在此介绍DQN算法改进算法之一Double DQN&#xff0c;其在DQN算法基础上稍加修改实现在一定程度上改善DQN效果。 普通DQN算法会导致对Q值的过…

Leetcode75-5 反转字符串的元音字母

本质上来说就是反转字符串 一部分需要反转 一部分不动 思路: 1.用String字符串倒序拼接 就是过滤掉不是元音字符 然后把所有的字符&#xff08;非元音的直接复制过来 元音字母直接从反转的字符串里边复制即可&#xff09; 2.看了题解发现自己写的啰嗦了 就是一个双指针问题用…

螺旋矩阵

螺旋矩阵 思路&#xff1a; 这题是一个模拟的题目。 可以观察出一些性质&#xff1a;每次需要换方向的时候都是到达了边界&#xff08;长度和宽度的边界&#xff09;。 不知道怎么转化为代码&#xff01; 哭了 看看题解吧&#xff1a;真不会 看到一个太妙的方法了&#x…

《变形金刚》战斗力排名分析

Top1 天火擎天柱 作为博派的领袖&#xff0c;擎天柱本身实力不凡。然而&#xff0c;胜败乃兵家常事。在《变形金刚2》中&#xff0c;他虽然成功击败了破坏者、碾碎器和红蜘蛛&#xff0c;却不幸被威震天一炮穿心&#xff0c;阵亡。 不过&#xff0c;擎天柱是《变形金刚》系列…

Zero123 论文学习

论文链接&#xff1a;https://arxiv.org/abs/2303.11328 代码链接&#xff1a;https://github.com/cvlab-columbia/zero123 解决了什么问题&#xff1f; 人类通常能够仅凭一个相机视角来想象物体的三维形状和外观。这种能力对于日常任务非常重要&#xff0c;例如物体操纵和在…

快速掌握Vue:基础命令详解

目录 1. Vue概述 2. 快速入门 3. Vue指令 3.1 v-bind 3.2 v-model 3.3 v-on 3.4 v-if 3.5 v-show 3.6 v-for 3.7 案例 4. 生命周期 1. Vue概述 Vue.js&#xff08;读音 /vjuː/, 类似于 「view」&#xff09; 是一套构建用户界面的 「渐进式框架」。与其他重量级框…

【EI会议征稿通知】第六届光电科学与材料国际学术会议 (ICOSM 2024)

会议主要围绕“光电技术应用”“光电科学材料”“光电信号处理”“低温等离子体技术与应用” “激光技术与应用”“材料科学”等研究领域展开讨论。旨在为光电学、电子工程学等专家学者、工程技术人员、技术研发人员提供一个交流平台。拓展国内外光电科学与材料技术方面的研究范…

科普文:微服务之全文检索ElasticSearch忝删改查详细操作说明

一、Restful简介 RESTFul&#xff1a;Representational State Transfer&#xff0c;中文意思&#xff1a;表现层状态转化。变现层指的是资源的表现层&#xff0c;这里的资源是指网络上的信息&#xff0c;比如一张图片&#xff0c;一段文本&#xff0c;一步电影&#xff0c;那么…

数据结构(学习)2024.8.6

今天开始学习数据结构的相关知识&#xff0c;大概分为了解数据结构、算法&#xff1b;学习线性表&#xff1a;顺序表、链表、栈、队列的相关知识和树&#xff1a;二叉树、遍历、创建&#xff0c;查询方法、排序方式等。 目录 一、数据结构 数据 逻辑结构 1.线性结构 2.树…

JavaEE: wait(等待) / notify (通知)

文章目录 wait(等待) / notify (通知)总结 wait(等待) / notify (通知) 线程在操作系统上的调度是随机的~ 那么我们想要控制线程之间执行某个逻辑的先后顺序,那该咋办呢? 可以让后执行的逻辑,使用wait, 先执行的线程,在完成某些逻辑之后,通过notify来唤醒对应的wait. 另外,通…

谈谈如何优雅地封装 el-table

效果 像这样的表格我们可以这样划分一下区域&#xff1a; 1区域的渲染是通过取反插槽的条件 2区域的渲染是写在 slot 插槽的内部的&#xff0c;直接显示行数据3区域的渲染是通过具名插槽 bind 渲染 直接上代码&#xff1a; 子组件&#xff1a; <template><el-tabl…

为什么要用分布式锁

单应用中,如果要确保多线程修改同一个资源的安全性 加synchronized就可以了 但是性能不高 而mybatis-plus的乐观锁就可以很好的解决这类问题 但是这样的锁机制,只在单应用中有效 试想,在分布式下,有没有可能出现多个应用中的线程同时去修改同一个数据资源的并发问题 例如A …

Golang | Leetcode Golang题解之第328题奇偶链表

题目&#xff1a; 题解&#xff1a; func oddEvenList(head *ListNode) *ListNode {if head nil {return head}evenHead : head.Nextodd : headeven : evenHeadfor even ! nil && even.Next ! nil {odd.Next even.Nextodd odd.Nexteven.Next odd.Nexteven even.N…

65 生成器函数设计要点

包含 yield 语句的函数可以用来创建生成器对象&#xff0c;这样的函数也称为生成器函数。yield 语句与 return 语句的作用相似&#xff0c;都是用来从函数中返回值。return 语句一旦执行会立刻结束函数的运行&#xff0c;而每次执行到 yield 语句返回一个值之后会暂停或挂起后面…

无人机无线电监测设备技术分析

随着无人机技术的飞速发展&#xff0c;其在民用、军事、科研及娱乐等领域的广泛应用&#xff0c;对无线电频谱资源的有效管理和监测提出了更高要求。无人机无线电监测设备作为保障空域安全、维护无线电秩序的重要工具&#xff0c;集成了高精度定位、频谱扫描、信号分析、数据处…

stm32应用、项目

主要记录实际使用中的一些注意点。 1.LCD1602 电路图&#xff1a; 看手册&#xff1a;电源和背光可以使用5v或者3.3v&#xff0c;数据和控制引脚直接和单片机引脚连接即可。 单片机型号&#xff1a;stm32c031c6t6 可以直接使用推完输出连接D0--D7,RS,EN,RW引脚&#xff0c;3…

大数据面试SQL(二):每天最高峰同时直播人数

文章目录 每天最高峰同时直播人数 一、题目 二、分析 三、SQL实战 四、样例数据参考 每天最高峰同时直播人数 一、题目 有如下数据记录直播平台主播上播及下播时间&#xff0c;根据该数据计算出平台当天最高峰同时直播人数。 这里用主播名称做统计&#xff0c;前提是主…

Flask+LayUI开发手记(一):LayUI表格的前端数据分页展现

用数据表格table展示系统数据&#xff0c;是LayUI的基本功能&#xff0c;编码十分简单&#xff0c;就是通过table.render()渲染&#xff0c;把属性配置好就OK了&#xff0c;十分方便&#xff0c;功能也十分强大。 不过&#xff0c;在实现时&#xff0c;把table的有个功能却理解…