十一、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 &current, 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 &current, 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、相关类

QAbstractTableModel
	QSqlQueryModel //封装了指向SELECT语句从数据库查询数据的功能
		QSqlTableModel
			QSqlRelationalTableModel

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 &current, 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类为单张的数据库提供了一个可以编辑的数据模型,它支持外键。
QAbstractTableModel
	QSqlQueryModel //封装了指向SELECT语句从数据库查询数据的功能
		QSqlTableModel
			QSqlRelationalTableModel

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

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试redis篇-05双写一致

原理 双写一致性:当修改了数据库的数据也要同时更新缓存的数据,缓存和数据库的数据要保持一致 读操作:缓存命中,直接返回;缓存未命中查询数据库,写入缓存,设定超时时间写操作:延迟双删方案一:分布式锁,一致性要求高

C语言之mkdtemp()特定占位符:XXXXXX 用法实例(八十五)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

2.deeplabv3+的主干网络(mobilenet网络)

deeplabv3的论文中用了resnet网络&#xff0c;在这里用轻量级网络mobilenet替换resnet&#xff0c;下面分别是两个网络的代码。 1.mobilenet网络 代码如下&#xff1a; import math import os import cv2 import numpy as np import torch import torch.nn as nn import tor…

STM32_DS18B20_1_芯片简介及初始化配置

DS18B20介绍 DS18B20数字温度计提供9位到12位摄氏度的温度测量&#xff0c;并具有非易失性&#xff0c;用户可编程的上下触发点的报警功能。DS18B20通过1线总线进行通信&#xff0c;根据定义&#xff0c;该总线只需要一条数据线&#xff0c;即可与中央微处理器进行通信…

NestJS入门7:增加异常过滤器

前文参考&#xff1a; NestJS入门1 NestJS入门2&#xff1a;创建模块 NestJS入门3&#xff1a;不同请求方式前后端写法 NestJS入门4&#xff1a;MySQL typeorm 增删改查 NestJS入门5&#xff1a;加入Swagger NestJS入门6&#xff1a;日志中间件 本文代码基于上一篇文章《…

Flink join详解(含两类API及coGroup、connect详解)

Flink SQL支持对动态表进行复杂而灵活的连接操作。 为了处理不同的场景&#xff0c;需要多种查询语义&#xff0c;因此有几种不同类型的 Join。 默认情况下&#xff0c;joins 的顺序是没有优化的。表的 join 顺序是在 FROM 从句指定的。可以通过把更新频率最低的表放在第一个、…

Redis可视化工具——RedisInsight

文章目录 1. 下载2. 安装3. RedisInsight 添加 Redis 数据库4. RedisInsight 使用 RedisInsight 是 Redis 官方出品的可视化管理工具&#xff0c;支持 String、Hash、Set、List、JSON 等多种数据类型的管理&#xff0c;同时集成了 RedisCli&#xff0c;可进行终端交互。 1. 下载…

【数据结构和算法初阶(C语言)】时间复杂度(衡量算法快慢的高端玩家,搭配例题详细剖析)

目录 1.算法效率 1.1如何衡量一个算法的好坏 1.2 算法的复杂度 2.主菜-时间复杂度 2.1 时间复杂度的概念 2.2 大O的渐进表示法 2.2.1算法的最好&#xff0c;最坏和平均的情况 3.经典时间复杂度计算举例 3.1计算冒泡排序的时间复杂度 3.2计算折半查找的时间复杂度 3.…

思维导图教你如何学会计算机组成原理

02 给你一张知识地图&#xff0c;计算机组成原理应该这么学 了解了现代计算机的基本硬件组成和背后最基本的冯诺依曼体系结构&#xff0c;我们就可以正式进入计算机组成原理的学习了。在学习一个一个零散的知识点之前&#xff0c;我整理了一份学习地图&#xff0c;好让你对将要…

AI:132-基于深度学习的涉案人脸图像识别与敲诈勒索嫌疑分析

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

华清远见作业第四十二天——Qt(第四天)

思维导图&#xff1a; 编程&#xff1a; 代码&#xff1a; widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTextToSpeech> //语音播报类 QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public Q…

一种新型的AlGaN/GaN HEMTs小信号建模与参数提取方法

来源&#xff1a;A new small-signal modeling and extraction methodin AlGaN/GaN HEMTs&#xff08;SOLID-STATE ELECTRONICS 07年&#xff09; 摘要 本文提出了一种新型的用于GaN HEMTs&#xff08;氮化镓高电子迁移率晶体管&#xff09;的小信号等效电路&#xff0c;包含2…

大离谱!AI写作竟让孔子遗体现身巴厘岛,看完笑不活了

大家好&#xff0c;我是二狗。 这两天我在知乎上看到了一个AI写作大翻车的案例&#xff0c;看完简直笑不活了&#xff0c;特地分享给大家一起 happy happy&#xff5e; 知乎网友“打开盒子吓一跳”一上来就抛出来了一个“孔子去世”的王炸。 首先&#xff0c;下面是一条真实新…

Linux第65步_学习“Makefie”

学习“Makefie”&#xff0c;为后期学习linux驱动开发做铺垫。 1、在“/home/zgq/linux/atk-mp1”创建一个“Test_MakeFile”目录用于学习“Makefie”。 打开终端 输入“cd /home/zgq/linux/回车”&#xff0c;切换到“/home/zgq/linux/”目录 输入“mkdir Linux_Drivers回…

代码随想录刷题笔记-Day22

1. 修剪二叉搜索树 669. 修剪二叉搜索树https://leetcode.cn/problems/trim-a-binary-search-tree/ 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留…

神经网络系列---计算图基本原理

文章目录 计算图符号微分符号微分的步骤示例符号微分在计算图中的使用总结 数值微分前向差分法中心差分法数值微分的使用注意事项总结 自动微分1. 基本原理2. 主要类型3. 计算图4. 应用5. 工具和库6. 优点和缺点 计算图1. **计算图的建立**2. **前向传播**3. **反向传播**4. **…

《插入排序》与《选择排序》

目录 前言&#xff1a; 排序的概念&#xff1a; 插入排序&#xff1a; 1.直接插入排序&#xff1a; 2.希尔排序( 缩小增量排序 )&#xff1a; 选择排序&#xff1a; 1.直接选择排序: 2.快速排序&#xff1a; hore思想&#xff1a; 挖坑法&#xff1a; 双指针法&#…

责任链模式与spring容器的搭配应用

背景 有个需求&#xff0c;原先只涉及到一种A情况设备的筛选&#xff0c;每次筛选会经过多个流程&#xff0c;比如先a功能&#xff0c;a功能通过再筛选b功能&#xff0c;然后再筛选c功能&#xff0c;以此类推。现在新增了另外一种B情况的筛选&#xff0c;B情况同样需要A情况的筛…

软件设计师软考题目解析02 --每日五题

想说的话&#xff1a;要准备软考了。0.0&#xff0c;其实我是不想考的&#xff0c;但是吧&#xff0c;由于本人已经学完所有知识了&#xff0c;只是被学校的课程给锁在那里了&#xff0c;不然早找工作去了。寻思着反正也无聊&#xff0c;就考个证玩玩。 本人github地址&#xf…

网络中的进程监控

每个企业都有一些流程和程序来实现他们的业务目标&#xff0c;这同样适用于网络&#xff0c;网络中的进程监控是分析、处理和管理网络内发生的各种活动以提高网络性能和能力的做法。 网络中需要监控的基本进程 监视系统资源&#xff08;CPU 利用率、内存利用率、CPU 温度等&a…