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_OBJECT

private:
    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_OBJECT

private:
    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()
{ //"确定"按钮后,界面数据保存到记录mRecord
    mRecord.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();//获取EmpNo

    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();//获取当前记录的数据
    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);
        else
            qryModel->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; //临时 QSqlQuery
    qryUpdate.prepare("UPDATE employee SET Salary=:Salary WHERE EmpNo = :ID");

    while (qryEmpList.isValid()) //当前记录有效
    {
        int empID=qryEmpList.value("empNo").toInt(); //获取empNo
        float salary=qryEmpList.value("Salary").toFloat(); //获取Salary
        salary=salary+1000; //涨工资

        qryUpdate.bindValue(":ID",empID);
        qryUpdate.bindValue(":Salary",salary); //设置SQL语句参数
        qryUpdate.exec(); //执行update

        if (!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_OBJECT

private:
    QSqlDatabase  DB; //数据库

    QSqlQueryModel  *qryModel; //数据库模型

    QItemSelectionModel *theSelection; //选择模型

    void    openTable();//打开数据表

    void    updateRecord(int recNo); //更新记录
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:

// QTableView的SelectionModel的行发生了变化,进行处理
//    void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);
///
    void on_actOpenDB_triggered();

    void on_actRecInsert_triggered();

    void on_actRecDelete_triggered();

    void on_actRecEdit_triggered();

    void on_tableView_doubleClicked(const QModelIndex &index);

    void on_actScan_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

(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();//获取EmpNo

    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();//获取当前记录的数据
    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);
        else
            qryModel->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; //临时 QSqlQuery
    qryUpdate.prepare("UPDATE employee SET Salary=:Salary WHERE EmpNo = :ID");

    while (qryEmpList.isValid()) //当前记录有效
    {
        int empID=qryEmpList.value("empNo").toInt(); //获取empNo
        float salary=qryEmpList.value("Salary").toFloat(); //获取Salary
        salary=salary+1000; //涨工资

        qryUpdate.bindValue(":ID",empID);
        qryUpdate.bindValue(":Salary",salary); //设置SQL语句参数
        qryUpdate.exec(); //执行update

        if (!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_OBJECT

private:
    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()
{ //"确定"按钮后,界面数据保存到记录mRecord
    mRecord.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()));
}

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

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

相关文章

【RabbitMQ】Linux系统服务器安装RabbitMQ

一、下载 首先应该下载erlang&#xff0c;rabbitmq运行需要有erland环境。 官网地址&#xff1a;https://www.erlang.org/downloads 下载rabbitmq 官网环境&#xff1a;https://www.rabbitmq.com/download.html 注意&#xff1a;el7对应centos7&#xff0c;el8对应centos8…

探索运营商渠道佣金数字化运营

当前全球经济增长放缓&#xff0c;行业竞争持续加剧已是常态&#xff0c;用户需求越发苛刻、经营成本不断上升。内忧外患&#xff0c;企业经营如何突围&#xff1f;越来越多的企业发现&#xff0c;融合数字化技术的IT解决方案为企业提供了一种解决问题的可能。 数字化运营可以帮…

B. Binary Cafe(二进制的妙用)

题目&#xff1a;Problem - B - Codeforces 总结&#xff1a; 对于该题最简单的方法为使用二进制的数表示状态 例如&#xff1a; 对于一个数7的二进制&#xff1a;111 它的每一位都可表示两种状态我们可以理解为取或者不取 对于7这个数字它可以表示一种状态即在三个位置都…

道本科技||全面建立国有企业合规管理体系

为全面深化国有企业法治建设&#xff0c;不断加强合规管理&#xff0c;防控合规风险&#xff0c;保障企业稳健发展&#xff0c;近日&#xff0c;市国资委印发《常州市市属国有企业合规管理办法&#xff08;试行&#xff09;》&#xff08;以下简称《办法》&#xff09;&#xf…

小研究 - JVM GC 对 IMS HSS 延迟分析(二)

用户归属服务器&#xff08;IMS HSS&#xff09;是下一代通信网&#xff08;NGN&#xff09;核心网络 IP 多媒体子系统&#xff08;IMS&#xff09;中的主要用户数据库。IMS HSS 中存储用户的配置文件&#xff0c;可执行用户的身份验证和授权&#xff0c;并提供对呼叫控制服务器…

【Matlab】判断点和多面体位置关系的两种方法实现

我的主页&#xff1a; 技术邻&#xff1a;小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩&#xff1a;小铭的ABAQUS学习的个人空间csdn&#xff1a;qgm1702 博客园文章链接&#xff1a; https://www.cnblogs.com/aksoam/p/17590039.html 分别是向量判别法&…

Azure pipeline自动化打包发布

pipeline自动化&#xff0c;提交代码后&#xff0c;就自动打包&#xff0c;打包成功后自动发布 第一步 pipeline提交代码后&#xff0c;自动打包。 1 在Repos,分支里选择要触发的分支&#xff0c;这里选择cn_china,对该分支设置分支策略 2 在生产验证中增加新的策略 3 在分支安…

【单机多卡】torch改造代码为DDP单机多卡分布式并行

torch分布式数据并行DDPtorch.nn.parallel.DistributedDataParallel代码修改记录。&#xff08;要求pytorch_version>1.0&#xff09; 目录 1.&#x1f344;&#x1f344;要修改的地方概览 2.✏️✏️初始化 3.✏️✏️设置当前进程GPU 4.✏️✏️设置sampler 5.✏️✏…

后端技术趋势指南|如何选择自己的技术方向

编程多条路&#xff0c;条条通罗马 后台大佬 后台路线都是面对后台服务器业务&#xff0c;比如web后台服务器&#xff0c;视频后台服务器&#xff0c;搜索后台服务器&#xff0c;游戏后台服务器&#xff0c;直播后台服务器&#xff0c;社交IM后台服务器等等&#xff0c;大部分…

Python基础入门教程(下)

目录 七、函数进阶 7.1、函数多返回值 7.2、函数多种传参方式 位置参数 关键字参数 缺省参数 不定长参数 位置传递 关键字传递 7.3、匿名函数 函数作为参数传递 lambda匿名函数 八、文件操作 8.1、文件的读取 open()打开函数 mode常用的三种基础访问模式 读操…

无人机调试笔记——常见参数

无人机的PID调试以及速度相关参数 1、Multicopter Position Control主要是用来设置无人机的各种速度和位置参数。调试顺序是先调试内环PID&#xff0c;也就是无人机的速度闭环控制&#xff0c;确认没有问题后再进行外环位置控制&#xff0c;也就是定点模式控制。 2、调试的时…

【C++】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值

[导读]本系列博文内容链接如下&#xff1a; 【C】做一个飞机空战小游戏(一)——使用getch()函数获得键盘码值 【C】做一个飞机空战小游戏(二)——利用getch()函数实现键盘控制单个字符移动 【C】【C】做一个飞机空战小游戏(三)——模块化程设设计 最近想用c做一个小游戏&#x…

ClickHouse的安装启动

安装步骤 1.关闭防火墙 2.修改资源限制配置文件 2.1 路径&#xff1a;/etc/security/limits.conf 在末尾添加&#xff1a; * soft nofile 65536 #任何用户可以打开的最大的文件描述符数量&#xff0c;默认1024 这里的设置会限制tcp连接数 * hard nofile 65536 * soft nproc…

Android 测试

工程目录图 1- Espresso 2- uiautomator Espresso 文档UI Automator文档ui-automator 英文文档 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;testespresso 参考文献 Android 利用 espre…

自建纯内网iot平台服务,软硬件服务器全栈实践

基于以下几个考虑&#xff0c;自制硬件设备&#xff0c;mqtt内网服务器。 1.米家app不稳定&#xff0c;逻辑在云端或xiaomi中枢网关只支持少部分在本地计算。 2.监控homeassistant官方服务有大量数据交互。可能与hass安装小米账户有关。 3.硬件&#xff1a;原理图&#xff0c;l…

机器学习李宏毅学习笔记39

文章目录 前言一、大模型的发展趋势二、KNN LM总结 前言 大模型大资料 大模型的顿悟时刻 一、大模型的发展趋势 随数据量增加&#xff0c;模型可以从量变达到质变&#xff0c;从某一刻开始突然学会东西。 当成为大模型时&#xff0c;分数会从0,0突然变成100&#xff0c;完成“…

OSG3.6.5 + VS2017前期准备及编译

OSG3.6.5 VS2017前期准备及编译 1、前期准备 1.1、osg稳定版本源码 Stable releases (openscenegraph.com) 1.2、osg依赖项 Dependencies (openscenegraph.com) 1.3、osg测试及演示数据 Data Resources (openscenegraph.com) 1.4、安装doxygen和Graphviz&#xff08;用…

Springboot计算机课程教学辅助系统小程序【纯干货分享,免费领源码01616】

目 录 摘要 1 绪论 1.1课题背景 1.2研究现状 1.3springboot框架介绍 1.4小程序框架以及目录结构介绍 2 计算机课程教学辅助系统小程序系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 操作可行性分析 2.2 系统业务流程分析 2.3 系统功能…

Practice3|922. 按奇偶排序数组 II、143. 重排链表

922. 按奇偶排序数组 II 1.题目&#xff1a; 给定一个非负整数数组 nums&#xff0c; nums 中一半整数是 奇数 &#xff0c;一半整数是 偶数 。 对数组进行排序&#xff0c;以便当 nums[i] 为奇数时&#xff0c;i 也是 奇数 &#xff1b;当 nums[i] 为偶数时&#xff0c; i…

Spring Cloud Eureka 服务注册和服务发现超详细(附加--源码实现案例--及实现逻辑图)

文章目录 EurekaEureka组件可以实现哪些功能什么是CAP原则&#xff1f;服务注册代码实战搭建注册中心服务A搭建服务B搭建启动服务启动注册中心启动服务A启动服务B 结束语 Eureka 这篇文章先讲述一下Eureka的应用场景、代码实现案例&#xff0c;多个服务模块注册到Euraka中&…