十一、Qt数据库操作
一、Sql介绍
Qt Sql模块包含多个类,实现数据库的连接,Sql语句的执行,数据获取与界面显示,数据与界面直接使用Model/View结构。
1、使用Sql模块
(1)工程加入
QT += sql
(2)添加头文件
#include <QtSel>
2、Sql相关类
1、数据库相关类
- QTableView:常用的数据库内容显示组件
- QSalQuryModel:通过设置select语句查询获取数据库内容,数据只读。
- QSqlTableModel:直接设置一个数据表的名称,可以获取苏韩剧表的全部记录,可以编辑。
- QSqlRelationalTableModel:为单张的数据库表提供了一个编辑的数据模型,支持外键。
二、QSqltableModel
1、实现程序

(1)创建项目,基于QMainWindow
(2)添加类

(3)添加组件

(4)加载数据库
void MainWindow::openTable()
{tabModel = new QSqlTableModel(this, DB);tabModel->setTable("employee"); //设置数据表名称tabModel->setSort(tabModel->fieldIndex("empNo"), Qt::AscendingOrder); //按照员工号升序tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit); //手动提交数据if(!tabModel->select()){QMessageBox::critical(this, "错误", "打开数据表错误,错误信息\n"+ tabModel->lastError().text());return;}// 修改表头tabModel->setHeaderData(tabModel->fieldIndex("empNo"), Qt::Horizontal, "工号");tabModel->setHeaderData(tabModel->fieldIndex("Name"), Qt::Horizontal, "姓名");tabModel->setHeaderData(tabModel->fieldIndex("Gender"), Qt::Horizontal, "性别");tabModel->setHeaderData(tabModel->fieldIndex("Height"), Qt::Horizontal, "身高");tabModel->setHeaderData(tabModel->fieldIndex("Birthday"), Qt::Horizontal, "出生日期");tabModel->setHeaderData(tabModel->fieldIndex("Mobile"), Qt::Horizontal, "手机号");tabModel->setHeaderData(tabModel->fieldIndex("Province"), Qt::Horizontal, "省份");tabModel->setHeaderData(tabModel->fieldIndex("City"), Qt::Horizontal, "城市");tabModel->setHeaderData(tabModel->fieldIndex("Depart"), Qt::Horizontal, "部门");tabModel->setHeaderData(tabModel->fieldIndex("Education"), Qt::Horizontal, "学历");tabModel->setHeaderData(tabModel->fieldIndex("Salary"), Qt::Horizontal, "薪资");tabModel->setHeaderData(tabModel->fieldIndex("Photo"), Qt::Horizontal, "照片");tabModel->setHeaderData(tabModel->fieldIndex("Memo"), Qt::Horizontal, "备注");theSelection = new QItemSelectionModel(tabModel);ui->tableView->setModel(tabModel);ui->tableView->setSelectionModel(theSelection);connect(theSelection, SIGNAL(currentChanged(QModelIndex, QModelIndex)),this, SLOT(on_currentChanged(QModelIndex, QModelIndex)));connect(theSelection, SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),this, SLOT(on_currentRowChanged(QModelIndex, QModelIndex)));// 隐藏列ui->tableView->setColumnHidden(tabModel->fieldIndex("Photo"), true);ui->tableView->setColumnHidden(tabModel->fieldIndex("Memo"), true);dataMapper = new QDataWidgetMapper;dataMapper->setModel(tabModel);dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);dataMapper->addMapping(ui->spinBoxNum, tabModel->fieldIndex("empNo"));dataMapper->addMapping(ui->lineEditName, tabModel->fieldIndex("Name"));dataMapper->addMapping(ui->comboBoxSex, tabModel->fieldIndex("Gender"));dataMapper->addMapping(ui->doubleSpinBoxHeight, tabModel->fieldIndex("Height"));dataMapper->addMapping(ui->lineEditBirthday, tabModel->fieldIndex("Birthday"));dataMapper->addMapping(ui->lineEditPhone, tabModel->fieldIndex("Mobile"));dataMapper->addMapping(ui->comboBoxProvince, tabModel->fieldIndex("Province"));dataMapper->addMapping(ui->lineEditCity, tabModel->fieldIndex("City"));dataMapper->addMapping(ui->comboBoxWork, tabModel->fieldIndex("Depart"));dataMapper->addMapping(ui->comboBoxStudy, tabModel->fieldIndex("Education"));dataMapper->addMapping(ui->textEditInfo, tabModel->fieldIndex("Memo"));getFiledNames();ui->actOpen->setEnabled(false);ui->actAppend->setEnabled(true);ui->actDelete->setEnabled(true);ui->actInsert->setEnabled(true);ui->actScan->setEnabled(true);ui->groupBoxSort->setEnabled(true);ui->groupBoxFilter->setEnabled(true);// 使用delegate实现下拉选择QStringList strList;strList << "男" << "女";bool isEditable = false;delegateSex.setItem(strList, isEditable);ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("Gender"), &delegateSex);
}void MainWindow::getFiledNames()
{QSqlRecord emptyRec = tabModel->record();for (int i = 0; i < emptyRec.count(); ++i){ui->comboBoxFields->addItem(emptyRec.fieldName(i));}
}void MainWindow::on_currentChanged(const QModelIndex ¤t, const QModelIndex &preivous)
{Q_UNUSED(current)Q_UNUSED(preivous)ui->actSubmit->setEnabled(tabModel->isDirty()); // 是否有数据修改ui->actRevert->setEnabled(tabModel->isDirty()); // 是否有数据修改
}void MainWindow::on_currentRowChanged(const QModelIndex ¤t, const QModelIndex &preivous)
{ui->actDelete->setEnabled(current.isValid());ui->actAppend->setEnabled(current.isValid());ui->actInsert->setEnabled(current.isValid());if(! current.isValid()){ui->labelPhoto->clear();return;}dataMapper->setCurrentIndex(current.row());QSqlRecord curRec = tabModel->record(current.row());if(curRec.isNull("Photo")){ui->labelPhoto->clear();}else{QByteArray data = curRec.value("Photo").toByteArray();QPixmap pic;pic.loadFromData(data);ui->labelPhoto->setPixmap(pic.scaledToWidth(ui->labelPhoto->size().width()));}
}void MainWindow::on_actOpen_triggered()
{QString fileName = QFileDialog::getOpenFileName(this, "选择数据库文件","", "Sqlite数据库(*.db *.db3)");if(fileName.isEmpty()){return;}DB = QSqlDatabase::addDatabase("QSQLITE"); //添加数据库驱动DB.setDatabaseName(fileName); // 设置数据库名称if(!DB.open()){QMessageBox::warning(this, "错误", "打开数据库失败");return;}openTable();
}

(5)实现工具栏按钮功能
void MainWindow::on_actAppend_triggered()
{tabModel->insertRow(tabModel->rowCount(), QModelIndex());QModelIndex curIndex = tabModel->index(tabModel->rowCount() - 1, 1); // 插入后增加一行theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);tabModel->setData(tabModel->index(curIndex.row(), 0), 2000 + tabModel->rowCount());tabModel->setData(tabModel->index(curIndex.row(), 2), "男");ui->actSubmit->setEnabled(true);ui->actRevert->setEnabled(true);
}void MainWindow::on_actInsert_triggered()
{QModelIndex curIndex = theSelection->currentIndex();tabModel->insertRow(curIndex.row(), QModelIndex());theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);tabModel->setData(tabModel->index(curIndex.row(), 0), 2000 + tabModel->rowCount());tabModel->setData(tabModel->index(curIndex.row(), 2), "男");ui->actSubmit->setEnabled(true);ui->actRevert->setEnabled(true);
}void MainWindow::on_actDelete_triggered()
{QModelIndex curIndex = theSelection->currentIndex();tabModel->removeRow(curIndex.row());ui->actSubmit->setEnabled(true);ui->actRevert->setEnabled(true);
}void MainWindow::on_actSubmit_triggered()
{bool result = tabModel->submitAll();if(!result){QMessageBox::information(this, "信息", "数据提交错误,错误信息\n"+ tabModel->lastError().text());}else{ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);}
}void MainWindow::on_actRevert_triggered()
{tabModel->revertAll();ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);
}void MainWindow::on_actSetPhoto_triggered()
{QString fileName = QFileDialog::getOpenFileName(this, "选择图片", "", "照片(*.jpg *.png)");if(fileName.isEmpty()){return;}QByteArray data;QFile *file = new QFile(fileName);if(file->open(QIODevice::ReadOnly)){data = file->readAll();QModelIndex curIndex = theSelection->currentIndex();QSqlRecord curRec = tabModel->record(curIndex.row());curRec.setValue("Photo", data);tabModel->setRecord(curIndex.row(), curRec);QPixmap pic;pic.load(fileName);ui->labelPhoto->setPixmap(pic.scaledToWidth(ui->labelPhoto->width()));file->close();}delete file;
}void MainWindow::on_actClearPhoto_triggered()
{QModelIndex curIndex = theSelection->currentIndex();QSqlRecord curRec = tabModel->record(curIndex.row());curRec.setNull("Photo");tabModel->setRecord(curIndex.row(), curRec);ui->labelPhoto->clear();
}void MainWindow::on_actScan_triggered()
{if(tabModel->rowCount() != 0){for (int i = 0; i < tabModel->rowCount(); ++i){QSqlRecord aRec = tabModel->record(i);float salary = aRec.value("Salary").toFloat();salary *= 1.1;aRec.setValue("Salary", salary);tabModel->setRecord(i, aRec);}if(tabModel->submitAll()){QMessageBox::information(this, "信息", "涨工资完成");}}
}void MainWindow::on_comboBoxFields_currentIndexChanged(int index)
{if(ui->rbtnAscend->isCheckable()){tabModel->setSort(index, Qt::AscendingOrder);}else{tabModel->setSort(index, Qt::DescendingOrder);}tabModel->select(); // 重新从数据库装载
}void MainWindow::on_rbtnAscend_clicked()
{tabModel->setSort(ui->comboBoxFields->currentIndex(), Qt::AscendingOrder);tabModel->select(); // 重新从数据库装载
}void MainWindow::on_rbtnDescend_clicked()
{tabModel->setSort(ui->comboBoxFields->currentIndex(), Qt::DescendingOrder);tabModel->select(); // 重新从数据库装载
}void MainWindow::on_rbtnMan_clicked()
{tabModel->setFilter("Gender='男'");
}void MainWindow::on_rbtnWoman_clicked()
{tabModel->setFilter("Gender='女'");
}void MainWindow::on_rbtnAll_clicked()
{tabModel->setFilter("");
}
三、QSqlQueryModel
1、相关类
QAbstractTableModelQSqlQueryModel //封装了指向SELECT语句从数据库查询数据的功能QSqlTableModelQSqlRelationalTableModel
2、实现程序

1、创建项目,基于QMainWindow
2、添加图标资源文件,添加工具按钮
3、添加组件

4、实现功能
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);qryModel = new QSqlQueryModel(this);theSelection = new QItemSelectionModel(qryModel);dataMapper = new QDataWidgetMapper(this);dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);dataMapper->setModel(qryModel);ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(theSelection);connect(theSelection, SIGNAL(currentRowChanged(QModelIndex, QModelIndex)),this, SLOT(on_currentRowChanged(QModelIndex, QModelIndex)));
}MainWindow::~MainWindow()
{delete ui;
}#include <QFileDialog>
#include <QMessageBox>
void MainWindow::on_actOpenDB_triggered()
{QString fileName = QFileDialog::getOpenFileName(this, "打开数据库", "","数据库文件(*.db *.db3)");if(fileName.isEmpty()){return;}DB = QSqlDatabase::addDatabase("QSQLITE");DB.setDatabaseName(fileName);if(!DB.open()){QMessageBox::warning(this, "错误", "打开数据库失败");return;}qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary FROM employee ORDER BY EMpNo", DB);if(qryModel->lastError().isValid()){QMessageBox::critical(this, "错误", "查询失败\n" + qryModel->lastError().text());return;}qryModel->setHeaderData(0, Qt::Horizontal, "工号");qryModel->setHeaderData(2, Qt::Horizontal, "性别");dataMapper->addMapping(ui->spinBoxNum, 0);dataMapper->addMapping(ui->lineEditName, 1);dataMapper->addMapping(ui->comboBoxSex, 2);dataMapper->addMapping(ui->doubleSpinBoxHeight, 3);dataMapper->addMapping(ui->lineEditBirthday, 4);dataMapper->addMapping(ui->lineEditPhone, 5);dataMapper->addMapping(ui->comboBoxProvince, 6);dataMapper->addMapping(ui->lineEditCity, 7);dataMapper->addMapping(ui->comboBoxWork, 8);dataMapper->addMapping(ui->comboBoxStudy, 9);dataMapper->addMapping(ui->textEditInfo, 10);// dataMapper->toFirst();ui->actOpenDB->setEnabled(false);}void MainWindow::on_currentRowChanged(const QModelIndex ¤t, const QModelIndex &previous)
{if(!current.isValid()){ui->labelPhoto->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;query.prepare("select EmpNo,Memo,Photo from employee where EmpNo = :ID");query.bindValue(":ID", empNo); //防注入query.exec();query.first(); // 回到第一条记录if(qryModel->lastError().isValid()){QMessageBox::critical(this, "错误", "查询失败\n" + qryModel->lastError().text());return;}QVariant va = query.value("Photo");if(!va.isValid()){ui->labelPhoto->clear();}else{QPixmap pic;QByteArray data = va.toByteArray();pic.loadFromData(data);ui->labelPhoto->setPixmap(pic.scaledToWidth(ui->labelPhoto->size().width()));}QVariant va2 = query.value("Memo");ui->textEditInfo->setPlainText(va2.toString());
}void MainWindow::on_actRecFirst_triggered()
{dataMapper->toFirst();int index = dataMapper->currentIndex();QModelIndex curIndex = qryModel->index(index, 1);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void MainWindow::on_actRecPrevious_triggered()
{dataMapper->toPrevious();int index = dataMapper->currentIndex();QModelIndex curIndex = qryModel->index(index, 1);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void MainWindow::on_actRecNext_triggered()
{dataMapper->toNext();int index = dataMapper->currentIndex();QModelIndex curIndex = qryModel->index(index, 1);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}void MainWindow::on_actRecLast_triggered()
{dataMapper->toLast();int index = dataMapper->currentIndex();QModelIndex curIndex = qryModel->index(index, 1);theSelection->clearSelection();theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select);
}
四、QSqlQuery
QSqlQuery是可以执行任意SQL语句的类,如SELECT、INSERT、UPDATE、DELETE等。
1、实现程序

(1)创建项目,基于QMainWindow
(2)添加工具栏按钮
(3)添加对话框


#include "dialogdata.h"
#include "ui_dialogdata.h"DialogData::DialogData(QWidget *parent) :QDialog(parent),ui(new Ui::DialogData)
{ui->setupUi(this);
}DialogData::~DialogData()
{delete ui;
}void DialogData::setUpdateRecord(QSqlRecord &recData)
{mRecord = recData;ui->spinBoxEmpNo->setEnabled(false);setWindowTitle("更新记录");// 更新界面ui->spinBoxEmpNo->setValue(recData.value("EmpNo").toInt());ui->lineEditName->setText(recData.value("Name").toString());ui->comboBoxSex->setCurrentText(recData.value("Gender").toString());ui->doubleSpinBoxHeight->setValue(recData.value("Height").toFloat());ui->lineEditBirthday->setText(recData.value("Birthday").toString());ui->lineEditPhone->setText(recData.value("Mobile").toString());ui->comboBoxProvince->setCurrentText(recData.value("Province").toString());ui->lineEditCity->setText(recData.value("City").toString());ui->comboBoxDepart->setCurrentText(recData.value("Depart").toString());ui->comboBoxEducation->setCurrentText(recData.value("Education").toString());ui->spinBoxSalary->setValue(recData.value("Salary").toInt());ui->textEditInfo->setText(recData.value("Memo").toString());QVariant va = recData.value("Photo");if(!va.isValid()){ui->labelPhoto->clear();}else{QByteArray data = va.toByteArray();QPixmap pic;pic.loadFromData(data);ui->labelPhoto->setPixmap(pic.scaledToWidth(ui->labelPhoto->size().width()));}
}void DialogData::setInsertRecord(QSqlRecord &recData)
{mRecord = recData;ui->spinBoxEmpNo->setEnabled(true);setWindowTitle("新建记录");ui->spinBoxEmpNo->setValue(recData.value("EmpNo").toInt());
}QSqlRecord DialogData::getRecordData()
{mRecord.setValue("EmpNo", ui->spinBoxEmpNo->value());mRecord.setValue("Name", ui->lineEditName->text());mRecord.setValue("Gender", ui->comboBoxSex->currentText());mRecord.setValue("Height", ui->doubleSpinBoxHeight->value());mRecord.setValue("Birthday", ui->lineEditBirthday->text());mRecord.setValue("Mobile", ui->lineEditPhone->text());mRecord.setValue("Province", ui->comboBoxProvince->currentText());mRecord.setValue("City", ui->lineEditCity->text());mRecord.setValue("Depart", ui->comboBoxDepart->currentText());mRecord.setValue("Education", ui->comboBoxEducation->currentText());mRecord.setValue("Salary", ui->spinBoxSalary->value());mRecord.setValue("Memo", ui->textEditInfo->toPlainText());return mRecord;
}#include <QFileDialog>
void DialogData::on_btnLoadPhoto_clicked()
{QString fileName = QFileDialog::getOpenFileName(this, "选择图片", "","图片(*.png *.jpg)");if(fileName.isEmpty()){return;}QByteArray data;QFile *file = new QFile(fileName);file->open(QIODevice::ReadOnly);data = file->readAll();file->close();delete file;mRecord.setValue("Photo", data);QPixmap pic;pic.loadFromData(data);ui->labelPhoto->setPixmap(pic.scaledToWidth(ui->labelPhoto->size().width()));
}void DialogData::on_btnClearPhoto_clicked()
{}
(4)工具栏按钮功能
#include "mainwindow.h"
#include "ui_mainwindow.h"#include <QMessageBox>#include "dialogdata.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setCentralWidget(ui->tableView);qryModel = new QSqlQueryModel;theSelection = new QItemSelectionModel(qryModel);ui->tableView->setModel(qryModel);ui->tableView->setSelectionModel(theSelection);connect(ui->tableView, SIGNAL(doubleClicked(QModelIndex)),this, SLOT(on_TableView_doubleClicked(QModelIndex)));
}MainWindow::~MainWindow()
{delete ui;
}void MainWindow::openTable()
{qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary From employee order by EmpNo");if(qryModel->lastError().isValid()){QMessageBox::warning(this, "错误", "SqlCmdError" + qryModel->lastError().text());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->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);}#include <QFileDialog>void MainWindow::on_actOpenDB_triggered()
{QString fileName = QFileDialog::getOpenFileName(this, "选择数据库","", "SQlite数据库(*.db *.db3)");if(fileName.isEmpty()){return;}DB = QSqlDatabase::addDatabase("QSQLITE");DB.setDatabaseName(fileName);if(!DB.open()){QMessageBox::warning(this, "错误", "打开数据库失败");return;}openTable();}void MainWindow::on_actRecInsert_triggered()
{QSqlQuery query;query.exec("select * from employee where EmpNo = -1");DialogData *dataDlg = new DialogData;Qt::WindowFlags flags = dataDlg->windowFlags();dataDlg->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //固定大小QSqlRecord curData = query.record();curData.setValue("EmpNo", qryModel->rowCount() + 1000);dataDlg->setInsertRecord(curData);int ret = dataDlg->exec();if(ret == QDialog::Accepted){QSqlRecord recData = dataDlg->getRecordData();query.prepare("INSERT INTO employee (EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary,Memo,Photo) ""VALUES(:EmpNo,:Name,:Gender,:Height,:Birthday,:Mobile,:Province,:City,:Depart,: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(":Depart", recData.value("Depart"));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, "error", "Information:" + query.lastError().text());}else{qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary From employee order by EmpNo");if(qryModel->lastError().isValid()){QMessageBox::warning(this, "错误", "SqlCmdError" + qryModel->lastError().text());return;}}}delete dataDlg;
}void MainWindow::on_actRecEdit_triggered()
{int curRecNo = theSelection->currentIndex().row();QSqlRecord curRec = qryModel->record(curRecNo);int empNo = curRec.value("EmpNo").toInt();QSqlQuery query;query.prepare("select * from employee where EmpNo = :ID");query.bindValue(":ID", empNo);query.exec();query.first();if(!query.isValid()){return;}curRec = query.record();DialogData *dataDlg = new DialogData;Qt::WindowFlags flags = dataDlg->windowFlags();dataDlg->setWindowFlags(flags | Qt::MSWindowsFixedSizeDialogHint); //固定大小dataDlg->setUpdateRecord(curRec);int ret = dataDlg->exec();if(ret == QDialog::Accepted){QSqlRecord recData = dataDlg->getRecordData();query.prepare("update employee set ""Name=:Name,Gender=:Gender,Height=:Height,Birthday=:Birthday,""Mobile=:Mobile,Province=:Province,City=:City,Depart=:Depart,""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(":Depart", recData.value("Depart"));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", recData.value("EmpNo"));if(!query.exec()){QMessageBox::critical(this, "error", "Information:" + query.lastError().text());}else{qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary From employee order by EmpNo");if(qryModel->lastError().isValid()){QMessageBox::warning(this, "错误", "SqlCmdError" + qryModel->lastError().text());return;}}}delete dataDlg;
}void MainWindow::on_actRecDelete_triggered()
{int curRecNo = theSelection->currentIndex().row();QSqlRecord curRec = qryModel->record(curRecNo);int empNo = curRec.value("EmpNo").toInt();QSqlQuery queryDelete;queryDelete.prepare("delete from employee where EmpNo=:ID");queryDelete.bindValue(":ID", empNo);if(!queryDelete.exec()){QMessageBox::warning(this, "错误", "SqlCmdError" + queryDelete.lastError().text());}else{qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary From employee order by EmpNo");if(qryModel->lastError().isValid()){QMessageBox::warning(this, "错误", "SqlCmdError" + qryModel->lastError().text());return;}}}void MainWindow::on_actScan_triggered()
{QSqlQuery queryEmList;queryEmList.exec("select EmpNo,Salary From employee order by EmpNo");queryEmList.first();QSqlQuery queryUpdate;queryUpdate.prepare("update employee set Salary=:Salary where EmpNo=:ID");while (queryEmList.isValid()){int empID = queryEmList.value("EmpNo").toInt();float salary = queryEmList.value("Salary").toFloat() + 1000;queryUpdate.bindValue(":Salary", salary);queryUpdate.bindValue(":ID", empID);queryUpdate.exec();if(queryUpdate.lastError().isValid()){break;}queryEmList.next();}qryModel->setQuery("SELECT EmpNo,Name,Gender,Height,Birthday,Mobile,Province,City,Depart,Education,Salary From employee order by EmpNo");if(qryModel->lastError().isValid()){QMessageBox::warning(this, "错误", "SqlCmdError" + qryModel->lastError().text());return;}
}void MainWindow::on_TableView_doubleClicked(QModelIndex index)
{Q_UNUSED(index)on_actRecEdit_triggered();
}

五、QSelRelationalTableModel
QSelRelationalTableModel类为单张的数据库提供了一个可以编辑的数据模型,它支持外键。
QAbstractTableModelQSqlQueryModel //封装了指向SELECT语句从数据库查询数据的功能QSqlTableModelQSqlRelationalTableModel
1、实现程序

(1)创建项目,基于QMainWindow

(2)添加图标资源
(3)实现工具栏功能
#include "mainwindow.h"
#include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);setCentralWidget(ui->tableView);}MainWindow::~MainWindow()
{delete ui;
}#include <QFileDialog>
#include <QMessageBox>
void MainWindow::on_actOpenDB_triggered()
{QString fileName = QFileDialog::getOpenFileName(this, "打开数据库", "","Sqlite数据库(*.db *.db3)");if(fileName.isEmpty()){return;}DB = QSqlDatabase::addDatabase("QSQLITE");DB.setDatabaseName(fileName);if(!DB.open()){QMessageBox::warning(this, "错误", "打开数据库失败");}tabModel = new QSqlRelationalTableModel(this, DB);tabModel->setTable("studInfo");tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);tabModel->setSort(0, Qt::AscendingOrder);tabModel->setHeaderData(0, Qt::Horizontal, "学号");tabModel->setHeaderData(1, Qt::Horizontal, "姓名");tabModel->setHeaderData(2, Qt::Horizontal, "性别");tabModel->setHeaderData(3, Qt::Horizontal, "学院");tabModel->setHeaderData(4, Qt::Horizontal, "专业");tabModel->setRelation(3, QSqlRelation("departments", "departID", "department"));tabModel->setRelation(4, QSqlRelation("majors", "majorID", "major"));theSelection = new QItemSelectionModel(tabModel);ui->tableView->setModel(tabModel);ui->tableView->setSelectionModel(theSelection);// 表格添加代理(学院与专业下拉选)ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView));tabModel->select();ui->actOpenDB->setEnabled(false);ui->actRecAppend->setEnabled(true);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actFields->setEnabled(true);}void MainWindow::on_actFields_triggered()
{QSqlRecord emptyRec = tabModel->record();QString str;for (int var = 0; var < emptyRec.count(); ++var){str = str + emptyRec.fieldName(var) + "\n";}QMessageBox::information(this, "字段名称", str);
}void MainWindow::on_actRecAppend_triggered()
{tabModel->insertRow(tabModel->rowCount(), QModelIndex()); // 在末尾添加一条QModelIndex curIndex = tabModel->index(tabModel->rowCount() - 1, 1); //theSelection->clearSelection(); // 清空选择项theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select); // 设置新的选项ui->actRevert->setEnabled(true);ui->actSubmit->setEnabled(true);
}void MainWindow::on_actRecInsert_triggered()
{QModelIndex curIndex = ui->tableView->currentIndex();tabModel->insertRow(curIndex.row(), QModelIndex()); // 添加一条theSelection->clearSelection(); // 清空选择项theSelection->setCurrentIndex(curIndex, QItemSelectionModel::Select); // 设置新的选项ui->actRevert->setEnabled(true);ui->actSubmit->setEnabled(true);
}void MainWindow::on_actRevert_triggered()
{tabModel->revertAll();ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);
}void MainWindow::on_actSubmit_triggered()
{bool res = tabModel->submitAll();if(!res){QMessageBox::information(this, "信息", "数据保存错误\n" + tabModel->lastError().text(),QMessageBox::Ok, QMessageBox::NoButton);}else{ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);}
}void MainWindow::on_actRecDelete_triggered()
{QModelIndex curIndex = ui->tableView->currentIndex();QModelIndex nextIndex = tabModel->index(curIndex.row() + 1, 0);tabModel->removeRow(curIndex.row()); // 删除theSelection->clearSelection(); // 清空选择项theSelection->setCurrentIndex(nextIndex, QItemSelectionModel::Select); // 设置新的选项ui->actRevert->setEnabled(true);ui->actSubmit->setEnabled(true);
}

相关文章:
十一、Qt数据库操作
一、Sql介绍 Qt Sql模块包含多个类,实现数据库的连接,Sql语句的执行,数据获取与界面显示,数据与界面直接使用Model/View结构。1、使用Sql模块 (1)工程加入 QT sql(2)添加头文件 …...
【Spring】IoC容器 控制反转 与 DI依赖注入 XML实现版本 第二期
文章目录 基于 XML 配置方式组件管理前置 准备项目一、 组件(Bean)信息声明配置(IoC):1.1 基于无参构造1.2 基于静态 工厂方法实例化1.3 基于非静态 工厂方法实例化 二、 组件(Bean)依赖注入配置…...
神经网络系列---感知机(Neuron)
文章目录 感知机(Neuron)感知机(Neuron)的决策函数可以表示为:感知机(Neuron)的学习算法主要包括以下步骤:感知机可以实现逻辑运算中的AND、OR、NOT和异或(XOR)运算。 感知机(Neuron) 感知机(Neuron)是一种简单而有效的二分类算法,用于将输入…...
k8s(2)
目录 一.二进制部署k8s 常见的K8S安装部署方式: k8s部署 二进制与高可用的区别 二.部署k8s 初始化操作: 每台node安装docker: 在 master01 节点上操作; 准备cfssl证书生成工具:: 执行脚本文件: 拉入etcd压缩包…...
利用nginx内部访问特性实现静态资源授权访问
在nginx中,将静态资源设为internal;然后将前端的静态资源地址改为指向后端,在后端的响应头部中写上静态资源地址。 近期客户对我们项目做安全性测评,暴露出一些安全性问题,其中一个是有些静态页面(*.html&…...
fly-barrage 前端弹幕库(1):项目介绍
fly-barrage 是我写的一个前端弹幕库,由于经常在 Bilibili 上看视频,所以对网页的弹幕功能一直蛮感兴趣的,所以做了这个库,可以帮助前端快速的实现弹幕功能。 项目官网地址:https://fly-barrage.netlify.app/ÿ…...
jetcache如果一个主体涉及多个缓存时编辑或者删除时如何同时失效多个缓存
在实际使用过程中,可能会遇到这种情形:一个主体会有多个缓存,比如用户基础信息缓存、用户详情缓存,那么当删除用户信息后就需要同时失效多个缓存中该主体数据,那么jetcache支持这种应用场景么,答案是支持&a…...
uni-app 实现拍照后给照片加水印功能
遇到个需求需要实现,研究了一下后写了个demo 本质上就是把拍完照后的照片放到canvas里,然后加上水印样式然后再重新生成一张图片 代码如下,看注释即可~使用的话记得还是得优化下代码 <template><view class"content"&g…...
【ArcGIS】利用DEM进行水文分析:流向/流量等
利用DEM进行水文分析 ArcGIS实例参考 水文分析通过建立地表水文模型,研究与地表水流相关的各种自然现象,在城市和区域规划、农业及森林、交通道路等许多领域具有广泛的应用。 ArcGIS实例 某流域30m分辨率DEM如下: (1)…...
论文阅读笔记——PathAFL:Path-Coverage Assisted Fuzzing
文章目录 前言PathAFL:Path-Coverage Assisted Fuzzing1、解决的问题和目标2、技术路线2.1、如何识别 h − p a t h h-path h−path?2.2、如何减少 h − p a t h h-path h−path的数量?2.3、哪些h-path将被添加到种子队列?2.4、种…...
C语言中各种运算符用法
C语言中有许多不同的运算符,用于执行各种不同的操作。 以下是C语言中常见的运算符及其用法: 算术运算符: 加法运算符():用于将两个值相加。减法运算符(-):用于将一个值减…...
pythonJax小记(五):python: 使用Jax深度图像(正交投影和透视投影之间的转换)(持续更新,评论区可以补充)
python: 使用Jax深度图像(正交投影和透视投影之间的转换) 前言问题描述1. 透视投影2. 正交投影 直接上代码解释1. compute_projection_parameters 函数a. 参数解释b. 函数计算 2. ortho_to_persp 函数a. 计算投影参数:b. 生成像素坐标网格&am…...
web安全学习笔记【16】——信息打点(6)
信息打点-语言框架&开发组件&FastJson&Shiro&Log4j&SpringBoot等[1] #知识点: 1、业务资产-应用类型分类 2、Web单域名获取-接口查询 3、Web子域名获取-解析枚举 4、Web架构资产-平台指纹识别 ------------------------------------ 1、开源-C…...
145.二叉树的后序遍历
// 定义一个名为Solution的类,用于解决二叉树的后序遍历问题 class Solution { // 定义一个公共方法,输入是一个二叉树的根节点,返回一个包含后序遍历结果的整数列表 public List<Integer> postorderTraversal(TreeNode root) { /…...
ssh远程连接免密码访问
我们在远程登录的时候,经常需要输入密码,密码往往比较复杂,输入比较耗费时间,这种情况下可以使用ssh免密码登录。 一般的教程是需要生成ssh密钥后,然后把密钥复制到server端完成配置,这里提供一个简单的方…...
Vue-Json-Schema-Form: 如何基于模板定制前端页面
本人从事的是工业物联网, 面对工业设备的通讯难题是各大设备都有各自的通讯协议, 如果想要用一款硬件去和所有设备做通讯的话, 就得面对怎么把自己想要采集的配置下发给自己的采集器的问题, 以前都是采用各种模型去尝试构建配置项, 但是因为配置可能会有深层次嵌套, 而且…...
保存Json对象到数据库
文章目录 背景实现方式1. 直接以 Json 对象保存到数据库2. 以 String 类型保存到数据库 背景 项目过程中可能需要保存 Json 对象到数据库中。 实现方式 有两种实现方式,一种是直接保存 Json 对象到数据库,这种方式在创建实体类以及编写 Mapper XML 脚本…...
《Docker 简易速速上手小册》第3章 Dockerfile 与镜像构建(2024 最新版)
文章目录 3.1 编写 Dockerfile3.1.1 重点基础知识3.1.2 重点案例:创建简单 Python 应用的 Docker 镜像3.1.3 拓展案例 1:Dockerfile 优化3.1.4 拓展案例 2:多阶段构建 3.2 构建流程深入解析3.2.1 重点基础知识3.2.2 重点案例:构建…...
【Python笔记-设计模式】适配器模式
一、说明 适配器模式是一种结构型模式,它使接口不兼容的对象能够相互合作 (一) 解决问题 主要解决接口不兼容问题 (二) 使用场景 当系统需要使用现有的类,但类的接口不符合需求时当需要一个统一的输出接口,但输入类型不可预知时当需要创…...
二分算法(c++版)
二分的本质是什么? 很多人会认为单调性是二分的本质,但其实其本质并非单调性,只是说,有单调性的可以进行二分,但是有些题目没有单调性我们也可以进行二分。其本质其实是一个边界问题,给定一个条件…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面
代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口(适配服务端返回 Token) export const login async (code, avatar) > {const res await http…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Fabric V2.5 通用溯源系统——增加图片上传与下载功能
fabric-trace项目在发布一年后,部署量已突破1000次,为支持更多场景,现新增支持图片信息上链,本文对图片上传、下载功能代码进行梳理,包含智能合约、后端、前端部分。 一、智能合约修改 为了增加图片信息上链溯源,需要对底层数据结构进行修改,在此对智能合约中的农产品数…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
