Qt基础 | QSqlTableModel 的使用

文章目录

  • 一、QSqlTableModel 的使用
    • 1.主窗口MainWindow类定义
    • 2.构造函数
    • 3.打开数据表
      • 3.1 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
      • 3.2 数据模型设置、选择模型、自定义代理组件、界面组件与模型数据字段间的数据映射
    • 4.添加、插入与删除记录
    • 5.保存与取消修改
    • 6.设置和清除照片
    • 7.数据记录的遍历
    • 8.记录排序
    • 9.记录过滤

关于QSqlDatabase、QSqlTableModel、QSqlRecord、QDataWidgetMapper 类的使用可参考:Qt基础 | Qt SQL模块介绍 | Qt SQL模块常用类及其常用函数介绍

一、QSqlTableModel 的使用

  这一部分使用 QSqlTableModel 显示实例数据库 demodb 中 employee 数据表的内容,实现编辑、插入、删除记录的操作,实现数据的排序和记录过滤,还实现 BLOB 类型字段 Photo 中存储照片的显示、导入等操作。

1.主窗口MainWindow类定义

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include    <QMainWindow>#include    <QLabel>
#include    <QString>#include    <QtSql>
#include    <QDataWidgetMapper>#include    "qwcomboboxdelegate.h"namespace Ui {
class MainWindow;
}class MainWindow : public QMainWindow
{Q_OBJECTprivate:QSqlDatabase  DB;//数据库连接QSqlTableModel  *tabModel;  //数据模型QItemSelectionModel *theSelection; //选择模型QDataWidgetMapper   *dataMapper; //数据映射QWComboBoxDelegate   delegateSex; //自定义数据代理,性别QWComboBoxDelegate   delegateDepart; //自定义数据代理,部门void    openTable();//打开数据表void    getFieldNames();//获取字段名称,填充“排序字段”的comboBox
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);// QTableView的SelectionModel的行发生了变化,进行处理void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);void on_actOpenDB_triggered();void on_actRecAppend_triggered();void on_actRecInsert_triggered();void on_actRevert_triggered();void on_actSubmit_triggered();void on_actRecDelete_triggered();void on_actPhoto_triggered();void on_actPhotoClear_triggered();void on_radioBtnAscend_clicked();void on_radioBtnDescend_clicked();void on_radioBtnMan_clicked();void on_radioBtnWoman_clicked();void on_radioBtnBoth_clicked();void on_comboFields_currentIndexChanged(int index);void on_actScan_triggered();
private:Ui::MainWindow *ui;
};#endif // MAINWINDOW_H

MainWindow 类中定义了几个私有变量:

  • QSqlDatabase DB:用于加载数据库驱动和建立与数据库之间的连接

  • QSqlTableModel *tabModel:用于指定某个数据表 ,作为数据表的数据模型

  • QItemSelectionModel *theSelection:作为 tabModel 的选择模型,提供 currentChanged()、currentRowChanged()信号,在 tabModel 选择的字段发生变化、当前记录发生变化时发射信号,以便程序进行响应。

    例如,在 currentChanged() 信号发射时,检查 tabModel 是否有数据被修改 ,从而更新界面上 “保存”和“取消“两个按钮的使能状态

  • QDataWidgetMapper *dataMapper:用于实现界面组件与 tabModel 的字段之间的映射。

    例如,界面上的 QLineEdit 型的 dbEditName 组件与数据表的 Name 字段映射,当前记录变化时会自动更新显示当前记录 Name 段的数据。

  • QWComboBoxDelegate delegateSex:是自定义的基于 QComboBox 的代理类,delegateSex 和 delegateDepart 用作 tableView 中“性别” 和 “部门” 字段的代理组件。

私有函数:

  • openTable函数:用于打开数据表,包括添加 SQLite 数据库驱动、打开数据库文件、连接 employee 数据表并设置显示属性,并创建 tableView 显示的代理组件,设置数据源与界面组件的映射等
  • getFieldNames函数:用于获取数据表 employee 的所有字段的名称,并填充界面上 “排序字段” 后的 ComboBox 组件。

槽函数:

  • on_currentChanged:用于检查数据表内容是否修改,根据是否有未提交的修改,更新工具栏按钮 “保存” 和 “取消” 两个按钮的使能状态。
  • on_currentRowChanged:用于在当前行变化时,从新的记录里提取 Photo 字段的内容,并将图片在 QLabel 组件里显示出来。

2.构造函数

  MainWindow 的构造函数代码如下,主要是对 tableView 一些显示属性的设置。

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);this->setCentralWidget(ui->splitter);//   tableView显示属性设置ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);ui->tableView->setAlternatingRowColors(true);
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);
}
  • setSelectionBehavior函数:用于定义视图(View)选择哪种选择行为

    void setSelectionBehavior(QAbstractItemView::SelectionBehavior behavior)
    

    QAbstractItemView::SelectionBehavior是一个枚举类型,有如下选择:

    • QAbstractItemView::SelectItems:选择单个项
    • QAbstractItemView::SelectRows:仅选择行
    • QAbstractItemView::SelectColumns:仅选择列
  • setSelectionMode函数:用于定义视图(view)的选择模式

    void setSelectionMode(QAbstractItemView::SelectionMode mode)
    

    QAbstractItemView::SelectionMode是一个枚举类型,有如下取值:

    • QAbstractItemView::SingleSelection:单选模式,用户只能选择一个项目。
    • QAbstractItemView::ContiguousSelection:连续选择模式,用户可以选择多个项目,但这些项目必须在视觉上是连续的。
    • QAbstractItemView::ExtendedSelection:扩展选择模式,用户可以选择多个项目,并且可以选择非连续的项目。
    • QAbstractItemView::MultiSelection:多选模式,用户可以选择多个项目。
    • QAbstractItemView::NoSelection:无选择模式
  • setAlternatingRowColors函数:用来控制当前是否启用交替行颜色绘制背景

    void setAlternatingRowColors(bool enable)
    
    • alternatingRowColors 属性设置为 true 时,视图中的项背景将使用 QPalette::BaseQPalette::AlternateBase 颜色交替绘制。QPalette::Base 是默认的背景颜色,而 QPalette::AlternateBase 是用于交替行的背景颜色。

      image-20240723122428920

    • alternatingRowColors 属性设置为 false 时,所有项的背景将统一使用 QPalette::Base 颜色绘制。

  • resizeColumnsToContents函数:用于根据列中每个项的代理组件的大小提示来调整所有列的宽度

    void QTableView::resizeColumnsToContents()
    
  • horizontalHeader函数:用于返回 QTableView 的水平表头

    QHeaderView *QTableView::horizontalHeader() const
    

3.打开数据表

  打开数据表这一部分主要包括:

  • 添加 SQLite 数据库驱动、设置数据库名称、打开数据库
  • 设置数据模型、选择模型、自定义代理组件、界面组件与模型数据字段间的数据映射

3.1 添加 SQLite 数据库驱动、设置数据库名称、打开数据库

  这一部分主要用到了 QSqlDatabase 类,该类用于处理与数据库的连接。

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

补充

  • QSqlDatabase::addDatabase:该静态函数用于添加数据库驱动,其返回结果为 QSqlDatabase 类,该类可用于数据库操作,包括建立数据库连接,设置登陆数据库的参数,打开数据库等。

    其完整的函数声明如下:

    [static] QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName = QLatin1String(defaultConnection))
    

    示例:

    // 添加一个名为 "myConnection" 的 SQLite 数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "myConnection");
    db.setDatabaseName("example.db"); // 设置数据库文件名
    db.setUserName("user"); // 设置用户名
    db.setPassword("password"); // 设置密码// 打开数据库连接
    if (db.open()) {QSqlQuery query;query.exec("SELECT * FROM table_name"); // 执行查询while (query.next()) {// 处理查询结果}db.close();
    } else {qDebug() << "Error: Unable to open database";
    }
    

    还有一个函数重载,参数指定的不是驱动名称,而是 QSqlDriver 类。

    [static] QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver *driver, const QString &connectionName = QLatin1String(defaultConnection))
    

    示例:

    PGconn *con = PQconnectdb("host=server user=bart password=simpson dbname=springfield");
    QPSQLDriver *drv = new QPSQLDriver(con);
    QSqlDatabase db = QSqlDatabase::addDatabase(drv); // becomes the new default connection
    QSqlQuery query;
    query.exec("SELECT NAME, ID FROM STAFF");
    
  • QSqlDatabase类的数据库连接操作:用于设置数据库连接与登陆参数

    注意:对于 SQLite 数据库,只需用 setDatabaseName() 设置数据库文件即可。如果是网络型数据库,如 Oracle、MS SQL Server等,还需要使用 setHostName() 设置主机名,setUserName() 设置数据库用户名,setPassword() 设置数据库登陆密码。

    • setDatabaseName:设置数据库名称
    • setHostName:设置数据库主机名
    • setUserName:设置数据库用户名
    • setPassword:设置数据库登陆密码
  • open()函数:打开数据库。如果成功打开数据库则返回true

3.2 数据模型设置、选择模型、自定义代理组件、界面组件与模型数据字段间的数据映射

  这部分用到 3 个类:

  • QSqlTableModel

    QSqlTableModel 是一个用于显示和编辑单个数据库表内容的模型

  • QTableView

    二维数据表视图组件,有多个行和多个列,每个基本显示单元是一个单元格,通过 setModel() 函数设置一个 QSqlTableModel 类的数据模型之后,一个单元格显示 QSqlTableModel 数据模型中的一个项

  • QItemSelectionModel

    一个用于跟踪视图组件的单元格选择状态的类,当在 QTableView 选择某个单元格,或多个单元格时,通过 QItemSelectionModel 可以获得选中的单元格的模型索引,为单元格的选择操作提供方便。

这几个类之间的关系是:QTableView是界面视图组件,其关联的数据模型是 QSqlTableModel,关联的项选择模型是 QItemSelectionModel。

数据模型创建与属性设置

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;
}
  • 创建数据库模型且指定数据库的连接

    通过往 QSqlTableModel 构造函数中传入参数来指定数据库连接

    构造函数为:

    QSqlTableModel::QSqlTableModel(QObject *parent = nullptr, QSqlDatabase db = QSqlDatabase())
    

    在本案例中为

    tabModel=new QSqlTableModel(this,DB);//数据表
    
  • 使用 setTable() 函数来指定数据表,此时不会立即读取记录,但会提取字段信息

    [virtual] void QSqlTableModel::setTable(const QString &tableName)
    

    在本案例中为

    tabModel->setTable("employee"); //设置数据表
    
  • 使用 setSort() 函数设置排序字段与排序规则,需调用 select() 函数才生效

    [virtual] void QSqlTableModel::setSort(int column, Qt::SortOrder order)
    
    • 第一个参数 column 是排序字段的列号
    • 第二个参数 order 是枚举类型Qt::SortOrder,表示排序方式,其中,Qt::AscendingOrder表示升序,Qt::DescendingOrder表示降序

    在本案例中为

    tabModel->setSort(tabModel->fieldIndex("empNo"),Qt::AscendingOrder); //排序
    
  • 使用 setEditStrategy() 函数用于设置编辑策略

    [virtual] void QSqlTableModel::setEditStrategy(QSqlTableModel::EditStrategy strategy)
    
    • 参数 strategy 是枚举类型 QSqlTableModel::EditStrategy,各取值的意义如下:
      • QSqlTableModel::OnFieldChange:字段值变化时立即更新到数据库
      • QSqlTableModel::OnRowChange:当前行(记录)变换时更新到数据库
      • QSqlTableModel::OnManualSubmit:所有修改暂时缓存,手动调用 submitAll() 保存所有修改,或调用 revertAll() 函数取消所有未保存的修改。
  • 使用 select() 函数查询数据表的数据,并使用设置的排序和过滤规则

    [virtual slot] bool QSqlTableModel::select()
    
    • 如果成功打开则返回true,否则,返回false

    在本案例中为:

    tabModel->select()
    

表头设置

  使用 setHeaderData() 函数设置表头,即设置数据库表的字段在 tableView 中显示时的字段名称。为此,将每个字段的显示设置为相应的中文标题。

[override virtual] bool QSqlQueryModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole)
  • 参数 section 是字段的序号,通过 fieldIndex() 函数可以获取某个字段名在数据模型里的序号
  • 参数 orientation 是字段的方向,其中,Qt::Horizontal表示是水平方向标题,Qt::Vertical表示是竖直方向标题
  • 参数 value 是要设置的值

表头设置部分代码为:

    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,"照片");

创建选择模型及信号的作用

  选择模型的作用是当用户在 TableView 组件上操作时,获取当前选择的行 、列信息,并且在选择的单元格变化时发射 currentChanged() 信号,在当前行变化时发射 currentRowChanged() 信号。

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

对应的槽函数为:

void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{//更新actPost和actCancel 的状态Q_UNUSED(current);Q_UNUSED(previous);ui->actSubmit->setEnabled(tabModel->isDirty()); //有未保存修改时可用ui->actRevert->setEnabled(tabModel->isDirty());
}void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{Q_UNUSED(previous);
// 行切换时的状态控制ui->actRecDelete->setEnabled(current.isValid());ui->actPhoto->setEnabled(current.isValid());ui->actPhotoClear->setEnabled(current.isValid());if (!current.isValid()){ui->dbLabPhoto->clear(); //清除图片显示return;}dataMapper->setCurrentIndex(current.row()); //更新数据映射到当前行,使界面上的编辑框、下拉列表框等与字段关联的界面组件显示当前记录的内容int curRecNo=current.row();//获取行号QSqlRecord  curRec=tabModel->record(curRecNo); //获取当前记录if (curRec.isNull("Photo"))  //图片字段内容为空ui->dbLabPhoto->clear();else{QByteArray data=curRec.value("Photo").toByteArray();QPixmap pic;pic.loadFromData(data);ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));}
}

tableView的设置

  用 QTableView 组件显示 tabModel 的表格数据内容时,需要设置其数据模型和关联选择模型,并且将 “Memo” 和 “Photo” 两个字段的列设置为隐藏,因为在表格里难以显示备注文件和图片。

ui->tableView->setModel(tabModel);//设置数据模型
ui->tableView->setSelectionModel(theSelection); //设置选择模型
ui->tableView->setColumnHidden(tabModel->fieldIndex("Memo"),true);//隐藏列
ui->tableView->setColumnHidden(tabModel->fieldIndex("Photo"),true);//隐藏列

  自定义基于 QComboBox 的代理组件类 QWComboBoxDelegate,组件类中有一个函数 setItems() ,用于初始化下拉列表框和设置是都可以编辑,

qwcombocoxdelegate.h

#ifndef QWCOMBOBOXDELEGATE_H
#define QWCOMBOBOXDELEGATE_H#include    <QStyledItemDelegate>
#include    <QComboBox>class QWComboBoxDelegate : public QStyledItemDelegate
{Q_OBJECTprivate:QStringList m_ItemList;//选择列表bool    m_isEdit; //是否可编辑public:QWComboBoxDelegate(QObject *parent=0);void    setItems(QStringList items, bool isEdit);//初始化设置列表内容,是否可编辑
//自定义代理组件必须继承以下4个函数QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const Q_DECL_OVERRIDE;void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;
};#endif // QWCOMBOBOXDELEGATE_H

qwcombocoxdelegate.cpp

#include "qwcomboboxdelegate.h"#include    <QComboBox>QWComboBoxDelegate::QWComboBoxDelegate(QObject *parent):QStyledItemDelegate(parent)
{}void QWComboBoxDelegate::setItems(QStringList items, bool isEdit)
{m_ItemList=items;m_isEdit=isEdit;
}QWidget *QWComboBoxDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(option);Q_UNUSED(index);QComboBox *editor = new QComboBox(parent);for (int i=0;i<m_ItemList.count();i++)   //从字符串列表初始下拉列表editor->addItem(m_ItemList.at(i));editor->setEditable(m_isEdit); //是否可编辑return editor;
}void QWComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{QString str = index.model()->data(index, Qt::EditRole).toString();QComboBox *comboBox = static_cast<QComboBox*>(editor);comboBox->setCurrentText(str);
}void QWComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{QComboBox *comboBox = static_cast<QComboBox*>(editor);QString str = comboBox->currentText();model->setData(index, str, Qt::EditRole);
}void QWComboBoxDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index) const
{Q_UNUSED(index);editor->setGeometry(option.rect);
}

  创建多个代理组件实例,分别用于“性别” 和 “部门” 两个字段。

//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选择型

数据映射

  QDataWidgetMapper 用于建立界面组件与数据模型之间的映射,可以将界面的 QLineEdit、QCombobox 等组件与数据模型的一个字段关联起来。当数据模型关联的字段内容发生变化时,自动更新组件的显示内容。

//创建界面组件与数据模型的字段之间的数据映射
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);
  • setModel() 函数–设置关联的数据模型

    void QDataWidgetMapper::setModel(QAbstractItemModel *model)
    

    用于设置 QDataWidgetMapper 将要使用的数据模型。参数 model 是一个指向 QAbstractItemModel 类型的指针

  • setSubmitPolicy() 函数–设置数据提交策略

    void setSubmitPolicy(QDataWidgetMapper::SubmitPolicy policy)
    

    其参数policy是一个枚举类型QDataWidgetMapper::SubmitPolicy。取值如下:

    • QDataWidgetMapper::AutoSubmit:自动,行切换时将自动提交修改。
    • QDataWidgetMapper::ManualSubmit:手动,需调用 submit() 方法,手工提交当前记录的修改。
  • addMapping() 函数 – 用于设置界面组件与数据模型的列的映射,这种映射关系使得控件的值可以与数据模型中的特定项关联起来

    void QDataWidgetMapper::addMapping(QWidget *widget, int section)
    

    参数 widget 是指向 UI 控件的指针,section 指定了数据模型中的列(如果方向是水平的)或行(如果方向是垂直的)

  • setCurrentIndex() 函数 – 将当前行数据映射到界面组件, 使界面上的编辑框、下拉列表框等与字段关联的界面组件显示当前记录的内容

    virtual void setCurrentIndex(int index)
    

    例如:

    dataMapper->setCurrentIndex(current.row()); //更新当前行数据映射
    
  • setCurrentModelIndex() 函数–当用户在视图中选择不同的行或列时,自动更新与之关联的表单或控件的数据。

    [slot] void QDataWidgetMapper::setCurrentModelIndex(const QModelIndex &index)
    
  • revert() 和 submit() 函数用于手工取消或提交当前记录的修改。

  • toFirst()、toPrevious()、toNext() 和 toLast() 函数用于在记录间移动

    如:toFirst()函数用于移动到首记录

获取数据表的所有字段名称

  使用不带参数的 record() 函数获取数据表的所有字段名称,并填充到排序的下拉列表框中

void MainWindow::getFieldNames()
{ //获取所有字段名称QSqlRecord  emptyRec=tabModel->record();//获取空记录,只有字段名for (int i=0;i<emptyRec.count();i++)ui->comboFields->addItem(emptyRec.fieldName(i));
}

4.添加、插入与删除记录

  使用 insertRow() 函数在数据模型的 row 行前面插入一行记录,如果 row 大于或等于数据模型的总行数,则在最后添加一行记录。最后,选中刚插入的那一行记录。

void MainWindow::on_actRecAppend_triggered()
{//添加记录tabModel->insertRow(tabModel->rowCount(),QModelIndex()); //在末尾添加一个记录QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);//创建最后一行的ModelIndextheSelection->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_actRecInsert_triggered()
{//插入记录QModelIndex curIndex=ui->tableView->currentIndex();tabModel->insertRow(curIndex.row(),QModelIndex());theSelection->clearSelection();//清除已有选择theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}

  使用 removeRow() 函数删除选中的那一行记录。

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

在插入或删除记录操作,未提交保存之前, tableView 的左侧表头会以标记表示记录编辑状态,"*"表示新插入的记录,”!” 表示删除的记录 。在保存或取消修改,这些标记就消失,删除的记录行也从 tableView 里删除。

5.保存与取消修改

  在打开数据表初始化时,设置数据模型的编辑策略为 OnManualSubmit,即手动提交修改。当数据模型的数据被修改后,不管是直接修改字段值,还是插入或删除记录,在未提交修改前,QSqlTableModel::isDirty() 函数返回 true,就是利用这个函数在槽函数 on_currentChanged() 里设置 ”保存修改“和”取消修改“ 按钮的使能状态。

  使用 submitAll() 函数用于将数据表所有未提交的修改保存到数据库中;使用 revertAll() 函数来取消所有修改。

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

6.设置和清除照片

  设置照片功能是用文件对话框选择一个图片文件,读取文件内容到 QByteArray 类型的变量data里,获取当前记录到变量 curRec 后,用 QSqlRecord 的 setValue() 函数为 Photo 字段设置数据为 data,然后用 setRecord() 函数更新当前记录的数据到数据模型,并在界面组件上显示。

注意:这里的更新只是更新到数据模型,并没有更新到数据库。

void MainWindow::on_actPhoto_triggered()
{
//设置照片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();int curRecNo=theSelection->currentIndex().row();QSqlRecord  curRec=tabModel->record(curRecNo); //获取当前记录curRec.setValue("Photo",data); //设置字段数据tabModel->setRecord(curRecNo,curRec);QPixmap pic;pic.load(aFile);  //在界面上显示ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->width()));
}

  清楚照片的功能是获取当前记录到变量 curRec 后,调用 setNull () 函数将 Photo 字段设置为 NULL,就是清除了字段的内容,然后更新记录到数据模型,并清除界面组件的显示。

void MainWindow::on_actPhotoClear_triggered()
{int curRecNo=theSelection->currentIndex().row();QSqlRecord  curRec=tabModel->record(curRecNo); //获取当前记录curRec.setNull("Photo");//设置为空值tabModel->setRecord(curRecNo,curRec);ui->dbLabPhoto->clear();
}

7.数据记录的遍历

  使用 record(int index) 函数获取每一行记录,并对该行记录的值进行修改。

void MainWindow::on_actScan_triggered()
{//涨工资,记录遍历if (tabModel->rowCount()==0)return;for (int i=0;i<tabModel->rowCount();i++){QSqlRecord aRec=tabModel->record(i); //获取当前记录float salary=aRec.value("Salary").toFloat();salary=salary*1.1;aRec.setValue("Salary",salary);tabModel->setRecord(i,aRec);}// 索引方式刷新记录,速度一样
//    float   salary;
//    for (int i=0;i<tabModel->rowCount();i++)
//    {
//        salary=tabModel->data(tabModel->index(i,10)).toFloat();
//        salary=salary*1.1;
//        tabModel->setData(tabModel->index(i,10),salary);
//    }if (tabModel->submitAll())QMessageBox::information(this, "消息", "涨工资计算完毕",QMessageBox::Ok,QMessageBox::NoButton);
}

8.记录排序

  使用 setSort() 函数设置数据表根据某个字段按照升序或降序排列,实际上就是设置 SQL 语句里的 ORDER BY 子句。在调用 setSort() 函数设置排序规则后,需要调用 QSqITableModel::select() 重新读取数据表的数据才会使排序规则生效。

void MainWindow::on_comboFields_currentIndexChanged(int index)
{//选择字段进行排序if (ui->radioBtnAscend->isChecked())tabModel->setSort(index,Qt::AscendingOrder);elsetabModel->setSort(index,Qt::DescendingOrder);tabModel->select();
}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();
}

9.记录过滤

  使用 setFilter() 函数设置记录的过滤条件,实际上就是设置 SQL 语句里的 WHERE 子句。调用 setFilter() 后无需调用 select() 函数就可以立即刷新记录,若要取消过滤条件,只需在 setFilter() 函数里传递一个空字符串。

void MainWindow::on_radioBtnMan_clicked()
{tabModel->setFilter(" Gender='男' ");
//    tabModel->select();
}void MainWindow::on_radioBtnWoman_clicked()
{tabModel->setFilter(" Gender='女' ");
//    tabModel->select();
}void MainWindow::on_radioBtnBoth_clicked()
{tabModel->setFilter("");
}

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

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

相关文章

计算机网络基础:1.上网设备与流程、OSI七层模型、TCP/IP五层模型

你正在经营一家繁忙的餐厅&#xff0c;顾客们点餐并期待着美味的食物。我们可以将网络的各个层次和设备比作餐厅的不同部分。 一、上网设备 网卡&#xff1a;就像是餐厅的点餐系统&#xff0c;顾客通过它来下单&#xff0c;而厨房通过它来接收订单。上网设备必须有网卡&#x…

数据结构之二元查找树转有序双向链表详解与示例(C/C++)

文章目录 1. 二元查找树&#xff08;BST&#xff09;简介2. 有序双向链表&#xff08;DLL&#xff09;简介3. 二元查找树的实现4. 转换为有序双向链表的步骤5. C实现代码6. C实现代码7. 效率与空间复杂度比较8. 结论 在数据结构与算法中&#xff0c;树和链表都是非常重要的数据…

压测实操--kafka-consumer压测方案

作者&#xff1a;九月 环境信息&#xff1a; 操作系统centos7.9&#xff0c;kafka版本为hdp集群中的2.0版本。 Consumer相关参数 使用Kafka自带的kafka-consumer-perf-test.sh脚本进行压测&#xff0c;该脚本参数为&#xff1a; thread&#xff1a;测试时的单机线程数&…

数据结构(稀疏数组)

简介 稀疏数组是一种数据结构&#xff0c;用于有效地存储和处理那些大多数元素都是零或者重复值的数组。在稀疏数组中&#xff0c;只有非零或非重复的元素会被存储&#xff0c;从而节省内存空间。 案例引入 假如想把下面这张表存入文件&#xff0c;我们会怎么做&#xff1f;…

Ubuntu 修改源地址

注意事项&#xff1a;版本说明&#xff01;&#xff01;&#xff01; Ubuntu24.04的源地址配置文件发生改变。 不再使用以前的 sources.list 文件&#xff0c;该文件内容变成了一行注释&#xff1a; # Ubuntu sources have moved to /etc/apt/sources.list.d/ubuntu.sources…

U盘有盘符但是打不开?深度解析与双路径恢复策略

数字时代&#xff0c;U盘作为我们日常工作和生活中不可或缺的数据存储工具&#xff0c;其稳定性和可靠性直接关系到我们数据的安全。然而&#xff0c;当您遇到U盘已成功识别盘符&#xff0c;却无法正常访问的情况时&#xff0c;这无疑是一个令人头疼的问题。本文将围绕“U盘有盘…

我在百科荣创企业实践——简易函数信号发生器(5)

对于高职教师来说,必不可少的一个任务就是参加企业实践。这个暑假,本人也没闲着,报名参加了上海市电子信息类教师企业实践。7月8日到13日,有幸来到美丽的泉城济南,远离了上海的酷暑,走进了百科荣创科技发展有限公司。在这短短的一周时间里,我结合自己的教学经验和企业的…

【保姆级教程】油猴脚本的安装使用

目录 前言 一、油猴简介 1. 核心功能 2. 应用场景 3. 安全性与兼容性 4. 社区生态 二、教学开始&#xff08;嫌麻烦直接目录跳转开始学习&#xff09; 1.插件安装&#xff08;以Microsoft Edge浏览器为例&#xff09; 2.获取脚本 3.大展身手 三、扩展&#xff08;脚…

【23】Android高级知识之Window(四) - ThreadedRenderer

一、概述 在上一篇文章中已经讲了setView整个流程中&#xff0c;最开始的addToDisplay和WMS跨进程通信的整个过程做了什么。继文章Android基础知识之Window(二)&#xff0c;这算是另外一个分支了&#xff0c;接着讲分析在performTraversals的三个操作中&#xff0c;最后触发pe…

Ansible的脚本-----playbook剧本【上】

目录 1.playbook剧本组成 2.playbook剧本实战演练 2.1 实战演练一&#xff1a;给被管理主机安装httpd服务 2.2 实战演练二&#xff1a;定义、引用变量 2.3 实战演练三&#xff1a;指定远程主机sudo切换用户 2.4 实战演练四&#xff1a;when条件判断 2.5 实战演练五&…

一家银行数据库的六年攻坚战

前沿科技&#xff0c;数智经济 文&#xff5c;白 鸽 编&#xff5c;王一粟 从传统的商业数据库Oracle&#xff0c;到后来加入的MySQL数据库&#xff0c;再到现如今的分布式数据库&#xff0c;中国金融行业数据库的转型升级走过了多年时间。 “2018年&#xff0c;我们提出…

《你敢不学习?》numpy库——细细学<2>

续接上集: 1、reshape函数&#xff1a;重塑数组的形状 改变数组的维度 其语法为 numpy.reshape(arr, newshape, orderC) 如下图所示 首先生成一个1到17不包括17的16个元素的数组&#xff0c;然后对这个数组进行重塑&#xff0c;使其成为4行4列的二维数组&#xff0c;注意&…

【Micropython入门】Thoony安装并烧录固件到ESP32

文章目录 前言Thonny IDE 介绍Thoony的下载烧录固件到ESP32下载固件烧录固件烧录时的小问题 总结 前言 MicroPython 是一款为微控制器设计的精简版 Python 解释器&#xff0c;它以其简洁和强大的特性赢得了众多嵌入式开发者的青睐。ESP32 是一款功能强大且价格低廉的微控制器&…

React开发者并不存在

根本就没有所谓的React开发者 — 永远不要这样称呼自己。 这是许多软件开发者犯的一个巨大错误&#xff0c;浪费了你大量时间。 专注于工具而非概念。忽视了大局。 React只是一个JavaScript工具。JavaScript只是一个计算工具。计算只是一个解决问题的工具。 当我刚开始编码时&a…

hugging face 使用教程———快速入门

概述 本篇存在的意义是快速介绍hugging face使用&#xff0c;梳理主要部件&#xff0c;梳理易混淆概念。原因是&#xff1a;目前hugging face的使用&#xff0c;官方放在了3个地方&#xff08;参考链接部分&#xff09;&#xff1a;使用文档、NLP教程、Transformers git的readm…

PDF转Word后不能修改怎么办?是什么原因呢?

平时在生活中&#xff0c;很多朋友都会有将PDF转换成Word文档的需求&#xff0c;因为一般情况下PDF文件是不能直接编辑修改的&#xff0c;所以只能通过这种方式来解决问题。但是近期&#xff0c;有部分用户在后台反馈说PDF转Word后不能修改怎么办呢&#xff1f;其实这个问题也是…

前端页面:用户交互持续时间跟踪(duration)user-interaction-tracker

引言 在用户至上的时代&#xff0c;精准把握用户行为已成为产品优化的关键。本文将详细介绍 user-interaction-tracker 库&#xff0c;它提供了一种高效的解决方案&#xff0c;用于跟踪用户交互的持续时间&#xff0c;并提升项目埋点的效率。通过本文&#xff0c;你将了解到如…

云仓如何改变传统仓储模式?

云仓&#xff0c;即云仓储&#xff0c;是一种基于互联网技术的现代仓储模式&#xff0c;与传统的仓储模式相比&#xff0c;它在多个方面进行了创新和优化&#xff0c;包括&#xff1a; ———————————————————— 1、数据管理与实时监控&#xff1a; 云仓储利…

每日一题 LeetCode03 无重复字符的最长字串

1.题目描述 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长字串的长度。 2 思路 可以用两个指针, 滑动窗口的思想来做这道题,即定义两个指针.一个left和一个right 并且用一个set容器,一个length , 一个maxlength来记录, 让right往右走,并且用一个set容器来…

【数据结构】链表(单链表实现 + 详解 + 原码)

&#x1f387;&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了 博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳&#xff0c;欢迎大佬指点&#xff01; 人生格言: 当你的才华撑不起你的野心的时候,你就应该静下心来学习! 欢迎志同道合的朋友…