Qt QSqlTableModel详解

背景知识:

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 QSqlWidgetForm::on_pushButton_openDB_clicked()
{
    QString strFilter = "access数据库(*.mdb);;SQL Lite数据库(*.db *.db3)";
    QString strDBname = QFileDialog::getOpenFileName(this,"选择数据库文件","", strFilter);
    if (strDBname.isEmpty())
        return;
    if(QSqlDatabase::contains("MyAccessDB"))
    {
        QSqlDatabase::removeDatabase("MyAccessDB");
    }
    QString strName;
    if(strDBname.right(3) == "mdb")
    {
        m_db = QSqlDatabase::addDatabase("QODBC", "MyAccessDB");
        strName = QString("DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};FIL={MS Access};DBQ=%1").arg(strDBname);
    }
    else if(strDBname.right(3) == "db3" ||strDBname.right(2) == "db" )
    {
        m_db = QSqlDatabase::addDatabase("QSQLITE");
        strName = strDBname;
    }
    m_db.setDatabaseName(strName);
    if (!m_db.isOpen())
    {
        if (!m_db.open())
        {
            qDebug() << m_db.lastError().text();
            return ;
        }
    }
    QStringList  tablelist  = m_db.tables();
    ui->comboBox_table->clear();
    ui->comboBox_table->addItems(tablelist);
    ui->comboBox_table->setCurrentIndex(0);
    m_pTableModel = new QSqlTableModel(this,m_db);//设置数据库
}

打开数据表、设置表头、选择模型、数据映射、信号槽

void QSqlWidgetForm::on_pushButton_openTable_clicked()
{
    QString strTableName = ui->comboBox_table->currentText();
    m_pTableModel->clear();
    m_pTableModel->setTable(strTableName); //设置数据表
    m_pTableModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//编辑策略
    m_pTableModel->setSort(m_pTableModel->fieldIndex("id"),Qt::AscendingOrder); //增序排序

    if (!(m_pTableModel->select()))//查询数据
    {
        return ;
    }

    m_pTableModel->setHeaderData(m_pTableModel->fieldIndex("id"),Qt::Horizontal,"工号");
    m_pTableModel->setHeaderData(m_pTableModel->fieldIndex("name"),Qt::Horizontal,"姓名");
    m_pTableModel->setHeaderData(m_pTableModel->fieldIndex("sex"),Qt::Horizontal,"性别");

    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);

    ui->tableView->setModel(m_pTableModel);//设置数据模型
    theSelection = new QItemSelectionModel(m_pTableModel);//关联选择模型
    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)));

    QStringList strList;
    strList<<"男"<<"女";
    bool isEditable=false;
    delegateSex.setItems(strList,isEditable);
    ui->tableView->setItemDelegateForColumn(m_pTableModel->fieldIndex("sex"),&delegateSex);

    ui->pushButton_saveData->setEnabled(false); //有未保存修改时可用
    ui->pushButton_CancleSave->setEnabled(false);

    //创建界面组件与数据模型的字段之间的数据映射
    dataMapper= new QDataWidgetMapper();
    dataMapper->setModel(m_pTableModel);//设置数据模型
    dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);
    dataMapper->addMapping(ui->lineEdit_ID,m_pTableModel->fieldIndex("id"));
    dataMapper->addMapping(ui->lineEdit_Name,m_pTableModel->fieldIndex("name"));
    dataMapper->addMapping(ui->lineEdit_sex,m_pTableModel->fieldIndex("sex"));
}

添加表操作

void QSqlWidgetForm::on_pushButton_AddTable_clicked()
{
     QSqlQuery query = QSqlQuery(m_db);
     query.clear();
     QString strTablename = ui->lineEdit_TableName->text();
     QString strquery =QString("CREATE TABLE %1 ( id VARCHAR(8) PRIMARY KEY, name VARCHAR(20),sex VARCHAR(4) )").arg(strTablename);
     bool ret = query.exec(strquery);
     query.clear();
     if(!ret)
     {
        qDebug() << "创建表失败:" <<  query.lastError().text();
        return;
     }
     ui->comboBox_table->addItem(strTablename);
     ui->comboBox_table->setCurrentText(strTablename);
}

 删除表

void QSqlWidgetForm::on_pushButton_DeleteTable_clicked()
{
     QSqlQuery query = QSqlQuery(m_db);
     QString strTablename = ui->comboBox_table->currentText();
     query.clear();
     bool ret = false;
     QString strquery = QString("drop table %1").arg(strTablename);
     ret = query.prepare(strquery);
     ret = query.exec();
     query.clear();



     if(!ret)
     {
        qDebug() << "删除表失败:" << query.lastError().text();
        return;
     }
     int nIndex = ui->comboBox_table->findText(strTablename);
     ui->comboBox_table->removeItem(nIndex);
     ui->comboBox_table->setCurrentText(0);
     m_pTableModel->clear();

}

插入数据

void QSqlWidgetForm::on_pushButton_AddData_clicked()
{
    int row = m_pTableModel->rowCount();
     bool ret = m_pTableModel->insertRow(row,QModelIndex()); //在末尾添加一个记录
     if(!ret)
     {
        qDebug() << "插入数据行失败";
        return;
     }
    ret = m_pTableModel->setData(m_pTableModel->index(m_pTableModel->rowCount()-1,0),m_pTableModel->rowCount()); //自动生成编号
    m_pTableModel->setData(m_pTableModel->index(m_pTableModel->rowCount()-1,1),"秦汉");
    m_pTableModel->setData(m_pTableModel->index(m_pTableModel->rowCount()-1,2),"男");
     if(!ret)
     {
        qDebug() << "插入数据设置数据失败";
     }
}

删除数据

void QSqlWidgetForm::on_pushButton_DeleteData_clicked()
{
    bool ret = m_pTableModel->removeRow(m_pTableModel->rowCount()-1); //删除最后一行
     if(!ret)
     {
        qDebug() << "删除数据失败";
        return;
     }
}

保存修改

void QSqlWidgetForm::on_pushButton_saveData_clicked()
{
    bool res = m_pTableModel->submitAll();
     ui->pushButton_saveData->setEnabled(false); //有未保存修改时可用
     ui->pushButton_CancleSave->setEnabled(false);
}

取消修改

void QSqlWidgetForm::on_pushButton_CancleSave_clicked()
{
    m_pTableModel->revertAll();
     ui->pushButton_saveData->setEnabled(false); //有未保存修改时可用
     ui->pushButton_CancleSave->setEnabled(false);
}

排序


void QSqlWidgetForm::on_pushButton_sort_clicked()
{
    m_pTableModel->setSort(0,m_bSort == true ? Qt::AscendingOrder : Qt::DescendingOrder);
    m_pTableModel->select();
    m_bSort = !m_bSort;
}

过滤

void QSqlWidgetForm::on_pushButton_Filter_clicked()
{
    QString strsex = ui->lineEdit_sex->text();
    QString strtable = ui->comboBox_table->currentText();
//    QString strFilter = QString("sex='%1' ").arg(strsex);
//    m_pTableModel->setFilter(strFilter);
    QString strQuery =QString("select * from %1 where sex='%2'").arg(strtable).arg(strsex);
    m_pTableModel->QSqlQueryModel::setQuery(strQuery,m_db);
}

或者是直接调用QSqlQueryModel的setQuery函数,这样视图就会按实际查询的字段显示

关闭数据库

void QSqlWidgetForm::on_pushButton_closeDB_clicked()
{
    if (m_db.isOpen())
    {
        m_db.close();
    }
}

其他

void QSqlWidgetForm::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{
    Q_UNUSED(current);
    Q_UNUSED(previous);
    bool b = m_pTableModel->isDirty();
    ui->pushButton_saveData->setEnabled(b); //有未保存修改时可用
    ui->pushButton_CancleSave->setEnabled(b);
}

void QSqlWidgetForm::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{
    Q_UNUSED(current);
    Q_UNUSED(previous);
    bool b = m_pTableModel->isDirty();
    ui->pushButton_saveData->setEnabled(b); //有未保存修改时可用
    ui->pushButton_CancleSave->setEnabled(b);
    dataMapper->setCurrentIndex(current.row()); //更细数据映射的行号
}

  • 3
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值