当前位置: 首页 > news >正文

11-3_Qt 5.9 C++开发指南_QSqlQuery的使用(QSqlQuery 是能执行任意 SQL 语句的类)

文章目录

  • 1. QSqlQuery基本用法
  • 2. QSqlQueryModel和QSqlQuery联合使用
    • 2.1 可视化UI设计框架
      • 2.1.1主窗口的可视化UI设计框架
      • 2.1.2 对话框的可视化UI设计框架
    • 2.2 数据表显示
    • 2.3 编辑记录对话框
    • 2.4 编辑记录
    • 2.5 插入记录
    • 2.6 删除记录
    • 2.7 记录遍历
    • 2.8 程序框架及源码
      • 2.8.1 程序整体框架
      • 2.8.2 源码

1. QSqlQuery基本用法

QSqlQuery 是能执行任意 SQL 语句的类,如 SELECT、INSERT、UPDATE、DELETE 等,QSqlQuery 类的一些常用函数见表 11-11(省略函数中的 const 关键字,省略缺省参数,不同参数的同名函数一般只给出一种参数形式)。

在这里插入图片描述

使用 QSqlQuery 执行不带参数的 SQL 语句时可以用 exec(QString)函数,如:

QSqlQuery query;
query.prepare("SELECT * FROM employee where EmpNo=:ID");
query.bindValue(":ID",2003);
query.exec();

上面是SQL语句中的参数用“冒号+参数名”表示的形式,还可以直接用占位符来表示参数,如:

QSqlQuery query;
query.prepare("UPDATE employee SET Name=?, Gender=?, Height=?, where EmpNo=?");
query.bindValue(0,"高某某");
query.bindValue(1,"男");
query.bindValue(2,1.78);
query.bindValue(3,2010);
query.exec();

2. QSqlQueryModel和QSqlQuery联合使用

2.1 可视化UI设计框架

2.1.1主窗口的可视化UI设计框架

在这里插入图片描述

2.1.2 对话框的可视化UI设计框架

在这里插入图片描述

2.2 数据表显示

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

实例samp11_3 通过联合使用QSqlQueryModel和QSqlQuery 组件实现数据表的显示和编辑修改,下图 是实例 samp11_3 运行主窗口。
在这里插入图片描述

主窗口类定义如下(去掉有些自动生成部分)

#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:QSqlDatabase  DB; //数据库QSqlQueryModel  *qryModel; //数据库模型QItemSelectionModel *theSelection; //选择模型void    openTable();//打开数据表void    updateRecord(int recNo); //更新记录
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

这个主窗口类的定义相比于实例samp11_2只是增加了一个updateRecord()函数。工具栏上的“打开数据库”按钮的代码与实例samp11_2 完全相同,会调用openTable()连接数据库并查询数据表的数据。

本实例的openTable()函数代码如下:

void MainWindow::openTable()
{//打开数据表qryModel=new QSqlQueryModel(this);theSelection=new QItemSelectionModel(qryModel);qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "" Education, Salary FROM employee order by empNo");if (qryModel->lastError().isValid()){QMessageBox::information(this, "错误", "数据表查询错误,错误信息\n"+qryModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);return;}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,"工资");ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(theSelection);
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);ui->actOpenDB->setEnabled(false);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actRecEdit->setEnabled(true);ui->actScan->setEnabled(true);
}

openTable()函数创建了QSqlQueryModel类对象qryModel,从数据表employee 里查询出除了Memo和 Photo 之外的其他字段,并作为界面上的 tableView 的数据模型。还创建了选择模型 theSelection,但是没有为选择模型的currentRowChanged()信号关联槽函数,因为不需要在记录移动时做什么处理。由于使用QSqlQueryModel作为 tableView 的数据源,在 tableView 里是无法编辑修改数据的。

2.3 编辑记录对话框

由于在 tableView 上无法编辑修改数据,只是作为一个只读的数据显示,在主窗口工具栏上提供了“插入记录”“编辑记录”“删除记录”3 个按钮对数据进行编辑。“插入记录”和“编辑记录都会打开一个对话框,编辑一条记录的所有字段数据,确认插入后用 QSqlQuery 执行一条INSERT语句插入一条记录,确认编辑时用 QSqlQuery 执行一个UPDATE 语句更新一条记录。

设计了一个对话框 WDialogData,用于编辑一条记录的所有字段的数据,在“插入记录”和“编辑记录”时调用此对话框,对话框运行界面如下图所示。

在这里插入图片描述

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()函数初始化对话框的数据;编辑一条记
录时,创建对话框后调用 setUpdateRecord ()函数初始化对话框的数据。

对话框确认修改后,调用getRecordData()时,界面数据存入 mRecord,并将mRecord 作为返回值,返回编辑后的一条记录的数据。
对话框 WDialogData 的所有自定义函数,以及对话框上的“导入照片”“清除照片”按钮的代码如下,程序代码比较简单,这里不再过多解释。

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

2.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()函数,并且以记录的序号作为传递参数。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;
}

函数 updateRecord(int recNo)根据行号 reNo 从 qryModel 获取当前记录的 EmpNo 字段的值,即员工编号,然后使用一个QSqlQuery 对象从数据表里查询出这一个员工的所有字段的一条记录。使用 QsqlQuery 时用到了参数 SQL 语句:

    query.prepare("select * from employee where EmpNo = :ID");query.bindValue(":ID",empNo);query.exec();

由于 EmpNo 是数据表 employee 的主键字段,不允许出现重复,所以只会查询出一条记录,查询出的一条完整记录保存到变量 curRec。
然后创建 WDialogData 类型的对话框 dataDialog,调用 setUpdateRecord(curRec)将完整记录传递给对话框。对话框执行后,如果是“确定”返回,则通过 getRecordData()函数获取对话框编辑后的记录数据:

QSqlRecord  recData=dataDialog->getRecordData(); //获得对话框返回的记录

recData 里包含了编辑后的最新数据,然后使用 QSqlQuery 对象执行带参数的 UPDATE 语句更新一条记录。更新成功后,将数据模型 qryModel的SELECT 语句重新执行一次,可刷新 tableView的显示。

2.5 插入记录

工具栏上的”插入记录“可以插入一条新记录,代码如下:

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;
}

程序首先用QSqlQuery类对象query 执行一个SQL语“select * from employee where EmpNo=-1”这样不会查询到任何记录,目的就是得到一条空记录 curRec。

创建 WDialogData 类型的对话框 dataDialog 后,调用setInsertRecord()函数对话框进行初始化设置。
对话框 dataDialog运行“确认”返回后,使用query 执行INSERT 语插入一条新记录。若插入记录执行成功,需要重新执行数据模型 qryModel 的 SQL 语查询数据,才会更新界面上的tableView 的显示。

2.6 删除记录

工具栏上的“删除记录”删除 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);         //重新查询数据}
}

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

2.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);
}

程序里使用了两个 QSqlQuery 类变量,qryEmpList 查询 EmpNo 和 Salary 两个字段的全部记录,qryUpdate 用于执行一个带参数的 UPDATE 语句,每次更新一条记录。

遍历 qryEmpList 的所有记录,QSqlQuery 有 first()、previous()、next()、last()等函数记录移动,若到了最后一条记录后再执行 next(),将返回 false,以此判断是否遍历完所有记录。

2.8 程序框架及源码

2.8.1 程序整体框架

在这里插入图片描述

2.8.2 源码

(1)mainwindow.h

#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: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

(2)mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"#include    <QFileDialog>
#include    <QMessageBox>
#include    "wdialogdata.h"void MainWindow::openTable()
{//打开数据表qryModel=new QSqlQueryModel(this);theSelection=new QItemSelectionModel(qryModel);qryModel->setQuery("SELECT empNo, Name, Gender, Height, Birthday, Mobile, Province, City, Department, "" Education, Salary FROM employee order by empNo");if (qryModel->lastError().isValid()){QMessageBox::information(this, "错误", "数据表查询错误,错误信息\n"+qryModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);return;}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,"工资");ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(theSelection);
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);ui->actOpenDB->setEnabled(false);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actRecEdit->setEnabled(true);ui->actScan->setEnabled(true);
}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;
}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);
}MainWindow::~MainWindow()
{delete ui;
}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();
}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;
}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);         //重新查询数据}
}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);
}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);
}

(3)wdialogdata.h

#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

(4)wdialogdata.cpp

#include "wdialogdata.h"
#include "ui_wdialogdata.h"#include    <QFileDialog>WDialogData::WDialogData(QWidget *parent) :QDialog(parent),ui(new Ui::WDialogData)
{ui->setupUi(this);
}WDialogData::~WDialogData()
{delete ui;
}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()));}
}void WDialogData::setInsertRecord(QSqlRecord &recData)
{//插入记录,无需更新界面显示,但是要存储recData的字段结构mRecord=recData; //保存recData到内部变量ui->spinEmpNo->setEnabled(true); //插入的记录,员工编号允许编辑
//    setWindowTitle("插入新记录");
//    ui->spinEmpNo->setValue(recData.value("empNo").toInt());setWindowTitle("Insert new record");ui->spinEmpNo->setValue(recData.value("empNo").toInt());
}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()));
}

相关文章:

11-3_Qt 5.9 C++开发指南_QSqlQuery的使用(QSqlQuery 是能执行任意 SQL 语句的类)

文章目录 1. QSqlQuery基本用法2. QSqlQueryModel和QSqlQuery联合使用2.1 可视化UI设计框架2.1.1主窗口的可视化UI设计框架2.1.2 对话框的可视化UI设计框架 2.2 数据表显示2.3 编辑记录对话框2.4 编辑记录2.5 插入记录2.6 删除记录2.7 记录遍历2.8 程序框架及源码2.8.1 程序整体…...

神码ai火车头伪原创插件怎么用【php源码】

大家好&#xff0c;本文将围绕python绘制烟花特定爆炸效果展开说明&#xff0c;如何用python画一朵花是一个很多人都想弄明白的事情&#xff0c;想搞清楚用python画烟花的代码需要先了解以下几个事情。 1、表白烟花代码 天天敲代码的朋友&#xff0c;有没有想过代码也可以变得…...

13.Netty源码之Netty中的类与API

highlight: arduino-light ServerBootstrap Bootstrap 意思是引导&#xff0c;一个 Netty 应用通常由一个 Bootstrap 开始&#xff0c;主要作用是配置整个 Netty 程序&#xff0c;串联各个组件&#xff0c;Netty 中ServerBootstrap 是服务端启动引导类。 java //泛型 AbstractB…...

C# 如何检查数组列表中是否存在数组

原文&#xff1a;https://www.coder.work/article/2958674 列表&#xff1a; 一个数组列表&#xff0c;想检查一个确切的数组是否在列表中 List<int[]> Output new List<int[]>(); 有一个数组 int[] coordinates 想检查coordinates 数组是否在Output 列表中&…...

AI课堂教学质量评估系统算法 yolov7

AI课堂教学质量评估系统通过yolov7网络模型框架利用摄像头和人脸识别技术&#xff0c;AI课堂教学质量评估系统实时监测学生的上课表情和课堂行为。同时&#xff0c;还结合语音识别技术和听课专注度分析算法&#xff0c;对学生的听课专注度进行评估&#xff0c;生成教学质量报告…...

eventBus使用遇到的坑

**问题&#xff1a;**通过eventBus传递的参数&#xff0c;在子组件的methods中无法通过this.使用。 **思路&#xff1a;**考虑组件方法的执行顺序&#xff08;vue生命周期执行顺序&#xff09; **解决办法&#xff1a;**在传递参数的组件外 this.$nextTick this.$nextTick(() …...

ChatGPT应用|科大讯飞星火杯认知大模型场景创新赛开始报名了!

ChatGPT发布带来的 AI 浪潮在全球疯狂蔓延&#xff0c;国内掀起的大模型混战已经持续半年之久&#xff0c;国产大模型数量正以惊人的速度增长&#xff0c;据不完全统计&#xff0c;截止7月14号已经达到了111个&#xff0c;所谓的“神仙打架”不过如此了吧。 &#xff08; 包括但…...

DM8 DSC备份还原

1、检查磁盘空间 检查服务器磁盘空间使用情况&#xff0c;确认磁盘有充足的空间存放物理备份。 查看磁盘空间使用情况&#xff08;备份在端点0&#xff0c;此处检查端点0&#xff09; su - dmdba [dmdbacentos-04 ~]$ df -h 文件系统 容量 已用 可用 已用% …...

【Docker--harbor私有仓库部署与管理】

目录 一、Harbor 部署1. 部署 Docker-Compose 服务2. 部署 Harbor 服务&#xff08;1&#xff09;下载或上传 Harbor 安装程序&#xff08;2&#xff09;修改harbor安装的配置文件 3. 启动 Harbor4. 查看 Harbor 启动镜像5. 创建一个新项目1、在虚拟上进行登录 Harbor2、下载镜…...

基于量子同态加密的安全多方凸包协议

摘要安全多方计算几何(SMCG)是安全多方计算的一个分支。该协议是为SMCG中安全的多方凸包计算而设计的。首先&#xff0c;提出了一种基于量子同态加密的安全双方值比较协议。由于量子同态加密的性质&#xff0c;该协议可以很好地保护量子电路执行过程中数据的安全性和各方之间的…...

MySQL案例——多表查询以及嵌套查询

系列文章目录 MySQL笔记——表的修改查询相关的命令操作 MySQL笔记——MySQL数据库介绍以及在Linux里面安装MySQL数据库&#xff0c;对MySQL数据库的简单操作&#xff0c;MySQL的外接应用程序使用说明 文章目录 系列文章目录 前言 一 创建数据库 1.1 创建一个部门表 1.…...

AI 视频清晰化CodeFormer-Deepfacelab

CodeFormer 概述 (a) 我们首先学习一个离散码本和一个解码器&#xff0c;通过自重建学习来存储人脸图像的高质量视觉部分。(b) 使用固定的码本和解码器&#xff0c;我们引入了一个用于代码序列预测的 Transformer 模块&#xff0c;对低质量输入的全局人脸组成进行建模。此外&a…...

TCP协议如何实现可靠传输

TCP最主要的特点 TCP是面向连接的运输层协议&#xff0c;在无连接的、不可靠的IP网络服务基础之上提供可靠交付的服务。为此&#xff0c;在IP的数据报服务基础之上&#xff0c;增加了保证可靠性的一系列措施。 TCP最主要的特点&#xff1a; TCP是面向连接的输出层协议 每一条…...

万恶的Eclipse的使用

恨啊&#xff01;公司用eclipse&#xff0c;这种千年老古董又被翻出来了&#xff0c;我的idea&#xff0c;我的宝&#xff0c;我想你&#xff01; 下面是总结的各种eclipse的使用技巧&#xff1a; 让eclipse像idea一样使用 .sout eclipse设置自动保存代码&#xff08;图文&…...

文件上传--题目

之前有在技能树中学过文件上传&#xff0c;正好借这次进行一个整合&#xff1a; 技能树中所包含的题目类型有 无限制绕过 1.上传一句话木马 2.链接中国蚁剑 前端验证 1.会发现这个网站不让提交php&#xff0c;改后缀为jpg格式&#xff0c;再用burp抓包 2.在用中国蚁剑连接 .…...

小程序创建

1&#xff0c;下载HBuilder X ;(3.8.7) HBuilderX-高效极客技巧 2,下载模板&#xff08;不选云服务的&#xff09;&#xff1b; 3&#xff0c;运行-运行到小程序模拟器&#xff1b; 4&#xff0c;安装小程序开发工具&#xff1b; 5&#xff0c;选择稳定版-windows64版&…...

stable diffusion如何确保每张图的面部一致?

可以使用roop插件&#xff0c;确定好脸部图片后&#xff0c;使用roop固定&#xff0c;然后生成的所有图片都使用同一张脸。 这款插件的功能简单粗暴&#xff1a;一键换脸。 如图所示&#xff1a; 任意上传一张脸部清晰的图片&#xff0c;点击启用。 在其他提示词不变的情况下…...

保存Windows锁屏壁纸

原链接 1. 点击爱心 我保存过了,所以没有爱心了. 2. 打开本地文件夹 用户改成自己的 C:\Users\86186\AppData\Local\Packages\Microsoft.Windows.ContentDeliveryManager_cw5n1h2txyewy\LocalState\Assets 3. 复制这些文件到其他目录 我这个不知道咋的,操作完文件夹过1会就被…...

面向对象编程:深入理解内部类与抽象类的使用

文章目录 一、内部类使用&#xff1a;1.1 成员内部类&#xff1a;1.1.1 成员内部类的主要特点是&#xff1a; 1.2 局部内部类&#xff1a;1.2.1 局部内部类的主要特点是&#xff1a;1.2.2 局部内部类通常用于以下情况&#xff1a; 1.3 静态内部类&#xff1a;1.3.1 静态内部类的…...

linux安装oracle

oracle安装 基于linux系统安装 Linux安装oracle12C Centos7.6 内存8GB 硬盘&#xff1a;50GB 可视化图形界面 yum groupinstall "GNOME Desktop" -y 可视化后续安装命令 1、软件环境包安装 yum -y install binutils compat-libcap1 compat-libstdc-33 gcc-c glib…...

切面 基于Aspect注解自动切面, 省下注解判断逻辑 handler

父文章 spring aop 切面配置_aop 切面设置.**_个人渣记录仅为自己搜索用的博客-CSDN博客 【Spring AOP】Aspect结合案例详解&#xff08;一&#xff09;: Pointcut使用annotation 五种通知Advice注解&#xff08;已附源码&#xff09;_pointcut annotation_天罡gg的博客-CSDN博…...

golang,gin框架的请求参数(一)--推荐

golang&#xff0c;gin框架的请求参数&#xff08;一&#xff09; gin框架的重要性不过多的强调&#xff0c;重点就gin使用中的参数传递&#xff0c;获取进行梳理文件&#xff0c;满足使用需求。 获取前端请求参数的几种方法&#xff1a; 一、获取参数【浏览器地址获取参数】…...

ardupilot 遥控的输入控制模式

目录 本节主要记录自己整理ardupilot的遥控器的输入控制模式:正常模式、简单模式、超简单模式的理解。 1.正常模式(有头模式) 在不用简单和超简单的模式的情况下,无人机操作员操作的控制输入是对应着不断旋转着的飞行器进行操作的。如上方图所示举例,当无人机操作员进行…...

Unity UGUI的StandaloneInputModule (标准输入模块)组件的介绍及使用

Unity UGUI的StandaloneInputModule (标准输入模块)组件的介绍及使用 1. 什么是StandaloneInputModule组件&#xff1f; StandaloneInputModule是Unity UGUI系统中的一个标准输入模块组件&#xff0c;用于处理鼠标和键盘的输入事件。它可以将鼠标和键盘的输入转化为UGUI系统中…...

惠普HP Color Laser 150a开机红色感叹号闪烁不打印故障解决方法

故障描述&#xff1a; 惠普HP Color Laser 150a开机红色感叹号闪烁&#xff0c;不能打印&#xff0c;电脑提示C3-6140。 检测分析&#xff1a; 在解决C3-6140错误代码之前&#xff0c;我们需要先检查打印机是否连接正常。如果打印机连接不正常&#xff0c;也可能会出现这个错误…...

CVE-2023-1454注入分析复现

简介 JeecgBoot的代码生成器是一种可以帮助开发者快速构建企业级应用的工具&#xff0c;它可以通过一键生成前后端代码&#xff0c;无需写任何代码&#xff0c;让开发者更多关注业务逻辑。 影响版本 Jeecg-Boot<3.5.1 环境搭建 idea 后端源码&#xff1a; https://git…...

MFC使用png做背景图片

在MFC中使用png图片作为背景&#xff0c;你需要使用GDI库。以下是一个简单的示例&#xff1a; 首先&#xff0c;你需要在你的项目中包含GDI头文件和库。在你的stdafx.h&#xff08;或者你的项目预编译头文件&#xff09;中添加以下代码&#xff1a; #include <GdiPlus.h&g…...

Java开发的基石:JDK

Java开发的基石&#xff1a;JDK 前言一、引入二、JDK的发展历程三、JDK主要目录结构解析四、JDK的使用 前言 本博主将用CSDN记录软件开发求学之路上亲身所得与所学的心得与知识&#xff0c;有兴趣的小伙伴可以关注博主&#xff01;也许一个人独行&#xff0c;可以走的很快&…...

使用langchain与你自己的数据对话(三):检索(Retrieval)

之前我已经完成了使用langchain与你自己的数据对话的前两篇博客&#xff0c;还没有阅读这两篇博客的朋友可以先阅读一下&#xff1a; 使用langchain与你自己的数据对话(一)&#xff1a;文档加载与切割使用langchain与你自己的数据对话(二)&#xff1a;向量存储与嵌入 今天我们…...

DEVICENET转ETHERNET/IP网关devicenet协议

捷米JM-EIP-DNT&#xff0c;你听说过吗&#xff1f;这是一款自主研发的ETHERNET/IP从站功能的通讯网关&#xff0c;它能够连接DEVICENET总线和ETHERNET/IP网络&#xff0c;从而解决生产管理系统中协议不同造成的数据交换互通问题。 这款产品在工业自动化领域可谓是一大利器&…...