Qt QSqlTableModel详解

news2024/11/17 1:05:50

背景知识:

Qt SQL的API分为不同层:

  1. 驱动层 

 驱动层  对于QT是基于C++来实现的框架,该层主要包括QSqlDriver、QSqlDriverCreator、QSqlDriverCreatorbase、QSqlDriverPlugin and QSqlResult。这一层提供了特定数据库和SQL API层之间的底层桥梁。

  1. SQL API层

SQL API层  对于SQL API 层提供了数据库的访问相关类,其中,QSqlDataBase类进行连接,QSqlQuery完成数据库的交互。除此之外,还有QSqlError、QSqlField、QSqlIndex and QSqlRecord类。

  1. 用户接口层

用户接口层  用户接口层的几个类实现将数据库中的数据链接到窗口部件上,这些类是使用模型/视图框架实现的,他们是更高层次的抽象,主要包括QSqlQureyModel,QSqlTableModel and QSqlRelationalTableModel。

用户接口层的类使用模型/视图框架实现了将数据库中的数据链接到窗口控件上

QTableView是常用的内容显示视图组件。数据模型类有:QSqlQueryModel 、QSqlTableModel 、QSqlRelationalTableModel

QSqlQueryModel :通过设置SELECT语句查询获取内容,Model数据是只读的,不能进行编辑。

QSqlTableModel : 直接设置一个数据表的名称,可以获取数据表的全部记录,结果是可编辑的。实现对数据的编辑、插入、删除等操作。实现数据的排序和过滤。

QSqlRelationalTableModel: 编辑一个数据表,将代码字段通过关系与代码表关联,将代码字段的编辑转换为直观的内容选择编辑。

QSqlTableModel

直接设置一个数据表的名称,可以获取数据表的全部记录,结果是可编辑的。实现对数据的编辑、插入、删除等操作。实现数据的排序和过滤。

一般是模型使用QSqlTableModel,视图使用QTableView。

优点:

  1. 简单易用,可以通过model直接操作字段数据
  2. 支持编辑,直接在视图中添加、修改、删除数据。
  3. 内置排序和过滤功能

缺点

  1. 只有用户单张表数据,无法执行自定义的sql语句
  2. 性能稍差,需要额外处理字段信息和刷新模型
  3. 不支持事务操作

常用的api函数

//设置数据表的名称,不立即读取数据

virtual void setTable(const QString &tableName);

//从字段获取到字段的索引号

int fieldIndex(const QString &fieldNameconst;

//数据表的主索引

QSqlIndex primaryKey() const;

//设置编辑策略

virtual void setEditStrategy(EditStrategy strategy);

enum EditStrategy {OnFieldChangeOnRowChangeOnManualSubmit};

OnFieldChange字段变化立即更新到数据库

OnRowChange当前行变换时更新到数据库

OnManualSubmit所有修改暂时缓存,只有手动调submitAll才保存修改到数据库

bool isDirty() const;//若有未更新到数据库的修改,返回true.

bool submitAll();//提交所有未更新的修改到数据库

void revertAll();//取消所有未更新的修改

QSqlError lastError() const;//获取错误信息

//设置模型的表头

bool setHeaderData(int sectionQt::Orientation orientationconst QVariant &value,nt role = Qt::EditRoleoverride;

//模型的行数

int rowCount(const QModelIndex &parent = QModelIndex()) const override;

//一条空记录获取字段名,没有值

QSqlRecord record() const;

//获取某行的记录数据

QSqlRecord record(int rowconst;

//QSqlRecord的value函数,获取某个字段的值

QVariant value(const QStringnameconst;

QModelIndex index(int rowint columnconst QModelIndex &parent = QModelIndex()) const override;

//QModelIndex 类的data函数,从而得到某行某列的数据

inline QVariant data(int role = Qt::DisplayRoleconst;或者

QVariant data(const QModelIndex &idxint role = Qt::DisplayRoleconst override;

//QSqlRecord类设置某个字段的值

void setValue(int iconst QVariantval);

void setValue(const QStringnameconst QVariantval);

//插入列

inline bool insertColumn(int columnconst QModelIndex &parent = QModelIndex());

//在某row行前插入数据

inline bool insertRow(int rowconst QModelIndex &parent = QModelIndex());

bool insertRows(int rowint countconst QModelIndex &parent = QModelIndex()) override;

bool insertRecord(int rowconst QSqlRecord &record);

//设置某行某列的数据

bool setData(const QModelIndex &indexconst QVariant &valueint role = Qt::EditRoleoverride;

//删除某行记录

bool removeRows(int rowint countconst QModelIndex &parent = QModelIndex()) override;

inline bool removeRow(int rowconst QModelIndex &parent = QModelIndex());

//修改某行的值

bool setRecord(int rowconst QSqlRecord &record);

//调用其基类QSqlQueryModel的setQuery函数,实现精准过滤,并显示部分字段

void setQuery(const QSqlQuery &query);

void setQuery(const QString &queryconst QSqlDatabase &db = QSqlDatabase());

tabModel->QSqlQueryModel::setQuery("select empNo, Name from employee where Name='王五'");

setQuery函数相当于QSqlQuery对象执行了exec函数

//按某一列排序和排序规则,需要调用select函数才生效,实际上是sql上午ORDER BY子句

virtual void setSort(int columnQt::SortOrder order);

//设置记录数据的过滤条件,过滤的字符串实际上为sql语句where后的字段。调用setFilter后无需调用select函数就可以立即刷新记录

virtual void setFilter(const QString &filter);

//查询数据表的数据,并使用设置的排序和过滤规则这是查询并显示全部的字段数据

virtual bool select();

//清除释放所有数据

void clear() override;

例子

  1. 数据库使用SQLite数据库,格式为.db3
  2. 模型使用QSqlTableModel,视图使用QTableView
  3. 因为QSqlTableModel可编辑,可使用代理处理编辑操作。
  4. QSqlTableModel的数据和界面其他控件通过QDataWidgetMapper进行关联
  5. 这里使用的OnManualSubmit:所有修改暂时缓存,只有手动调submitAll才保存修改到数据库。

打开数据库:

void MainWindow::on_actOpenDB_triggered()
{
    QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","",
                             "SQL Lite数据库(*.db *.db3)");
    if (aFile.isEmpty())  //选择SQL Lite数据库文件
       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::openTable()
{//打开数据表
    tabModel=new QSqlTableModel(this,DB);//数据表
    tabModel->setTable("employee"); //设置数据表
    tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//数据保存方式,OnManualSubmit , OnRowChange
    tabModel->setSort(tabModel->fieldIndex("empNo"),Qt::AscendingOrder); //排序
    if (!(tabModel->select()))//查询数据
    {
       QMessageBox::critical(this, "错误信息",
              "打开数据表错误,错误信息\n"+tabModel->lastError().text(),
                 QMessageBox::Ok,QMessageBox::NoButton);
       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("Department"),Qt::Horizontal,"部门");
    tabModel->setHeaderData(tabModel->fieldIndex("Education"),Qt::Horizontal,"学历");
    tabModel->setHeaderData(tabModel->fieldIndex("Salary"),Qt::Horizontal,"工资");

    tabModel->setHeaderData(tabModel->fieldIndex("Memo"),Qt::Horizontal,"备注"); //这两个字段不再tableView中显示
    tabModel->setHeaderData(tabModel->fieldIndex("Photo"),Qt::Horizontal,"照片");

    theSelection=new QItemSelectionModel(tabModel);//关联选择模型
//theSelection当前项变化时触发currentChanged信号
    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->setModel(tabModel);//设置数据模型
    ui->tableView->setSelectionModel(theSelection); //设置选择模型
    ui->tableView->setColumnHidden(tabModel->fieldIndex("Memo"),true);//隐藏列
    ui->tableView->setColumnHidden(tabModel->fieldIndex("Photo"),true);//隐藏列

//tableView上为“性别”和“部门”两个字段设置自定义代理组件
    QStringList strList;
    strList<<"男"<<"女";
    bool isEditable=false;
    delegateSex.setItems(strList,isEditable);
    ui->tableView->setItemDelegateForColumn(
       tabModel->fieldIndex("Gender"),&delegateSex); //Combbox选择型

    strList.clear();
    strList<<"销售部"<<"技术部"<<"生产部"<<"行政部";
    isEditable=true;
    delegateDepart.setItems(strList,isEditable);
    ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("Department"),&delegateDepart); //Combbox选择型

//创建界面组件与数据模型的字段之间的数据映射
    dataMapper= new QDataWidgetMapper();
    dataMapper->setModel(tabModel);//设置数据模型
    dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);//

//    dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); //含有外键的
//界面组件与tabModel的具体字段之间的联系
    dataMapper->addMapping(ui->dbSpinEmpNo,tabModel->fieldIndex("empNo"));
    dataMapper->addMapping(ui->dbEditName,tabModel->fieldIndex("Name"));
    dataMapper->addMapping(ui->dbComboSex,tabModel->fieldIndex("Gender"));

    dataMapper->addMapping(ui->dbSpinHeight,tabModel->fieldIndex("Height"));
    dataMapper->addMapping(ui->dbEditBirth,tabModel->fieldIndex("Birthday"));
    dataMapper->addMapping(ui->dbEditMobile,tabModel->fieldIndex("Mobile"));

    dataMapper->addMapping(ui->dbComboProvince,tabModel->fieldIndex("Province"));
    dataMapper->addMapping(ui->dbEditCity,tabModel->fieldIndex("City"));
    dataMapper->addMapping(ui->dbComboDep,tabModel->fieldIndex("Department"));

    dataMapper->addMapping(ui->dbComboEdu,tabModel->fieldIndex("Education"));
    dataMapper->addMapping(ui->dbSpinSalary,tabModel->fieldIndex("Salary"));

    dataMapper->addMapping(ui->dbEditMemo,tabModel->fieldIndex("Memo"));

//    dataMapper->addMapping(ui->dbPhoto,tabModel->fieldIndex("Photo")); //图片无法直接映射

    dataMapper->toFirst();//移动到首记录

    getFieldNames();//获取字段名称列表,填充ui->groupBoxSort组件

//更新actions和界面组件的使能状态
    ui->actOpenDB->setEnabled(false);

    ui->actRecAppend->setEnabled(true);
    ui->actRecInsert->setEnabled(true);
    ui->actRecDelete->setEnabled(true);
    ui->actScan->setEnabled(true);

    ui->groupBoxSort->setEnabled(true);
    ui->groupBoxFilter->setEnabled(true);
}

添加操作

void MainWindow::on_actRecAppend_triggered()
{//添加记录
    tabModel->insertRow(tabModel->rowCount(),QModelIndex()); //在末尾添加一个记录

    QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);//创建最后一行的ModelIndex
    theSelection->clearSelection();//清空选择项
    theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//设置刚插入的行为当前选择行

    int currow=curIndex.row(); //获得当前行
    tabModel->setData(tabModel->index(currow,0),2000+tabModel->rowCount()); //自动生成编号
    tabModel->setData(tabModel->index(currow,2),"男");
// 插入行时设置缺省值,需要在primeInsert()信号里去处理
}

 删除

void MainWindow::on_actRecDelete_triggered()
{//删除当前记录
//    tabModel->removeRow(theSelection->currentIndex().row());

    QModelIndex curIndex=theSelection->currentIndex();//获取当前选择单元格的模型索引
    tabModel->removeRow(curIndex.row()); //删除最后一行

}

保存

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_actRevert_triggered()
{//取消修改
    tabModel->revertAll();
    ui->actSubmit->setEnabled(false);
    ui->actRevert->setEnabled(false);
}

排序

void MainWindow::on_radioBtnAscend_clicked()
{//升序 tabModel->setSort(ui->comboFields->currentIndex(),Qt::AscendingOrder);
    tabModel->select();
}

void MainWindow::on_radioBtnDescend_clicked()
{//降序   tabModel->setSort(ui->comboFields->currentIndex(),Qt::DescendingOrder);
    tabModel->select();
}

过滤

void MainWindow::on_radioBtnMan_clicked()
{
    tabModel->setFilter(" Gender='男' ");
}

void MainWindow::on_radioBtnWoman_clicked()
{
    tabModel->setFilter(" Gender='女' ");
}

void MainWindow::on_radioBtnBoth_clicked()
{
    tabModel->setFilter("");
}


或者是直接调用QSqlQueryModel的setQuery函数,这样视图就会按实际查询的字段显示
void MainWindow::on_actPhotoClear_triggered()
{
    tabModel->QSqlQueryModel::setQuery("select empNo, Name from employee where Name='王五'");
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AutoSAR系列讲解(入门篇)3.2-RTE对Runnables的运行支撑

目录 一、作为运行环境的主要功能点 二、Runnables的触发条件 一、作为运行环境的主要功能点 通过RTE给runnable提供触发事件。 之前说过了runnable是可以被触发的&#xff0c;就是需要通过RTE来实现这个触发和调用runnable&#xff0c;具体在下面讲解 通过RTE给runnable提供…

STM32外设系列—DHT11

文章标题 一、DHT11简介二、数据手册分析2.1 接口说明2.2 串行通信说明2.2.1 单总线通信2.2.2 单总线传输数据位定义2.2.3 时序图 三、DHT11程序设计3.1 初始化GPIO3.2 发送起始信号3.3 接收一个字节数据3.4 接收温湿度信息并校准 四、总结 一、DHT11简介 DHT11是一款常用的数…

Qt生成安卓工程运行闪退分析

提示找不到库 jin目录下库是存在的 提示下列库没有找到 libopencv_java4.so libtiff.so libboost_filesystem.so.1.71.0 libboost_chrono.so.1.71.0 libboost_regex.so.1.71.0 导致无法加载符号 最终导致应用无法启动&#xff0c;而退出 重新编译为静态库,并以静态库方式链…

技术管理第三板斧招聘与解聘-升级汰换

1.开除人“心要慈&#xff0c;刀要快” No Surprise&#xff1a; 不要突然Fire一个人&#xff08;离职一定不是一个突发行为&#xff09;&#xff0c;没有任何征兆告诉员工 A“你被开除了”&#xff0c;这是典型的管理失职。如果A存在问题&#xff0c;你应该先告知&#xff0…

数据结构--顺序表的基本操作--插入 and 删除

数据结构–顺序表的基本操作–插入 顺序表的插入操作 实现目标 ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。 typedef struct {int data[MaxSize];int len; }Sqlist;代码实现&#xff1a; #include <stdio.h> #include <stdlib.h> …

前端JavaScript入门-day03

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 1、循环-for 1. for 循环-基本使用 1. for循环语法 2. 退出循环 2. for 循环嵌套 2、数组 1 数组是…

易点易动设备管理平台:为制药厂提升设备管理效率保驾护航

在高度竞争的制药行业中&#xff0c;设备管理对企业的生产效率和产品质量起着至关重要的作用。如何在保证设备安全、高效运行的同时&#xff0c;降低成本和提高设备利用率呢&#xff1f;易点易动设备管理平台为您提供了完美的解决方案。本文将详细阐述易点易动设备管理平台如何…

Linux搭建sqli-labs(sql注入实战)

目录 一、安装phpstudy 二、更改配置文件 三、加载数据库 一、安装phpstudy 需要php、mysql、httpd环境&#xff0c;phpstudy可以做到快速部署。 cd /opt yum install -y wget wget -O install.sh https://notdocker.xp.cn/install.sh && sudo bash install.sh wget…

Podman安装nacos使用(默认最新版)

一,命令熟悉 --name : 命名容器的名称. -d:表示在后台运行容器. -p:指定端口映射。如: 左边的8848是宿主机的端口,右边的8848是nacos容器内部的端口。 docker.io/nacos/nacos-server:表示根据docker.io/nacos/nacos-server镜像运行容器。 --restart=always 表示启…

【MySQL】看完这篇不信你学不会如何使用数据处理函数

&#x1f3ac; 博客主页&#xff1a;博主链接 &#x1f3a5; 本文由 M malloc 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f384; 学习专栏推荐&#xff1a;LeetCode刷题集&#xff01; &#x1f3c5; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指…

JDK的生成keytool证书

JDK的生成keytool证书 首先安装jdk环境 地址: https://www.oracle.com/downloads/ 点击页面下方的java 选择Java (JDK) for Developers 选择你的环境安装包&#xff0c;我的电脑是windows64位&#xff0c;选择x64 MSI Installer 下载完成后安装 进入jdk根路径执行命令 keytoo…

PaddleOCR #使用PaddleOCR进行光学字符识别 - OCR模型对比

PaddleOCR 在其工具包中提供了多种模型&#xff0c;并且非常易于应用。根据准确性和速度比较模型始终是一个好习惯。在本节中&#xff0c;我们将比较 PaddleOCR 提供的四种模型&#xff0c;即 SRN、PP-OCRv2、PP-OCRv3 和 NRTR。比较将在 COCO-text 数据集上进行&#xff0c;该…

【每日编程Day30】最难的问题 因子个数

目录 一、选择题 二、编程题 1、最难的问题 2、因子个数 一、选择题 &#xff08;1&#xff09;当包装类与基本数据类型比较&#xff0c;包装类会自动茶香变为基本数据类型再比较&#xff1b; &#xff08;2&#xff09;包装数据类直接赋值&#xff0c;默认调用其对用的val…

项目经理提高影响力的6大原则

在很多临时组建的项目团队中&#xff0c;项目经理往往处于权、责、利不匹配的尴尬状态&#xff0c;即有责无权。项目经理既需要对项目目标的实现负责&#xff0c;又没有相匹配的权利。 在这种情况下&#xff0c;项目经理不能通过权利进行团队管理&#xff0c;只能通过个人影响力…

cmd 108个常用命令,看看你知道多少

背景 一、CMD是什么 在不同的操作系统环境下&#xff0c;命令提示符各不相同&#xff0c;在Windows环境下&#xff0c;命令行程序为cmd.exe&#xff0c;是一个32 位的命令行程序。 cmd是指命令提示符&#xff0c;是在操作系统中&#xff0c;提示进行命令输入的一种工作提示符…

SpringBoot处理实际开发中常见的七种全局异常详解(全面详细+Gitee源码)

前言&#xff1a;在日常的开发工作中&#xff0c;项目在运行过程中多多少少是避免不了报错的&#xff0c;对于报错信息肯定不可以把全部信息都抛给客户端去显示&#xff0c;这里就需要我们对常见的七种异常情况统一进行处理&#xff0c;让整个项目更加优雅。 目录 一、基本介绍…

别迷茫!电子与通信相关专业,详细就业方向!

一、通信领域 1、算法工程师 算法工程师对我们来说&#xff0c;有两种可选择的方向&#xff0c;一种是通信算法工程师&#xff0c;一种是信号处理算法工程师。 通信算法工程师&#xff1a;需要对通信目标、干扰、杂波和信道模拟进行算法研究与数学仿真。了解4G和5G的相关技术。…

【Logback技术专题】「入门到精通系列教程」深入探索Logback日志框架的原理分析和开发实战技术指南(中篇)

深入探索Logback日志框架的原理分析和开发实战技术指南&#xff08;下篇&#xff09; Logback日志框架slf4j和logback的关系slf4jSlf4j的核心代码getLogger方法LoggerFactory的bind()方法 slf4j logback配置 log4j和logback的关系Logback的配置文件配置文件读取顺序 Logback配置…

告别StringUtil:使用Java 全新String API优化你的代码

前言 Java 编程语言的每一次重要更新&#xff0c;都引入了许多新功能和改进。 并且在String 类中引入了一些新的方法&#xff0c;能够更好地满足开发的需求&#xff0c;提高编程效率。 repeat(int count)&#xff1a;返回一个新的字符串&#xff0c;该字符串是由原字符串重复指…

MySQL数据库基础 16

第十六章 变量、流程控制与游标 1. 变量1.1 系统变量1.1.1 系统变量分类1.1.2 查看系统变量 1.2 用户变量1.2.1 用户变量分类1.2.2 会话用户变量1.2.3 局部变量1.2.4 对比会话用户变量与局部变量 2. 定义条件与处理程序2.1 案例分析2.2 定义条件2.3 定义处理程序2.4 案例解决 3…