Qt基础 | QSqlQueryModel 的使用 | QSqlQuery的使用

文章目录

  • 一、QSqlQueryModel 的使用
    • 1.主窗口类定义
    • 2.构造函数
    • 3.打开数据库
      • 3.1 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
      • 3.2 设置数据模型、选择模型、界面组件与模型数据字段间的数据映射
    • 4.记录移动
  • 二、QSqlQueryModel 和 QSqlQuery 联合使用
    • 1.主窗口 MainWindow 类定义
    • 2.构造函数
    • 3.编辑记录对话框
    • 4.编辑记录
    • 5.插入记录
    • 6.删除记录
    • 7.记录遍历

关于QSqlDatabase、QSqlQueryModel 、QSqlQuery、QSqlRecord、QDataWidgetMapper 类的使用可参考:Qt基础 | Qt SQL模块介绍 | Qt SQL模块常用类及其常用函数介绍

一、QSqlQueryModel 的使用

  使用 QSqlQueryModel 可以从一个数据表或多个数据表里查询数据,只需设计好 SELECT 语句即可。

1.主窗口类定义

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>#include    <QLabel>
#include    <QString>#include    <QtSql>
#include    <QDataWidgetMapper>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTprivate:QLabel  *LabInfo;QSqlDatabase  DB; //数据库QSqlQueryModel  *qryModel; //数据模型QItemSelectionModel *theSelection; //选择模型QDataWidgetMapper   *dataMapper;//数据界面映射void    openTable();//打开数据表void    refreshTableView();//移动记录时刷新TableView的当前行
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:// QTableView的SelectionModel的行发生了变化,进行处理void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);void on_actOpenDB_triggered();void on_actRecFirst_triggered();void on_actRecPrevious_triggered();void on_actRecNext_triggered();void on_actRecLast_triggered();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

MainWindow 类中定义了几个私有变量:

  • QSqlDatabase DB:用于加载数据库驱动和建立与数据库之间的连接

  • QSqlQueryModel *qryModel:作为数据表的数据模型

  • QItemSelectionModel *theSelection:作为 qryModel 的选择模型,提供 currentChanged()、currentRowChanged()信号,在 qryModel 选择的字段发生变化、当前记录发生变化时发射信号,以便程序进行响应。

    例如,在 currentRowChanged() 信号发射时,设置记录按钮的使能状态,并处理 Photo 字段的查询与照片显示。

  • QDataWidgetMapper *dataMapper:用于实现界面组件与 qryModel 的字段之间的映射。

公有函数:

  • openTable函数用于打开数据库、查询数据、建立界面显示等操作
  • refreshTableView函数用于记录移动后刷新 tableView 上的当前行位置。

槽函数:

  • on_currentRowChanged函数用于在记录移动时,查询出 Memo 和 Photo 字段的内容,并在界面上显示出来。

2.构造函数

  MainWindow 的构造函数代码如下,主要是对 tableView 一些显示属性的设置。

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);LabInfo=new QLabel("记录条数",this);LabInfo->setMinimumWidth(200);ui->statusBar->addWidget(LabInfo);this->setCentralWidget(ui->splitter);ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);ui->tableView->setAlternatingRowColors(true);
}
  • setSelectionBehavior函数:用于定义视图(View)选择哪种选择行为

  • setSelectionMode函数:用于定义视图(view)的选择模式

  • setAlternatingRowColors函数:用来控制当前是否启用交替行颜色绘制背景

3.打开数据库

  打开数据库这一部分主要包括:

  • 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
  • 设置数据模型、选择模型、界面组件与模型数据字段间的数据映射

3.1 添加 SQLite 数据库驱动、设置数据库名称、打开数据库

  这一部分主要用到了 QSqlDatabase 类,该类用于处理与数据库的连接。

void MainWindow::on_actOpenDB_triggered()
{//打开数据库QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","","SQL Lite数据库(*.db *.db3)");if (aFile.isEmpty())return;//打开数据库DB=QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动DB.setDatabaseName(aFile); //设置数据库名称
//    DB.setHostName();
//    DB.setUserName();
//    DB.setPassword();if (!DB.open())   //打开数据库{QMessageBox::warning(this, "错误", "打开数据库失败",QMessageBox::Ok,QMessageBox::NoButton);return;}//打开数据表openTable();
}

3.2 设置数据模型、选择模型、界面组件与模型数据字段间的数据映射

  使用 QSqlQueryModel 作为数据模型从数据库里查询数据,只需使用 setQuery() 函数设置一个 SELECT 查询语句即可。

qryModel=new QSqlQueryModel(this);
qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "" Education, Salary FROM employee ORDER BY empNo");
if (qryModel->lastError().isValid())
{QMessageBox::critical(this, "错误", "数据表查询错误,错误信息\n"+qryModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);return;
}

  使用 setHeaderData() 函数为每个字段设置显示标题。

qryModel->setHeaderData(0,Qt::Horizontal,"工号");
qryModel->setHeaderData(1,Qt::Horizontal,"姓名");
qryModel->setHeaderData(2,Qt::Horizontal,"性别");
qryModel->setHeaderData(3,Qt::Horizontal,"身高");
qryModel->setHeaderData(4,Qt::Horizontal,"出生日期");
qryModel->setHeaderData(5,Qt::Horizontal,"手机");
qryModel->setHeaderData(6,Qt::Horizontal,"省份");
qryModel->setHeaderData(7,Qt::Horizontal,"城市");
qryModel->setHeaderData(8,Qt::Horizontal,"部门");
qryModel->setHeaderData(9,Qt::Horizontal,"学历");
qryModel->setHeaderData(10,Qt::Horizontal,"工资");

  为 qryModel 创建选择模型 theSelection,并将其 currentRowChanged() 信号与槽函数 on_currentRowChanged() 关联起来。这个槽函数用于在记录移动时,查询除 Memo 和 Photo 字段的内同,并在界面上显示出来。

theSelection=new QItemSelectionModel(qryModel);
//选择行变化时
connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));

其对应槽函数为:

void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{Q_UNUSED(previous);if (!current.isValid()){ui->dbLabPhoto->clear();return;}dataMapper->setCurrentModelIndex(current);bool first=(current.row()==0); //是否首记录bool last=(current.row()==qryModel->rowCount()-1);//是否尾记录ui->actRecFirst->setEnabled(!first); //更新使能状态ui->actRecPrevious->setEnabled(!first);ui->actRecNext->setEnabled(!last);ui->actRecLast->setEnabled(!last);int curRecNo=theSelection->currentIndex().row();QSqlRecord  curRec=qryModel->record(curRecNo); //获取当前记录int empNo=curRec.value("EmpNo").toInt();QSqlQuery query; //查询当前empNo的Memo和Photo字段的数据query.prepare("select EmpNo, Memo, Photo from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();query.first();QVariant    va=query.value("Photo");//if (!va.isValid())  //图片字段内容为空ui->dbLabPhoto->clear();else{//显示照片QByteArray data=va.toByteArray();QPixmap pic;pic.loadFromData(data);ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));}QVariant    va2=query.value("Memo");//显示备注ui->dbEditMemo->setPlainText(va2.toString());
}

这个槽函数有 3 个功能:

  • 第一个功能是更新数据映射的行号,使窗口上的字段关联的显示组件刷新显示当前记录的内容。
  • 第二个功能是根据当前行号,判断是否是首记录或尾记录,以更新 4 个记录移动的 Action 的使能状态。
  • 第三个功能是获取当前记录的 EmpNo 字段的值(即员工编号),然后使用 QSqlQuery 执行查询语句 ,只查询出这个员工的 Memo 和 Photo 字段的数据,然后在界面元件上显示。

  接下来,设置 tableView 的数据模型和选择模型,

ui->tableView->setModel(qryModel);
ui->tableView->setSelectionModel(theSelection);

  然后,创建数据界面映射,设置各个界面组件与字段的映射关系。

//创建数据映射
dataMapper= new QDataWidgetMapper();
dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
dataMapper->setModel(qryModel);
dataMapper->addMapping(ui->dbSpinEmpNo,0);//"empNo";
dataMapper->addMapping(ui->dbEditName,1);//"Name";
dataMapper->addMapping(ui->dbComboSex,2);//"Gender";dataMapper->addMapping(ui->dbSpinHeight,3);//"Height";
dataMapper->addMapping(ui->dbEditBirth,4);//"Birthday";
dataMapper->addMapping(ui->dbEditMobile,5);//"Mobile";dataMapper->addMapping(ui->dbComboProvince,6);//"Province";
dataMapper->addMapping(ui->dbEditCity,7);//"City";
dataMapper->addMapping(ui->dbComboDep,8);//"Department";dataMapper->addMapping(ui->dbComboEdu,9);//"Education";
dataMapper->addMapping(ui->dbSpinSalary,10);//"Salary";dataMapper->toFirst();

4.记录移动

  由于选中行发生变化时,会引起数据模型关联的选择模型发射 currentRowChanged() 信号,在关联的槽函数中会更新数据映射的行号。因此,为数据映射的 QDataWidgetMapper 类设置数据模型后,总是指向数据模型的按当前记录。

void MainWindow::on_actRecFirst_triggered()
{ //首记录dataMapper->toFirst();refreshTableView();
}void MainWindow::on_actRecPrevious_triggered()
{ //前一条记录dataMapper->toPrevious();refreshTableView();
}void MainWindow::on_actRecNext_triggered()
{//后一条记录dataMapper->toNext();refreshTableView();
}void MainWindow::on_actRecLast_triggered()
{//最后一条记录dataMapper->toLast();refreshTableView();
}

  QDataWidgetMapper 有 4 个函数进行当前记录的移动,分别是 toFirst()、toLast()、toNext() 和 toPrevious() 。使用 QDataWidgetMapper 的记录移动操作后,QDataWidgetMapper 会移动到新纪录上,映射了字段的界面组件会自动显示新记录的字段的数据。但是,tableView 的当前行并不会自动变化,所以需要调用 refreshTableView() 函数刷新 tableView 的显示,其代码为:

void MainWindow::refreshTableView()
{//刷新tableView的当前选择行int index=dataMapper->currentIndex();QModelIndex curIndex=qryModel->index(index,1);//theSelection->clearSelection();//清空选择项theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//设置刚插入的行为当前选择行
}

二、QSqlQueryModel 和 QSqlQuery 联合使用

  QSqlQueryModel 可以查询数据并作为数据模型,实现数据的显示,QSqlQuery 可以执行 UPDATE、INSERT、DELETE 等 SQL 语句实现数据的编辑修改。

1.主窗口 MainWindow 类定义

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include    <QLabel>
#include    <QString>
#include    <QtSql>
#include    <QDataWidgetMapper>namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECT
private:QSqlDatabase  DB; //数据库QSqlQueryModel  *qryModel; //数据库模型QItemSelectionModel *theSelection; //选择模型void    openTable();//打开数据表void    updateRecord(int recNo); //更新记录
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:// QTableView的SelectionModel的行发生了变化,进行处理
//    void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);void on_actOpenDB_triggered();void on_actRecInsert_triggered();void on_actRecDelete_triggered();void on_actRecEdit_triggered();void on_tableView_doubleClicked(const QModelIndex &index);void on_actScan_triggered();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

MainWindow 类中定义了几个私有变量:

  • QSqlDatabase DB:用于加载数据库驱动和建立与数据库之间的连接
  • QSqlQueryModel *qryModel:作为数据表的数据模型
  • QItemSelectionModel *theSelection:作为 qryModel 的选择模型

函数:

  • openTable:创建数据模型与选择模型,使用 setQuery() 函数查询数据库中除了 Memo 和 Photo 之外的其他字段内容,设置字段的显示标题,为 tableView 设置数据模型与选择模型,设置一些 Action 的使能状态

    没有为选择模型的 currentRowChanged()信号关联槽函数,因为不需要在记录移动时做什么处理。由于使用 QSqlQueryModel 作为 tablView 数据源,在 tableView 里是无法编辑修改数据的。

  • updateRecord:实现当前记录的编辑并更新到数据库表中。

    步骤包括:

    • 从数据库表中查询除当前员工的所有字段的值
    • 调用对话框更新数据和界面
    • 当 “确认” 键被按下时,获取对话框返回的记录
    • 使用 UPDATE 子句更新一条记录到数据库表中
    • 更新成功后,将数据模型 qryModel 的 SELECT 语句重新执行一次,可刷新 tableView 的显示

2.构造函数

  MainWindow 的构造函数代码如下,主要是对 tableView 一些显示属性的设置。

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);this->setCentralWidget(ui->tableView);ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);ui->tableView->setAlternatingRowColors(true);//    ui->tableView->resizeColumnsToContents();//    ui->tableView->horizontalHeader()->setStretchLastSection(true);
}
  • setSelectionBehavior函数:用于定义视图(View)选择哪种选择行为

  • setSelectionMode函数:用于定义视图(view)的选择模式

  • setAlternatingRowColors函数:用来控制当前是否启用交替行颜色绘制背景

3.编辑记录对话框

  由于 tableView 上无法编辑修改数据,只是作为一个只读的数据显示。在 ”插入记录” 和 “编辑记录” 都会打开一个对话框,编辑一条记录的所有字段数据,确认插入后用 QSqlQuery 执行一条 INSERT 语句插入一条记录,确认编辑时用 QSqlQuery 执行一个 UPDATE 语句更新一条记录。

WDialogData类定义

#ifndef WDIALOGDATA_H
#define WDIALOGDATA_H#include <QDialog>
#include    <QSqlRecord>namespace Ui {
class WDialogData;
}class WDialogData : public QDialog
{Q_OBJECTprivate:QSqlRecord  mRecord; //保存一条记录的数据public:explicit WDialogData(QWidget *parent = 0);~WDialogData();void    setUpdateRecord(QSqlRecord &recData); //更新记录void    setInsertRecord(QSqlRecord &recData); //插入记录QSqlRecord  getRecordData();//获取录入的数据private slots:void on_btnClearPhoto_clicked(); //清理照片void on_btnSetPhoto_clicked(); //设置照片private:Ui::WDialogData *ui;
};#endif // WDIALOGDATA_H

私有属性说明:

  • QSqlRecord mRecord:用于存储一条记录的数据

函数:

  • setInsertRecord():插入一条记录时,创建对话框后调用 setInsertRecord() 函数初始化对话框的数据
  • setUpdateRecord():编辑一条记录时,创建对话框后调用 setUpdateRecord() 函数初始化对话框的数据
  • getRecordData():对话框确认修改后,调用 getRecordData() 函数,将对话框中的界面组件数据存入 mRecord,并将 mRecord 作为返回值,返回编辑后的一条记录的数据。

槽函数:

  • on_btnClearPhoto_clicked:清除图片显示与清空 记录中的 Photo 字段
  • on_btnSetPhoto_clicked:选择图片,将图片保存到 Photo 字段,重新显示图片

setInsertRecord函数

void WDialogData::setInsertRecord(QSqlRecord &recData)
{//插入记录,无需更新界面显示,但是要存储recData的字段结构mRecord=recData; //保存recData到内部变量ui->spinEmpNo->setEnabled(true); //插入的记录,员工编号允许编辑setWindowTitle("insert a new record");ui->spinEmpNo->setValue(recData.value("empNo").toInt());
}

setUpdateRecord函数

void WDialogData::setUpdateRecord(QSqlRecord &recData)
{ //编辑记录,更新记录数据到界面mRecord=recData;ui->spinEmpNo->setEnabled(false); //员工编号不允许编辑setWindowTitle("更新记录");//根据recData的数据更新界面显示ui->spinEmpNo->setValue(recData.value("empNo").toInt());ui->editName->setText(recData.value("Name").toString());ui->comboSex->setCurrentText(recData.value("Gender").toString());ui->spinHeight->setValue(recData.value("Height").toFloat());ui->editBirth->setDate(recData.value("Birthday").toDate());ui->editMobile->setText(recData.value("Mobile").toString());ui->comboProvince->setCurrentText(recData.value("Province").toString());ui->editCity->setText(recData.value("City").toString());ui->comboDep->setCurrentText(recData.value("Department").toString());ui->comboEdu->setCurrentText(recData.value("Education").toString());ui->spinSalary->setValue(recData.value("Salary").toInt());ui->editMemo->setPlainText(recData.value("Memo").toString());QVariant    va=recData.value("Photo");//if (!va.isValid())  //图片字段内容为空ui->LabPhoto->clear();else{QByteArray data=va.toByteArray();QPixmap pic;pic.loadFromData(data);ui->LabPhoto->setPixmap(pic.scaledToWidth(ui->LabPhoto->size().width()));}
}

getRecordData函数

QSqlRecord WDialogData::getRecordData()
{ //"确定"按钮后,界面数据保存到记录mRecordmRecord.setValue("empNo",ui->spinEmpNo->value());mRecord.setValue("Name",ui->editName->text());mRecord.setValue("Gender",ui->comboSex->currentText());mRecord.setValue("Height",ui->spinHeight->value());mRecord.setValue("Birthday",ui->editBirth->date());mRecord.setValue("Mobile",ui->editMobile->text());mRecord.setValue("Province",ui->comboProvince->currentText());mRecord.setValue("City",ui->editCity->text());mRecord.setValue("Department",ui->comboDep->currentText());mRecord.setValue("Education",ui->comboEdu->currentText());mRecord.setValue("Salary",ui->spinSalary->value());mRecord.setValue("Memo",ui->editMemo->toPlainText());//照片编辑时已经修改了mRecord的photo字段的值return  mRecord; //以记录作为返回值
}

槽函数

void WDialogData::on_btnClearPhoto_clicked()
{ //清除照片ui->LabPhoto->clear();mRecord.setNull("Photo"); //Photo字段清空
}void WDialogData::on_btnSetPhoto_clicked()
{//设置照片QString aFile=QFileDialog::getOpenFileName(this,"选择图片文件","","照片(*.jpg)");if (aFile.isEmpty())return;QByteArray data;QFile* file=new QFile(aFile); //fileName为二进制数据文件名file->open(QIODevice::ReadOnly);data = file->readAll();file->close();mRecord.setValue("Photo",data); //图片保存到Photo字段QPixmap pic;pic.loadFromData(data);ui->LabPhoto->setPixmap(pic.scaledToWidth(ui->LabPhoto->size().width()));
}

4.编辑记录

  点击工具栏中的 “编辑记录” 按钮,或在 tableView 上双击某条记录,会编辑当前记录。

void MainWindow::on_actRecEdit_triggered()
{//编辑当前记录int curRecNo=theSelection->currentIndex().row();updateRecord(curRecNo);
}void MainWindow::on_tableView_doubleClicked(const QModelIndex &index)
{ //tableView上双击,编辑当前记录int curRecNo=index.row();updateRecord(curRecNo);
}

  调用 updateRecord() 函数来实现当前记录的编辑并更新到数据库表中。

void MainWindow::updateRecord(int recNo)
{ //更新一条记录QSqlRecord  curRec=qryModel->record(recNo); //获取当前记录int empNo=curRec.value("EmpNo").toInt();//获取EmpNoQSqlQuery query; //查询出当前记录的所有字段query.prepare("select * from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();query.first();if (!query.isValid()) //是否为有效记录return;curRec=query.record();//获取当前记录的数据WDialogData    *dataDialog=new WDialogData(this); //创建对话框Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dataDialog->setUpdateRecord(curRec);//调用对话框函数更新数据和界面int ret=dataDialog->exec();// 以模态方式显示对话框if (ret==QDialog::Accepted) //OK键被按下{QSqlRecord  recData=dataDialog->getRecordData(); //获得对话框返回的记录query.prepare("update employee set Name=:Name, Gender=:Gender,Height=:Height,"" Birthday=:Birthday, Mobile=:Mobile, Province=:Province,"" City=:City, Department=:Department, Education=:Education,"" Salary=:Salary, Memo=:Memo, Photo=:Photo "" where EmpNo = :ID");query.bindValue(":Name",recData.value("Name"));query.bindValue(":Gender",recData.value("Gender"));query.bindValue(":Height",recData.value("Height"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Mobile",recData.value("Mobile"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":City",recData.value("City"));query.bindValue(":Department",recData.value("Department"));query.bindValue(":Education",recData.value("Education"));query.bindValue(":Salary",recData.value("Salary"));query.bindValue(":Memo",recData.value("Memo"));query.bindValue(":Photo",recData.value("Photo"));query.bindValue(":ID",empNo);if (!query.exec())QMessageBox::critical(this, "错误", "记录更新错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);elseqryModel->query().exec();//数据模型重新查询数据,更新tableView显示}delete dataDialog;
}

5.插入记录

  首先用 QSqlQuery 类对象 query 执行一行 SQL 语句 select * from employee where EmpNo =-1 ,这样不会查询到任何记录 ,目的就是得到一条空记录;然后设置空记录的主键 EmpNo 字段的值,调用 setInsertRecord() 函数初始化对话框;对话框运行 “确认”返回后,使用query 执行 INSERT 语句插入一条新记录。 若插入记录执行成功,需要重新执行数据模型的查询语句,才会更新界面上的tableView 的显示。

void MainWindow::on_actRecInsert_triggered()
{//插入记录QSqlQuery query;query.exec("select * from employee where EmpNo =-1"); //实际不查询出记录,只查询字段信息QSqlRecord curRec=query.record();//获取当前记录,实际为空记录curRec.setValue("EmpNo",qryModel->rowCount()+3000);WDialogData    *dataDialog=new WDialogData(this);Qt::WindowFlags    flags=dataDialog->windowFlags();dataDialog->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //设置对话框固定大小dataDialog->setInsertRecord(curRec); //插入记录int ret=dataDialog->exec();// 以模态方式显示对话框if (ret==QDialog::Accepted) //OK键被按下{QSqlRecord  recData=dataDialog->getRecordData();query.prepare("INSERT INTO employee (EmpNo,Name,Gender,Height,Birthday,Mobile,Province,"" City,Department,Education,Salary,Memo,Photo) "" VALUES(:EmpNo,:Name, :Gender,:Height,:Birthday,:Mobile,:Province,"" :City,:Department,:Education,:Salary,:Memo,:Photo)");query.bindValue(":EmpNo",recData.value("EmpNo"));query.bindValue(":Name",recData.value("Name"));query.bindValue(":Gender",recData.value("Gender"));query.bindValue(":Height",recData.value("Height"));query.bindValue(":Birthday",recData.value("Birthday"));query.bindValue(":Mobile",recData.value("Mobile"));query.bindValue(":Province",recData.value("Province"));query.bindValue(":City",recData.value("City"));query.bindValue(":Department",recData.value("Department"));query.bindValue(":Education",recData.value("Education"));query.bindValue(":Salary",recData.value("Salary"));query.bindValue(":Memo",recData.value("Memo"));query.bindValue(":Photo",recData.value("Photo"));if (!query.exec())QMessageBox::critical(this, "错误", "插入记录错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);else //插入,删除记录后需要重新设置SQL语句查询{QString sqlStr=qryModel->query().executedQuery();//  执行过的SELECT语句qryModel->setQuery(sqlStr);         //重新查询数据}}delete dataDialog;
}

6.删除记录

  从数据模型的当前记录中获取员工编号,然后使用 QSqlQuery 类的对象执行一条 DELETE 语句删除这条记录。删除记录后需要重新设置数据模型 qryModel 的 SQL 语句并查询数据,以更新数据和 tableView 的显示。

void MainWindow::on_actRecDelete_triggered()
{//删除当前记录int curRecNo=theSelection->currentIndex().row();QSqlRecord  curRec=qryModel->record(curRecNo); //获取当前记录if (curRec.isEmpty()) //当前为空记录return;int empNo=curRec.value("EmpNo").toInt();//获取员工编号QSqlQuery query;query.prepare("delete  from employee where EmpNo = :ID");query.bindValue(":ID",empNo);if (!query.exec())QMessageBox::critical(this, "错误", "删除记录出现错误\n"+query.lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);else //插入,删除记录后需要重新设置SQL语句查询{QString sqlStr=qryModel->query().executedQuery();//  执行过的SELECT语句qryModel->setQuery(sqlStr);         //重新查询数据}
}

7.记录遍历

  通过记录遍历,修改所有记录的 Salary 字段的值。

void MainWindow::on_actScan_triggered()
{//涨工资,记录遍历QSqlQuery qryEmpList; //员工工资信息列表
//    qryEmpList.setForwardOnly(true);qryEmpList.exec("SELECT empNo,Salary FROM employee ORDER BY empNo");qryEmpList.first();QSqlQuery qryUpdate; //临时 QSqlQueryqryUpdate.prepare("UPDATE employee SET Salary=:Salary WHERE EmpNo = :ID");while (qryEmpList.isValid()) //当前记录有效{int empID=qryEmpList.value("empNo").toInt(); //获取empNofloat salary=qryEmpList.value("Salary").toFloat(); //获取Salarysalary=salary+1000; //涨工资qryUpdate.bindValue(":ID",empID);qryUpdate.bindValue(":Salary",salary); //设置SQL语句参数qryUpdate.exec(); //执行updateif (!qryEmpList.next()) //移动到下一条记录,并判断是否到末尾了break;}qryModel->query().exec();//数据模型重新查询数据,更新tableView的显示QMessageBox::information(this, "提示", "涨工资计算完毕",QMessageBox::Ok,QMessageBox::NoButton);
}

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

生鲜云订单零售系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商品分类管理&#xff0c;商品信息管理&#xff0c;订单评价管理&#xff0c;订单管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;商品信息&#…

[Unity] ShaderGraph实现镜头加速线/残血效果 URP

效果如下所示&#xff1a;残血状态时&#xff0c;画面会压暗角&#xff0c;并出现速度线营造紧迫感。 使用到的素材如下&#xff0c;换别的当然也可以。[这是张白色的png放射图&#xff0c;并非皇帝的新图hhh] 这个效果的实现逻辑&#xff0c;其实就是利用time向圆心做透明度的…

2024经济师考试报名『注册流程』图解!

⏰报名时间&#xff1a;8月12日—9月11日 ☑️报名注册流程 1、经济师考试报名注册网站&#xff1a;中国人事考试网. 2、点击考生登录栏目中的【新用户注册】按钮&#xff0c;进行注册。 3、进入用户注册界面&#xff0c;填写注册信息。 4、填写完毕确认无误后点击【提交】&…

Unity UGUI 之 Mask

本文仅作学习笔记与交流&#xff0c;不作任何商业用途 本文包括但不限于unity官方手册&#xff0c;唐老狮&#xff0c;麦扣教程知识&#xff0c;引用会标记&#xff0c;如有不足还请斧正 本文在发布时间选用unity 2022.3.8稳定版本&#xff0c;请注意分别 1.什么是遮罩 遮罩是一…

深度解读大语言模型中的Transformer架构

一、Transformer的诞生背景 传统的循环神经网络&#xff08;RNN&#xff09;和长短期记忆网络&#xff08;LSTM&#xff09;在处理自然语言时存在诸多局限性。RNN 由于其递归的结构&#xff0c;在处理长序列时容易出现梯度消失和梯度爆炸的问题。这导致模型难以捕捉长距离的依…

学习react-登录状态验证

1.创建三个页面LoginPage, HomePage,NotFoundPage用于Router 创建LoginPage.tsx用于做登录页面 // LoginPage.tsx const LoginPage (props:LoginProp) > {const navigate useNavigate();return( <h1 onClick{ ()>{navigate("/");}}>Hello Login, {pr…

02 Go语言操作MySQL基础教程_20240729 课程笔记

概述 如果您没有Golang的基础&#xff0c;应该学习如下前置课程。 Golang零基础入门Golang面向对象编程Go Web 基础Go语言开发REST API接口_20240728 基础不好的同学每节课的代码最好配合视频进行阅读和学习&#xff0c;如果基础比较扎实&#xff0c;则阅读本教程巩固一下相…

微信小游戏之 三消(一)

首先设定一下 单个 方块 cell 类&#xff1a; 类定义和属性 init 方法 用于初始化方块&#xff0c;接收游戏实例、数据、宽度、道具类型和位置。 onWarning 方法 设置警告精灵的帧&#xff0c;并播放闪烁动作&#xff0c;用于显示方块的警告状态。 grow 方法 根据传入的方向…

21.发布确认模式-高级

问题 生产环境中由于一些不明原因&#xff0c;导致rabbitmq重启&#xff0c;在重启的期间生产者消息投递失败&#xff0c;导致消息丢失&#xff0c;需要手动处理恢复。那么如何才能进行rabbitmq的消息可靠性投递&#xff1f;特别是在极端的情况&#xff0c;rabbitmq集群不可用…

文件操作相关的精讲

目录&#xff1a; 思维导图 一. 文件定义 二. 文件的打开和关闭 三. 文件的顺序读写操作 四. 文件的随机读写操作 五. 文本文件和二进制文件 六. 文件读取结束的判断 七.文件缓冲区 思维导图&#xff1a; 一. 文件定义 1.文件定义 C语言中&#xff0c;文件是指一组相…

Vue3可媲美Element Plus Tree组件实战之移除节点

Element Plus Tree自定义节点内容示例中介绍了移除节点的用法&#xff0c;个人觉得作为提供给用户API&#xff0c;应该遵循迪米特法则&#xff0c;把功能实现的细节封装在组件内部&#xff0c;而提供给用户最简单的操作方式&#xff0c;同时在此基础上支持用户的扩展。 因此&a…

接口测试支持IDEA插件一键同步API、新增思维导图快速评审测试用例,MeterSphere开源持续测试工具v3.1.0版本发布

2024年7月29日&#xff0c;MeterSphere开源持续测试工具正式发布v3.1.0版本。 在这一版本中&#xff0c;接口测试方面&#xff0c;支持通过IDEA插件一键同步API至MeterSphere&#xff1b;测试管理方面&#xff0c;“测试用例”模块新增通过思维导图模式快捷评审测试用例。在“…

挑战房市预测领头羊:KNN vs. 决策树 vs. 线性回归

挑战房市预测领头羊&#xff08;KNN&#xff0c;决策树&#xff0c;线性回归&#xff09; 1. 介绍1.1 K最近邻&#xff08;KNN&#xff09;&#xff1a;与邻居的友谊1.1.1 KNN的基础1.1.2 KNN的运作机制1.1.3 KNN的优缺点 1.2 决策树&#xff1a;解码房价的逻辑树1.2.1 决策树的…

CSS实现文本溢出处理

1.单行文本溢出 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-wid…

总结——TI_音频信号分析仪

一、简介 设备&#xff1a;MSPM0G3507 库&#xff1a;CMSIS-DSP TI 数据分析&#xff1a;FFT 软件&#xff1a;CCS CLion MATLAB 目的&#xff1a;对音频信号进行采样&#xff08;滤波偏置处理&#xff09;&#xff0c;通过FFT获取信号的频率成分&am…

【Vue3】watchEffect

【Vue3】watchEffect 背景简介开发环境开发步骤及源码 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的日子。本文…

了解Selenium中的WebElement

Selenium中到处都使用WebElement来执行各种操作。什么是WebElement&#xff1f;这篇文章将详细讨论WebElement。 Selenium中的WebElement是一个表示网站HTML元素的Java接口。HTML元素包含一个开始标记和一个结束标记&#xff0c;内容位于这两个标记之间。 HTML元素的重命名 …

C#插件 调用存储过程(输出参数类型)

存储过程 CREATE PROCEDURE [dbo].[GetSum]num1 INT,num2 INT,result INT OUTPUT AS BEGINselect result num1 num2 END C#代码 using Kingdee.BOS; using Kingdee.BOS.App.Data; using Kingdee.BOS.Core.Bill.PlugIn; using Kingdee.BOS.Util; using System; using System.…

放大电路总结

补充: 只有直流移动时才有Rbe动态等效电阻 从RsUs看进去,实际上不管接了什么东西都能够看成是一个Ri(输入电阻) Ri Ui/Ii Rb//Rbe Ui/Us Ri/(RiRs) Aus (Uo/Ui)*(Ui/Us) Au *Ri/(RiRs) 当前面是一个电压源的信号 我们就需要输入电阻更大 Ro--->输出电阻--->将…

基于FFmpeg和SDL的音视频解码播放的实现过程与相关细节

目录 1、视频播放器原理 2、FFMPEG解码 2.1 FFMPEG库 2.2、数据类型 2.3、解码 2.3.1、接口函数 2.3.2、解码流程 3、SDL播放 3.1、接口函数 3.2、视频播放 3.3、音频播放 4、音视频的同步 4.1、获取音频的播放时间戳 4.2、获取当前视频帧时间戳 4.3、获取视…