Bootstrap

Qt基础 | QSqIRelationalTableModel 的使用

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

一、QSqIRelationalTableModel 的使用

  QSqIRelationalTableModel 可以处理关系数据表。所谓关系数据表,是指将主表里的某个字段存储为代码型字段,而代码字段的具体含义是在另一个数据表(代码表)里。QSqIRelationalTableModel 类专门用来编辑这种具有代码字段的数据表,可以很方便地将代码字段与关系数据表建立关系,在显示和编辑数据表时,直接使用关系表的代码意义字典的内容

1.主窗口MainWindow类定义

#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; //数据库连接
    QSqlRelationalTableModel  *tabModel;//数据模型
    QItemSelectionModel *theSelection;//选择模型

    void    openTable();//打开数据表
//    void    getFieldNames();//获取字段名称
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_currentChanged(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_actFields_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

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

  • QSqlDatabase DB:用于加载数据库驱动和建立与数据库之间的连接
  • QSqlRelationalTableModel *tabModel:用于指定某个数据表,作为数据表的数据模型,用来编辑关系数据表
  • QItemSelectionModel *theSelection:作为 tabModel的选择模型

函数:

  • openTable

槽函数:

  • on_currentChanged

2.构造函数

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

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    this->setCentralWidget(ui->tableView);

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

3.打开数据表

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

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

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

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

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

3.2 创建数据模型及其属性设置、选择模型、设置代码字段的查询关系数据表、为关系型字段设置缺省代理组件

  使用 QSqIRelationalTableModel 作为指定数据表的数据模型,用于显示与编辑关系数据表,并设置数据模型的属性。

tabModel=new QSqlRelationalTableModel(this,DB);
tabModel->setTable("studInfo"); //设置数据表
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);  //OnManualSubmit , OnRowChange
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"));//专业

  为数据模型创建一个选择模型,当选中的项发生变化时,选择模型发出currentChanged信号,其关联槽函数用于设置 “保存”和“取消” Action是否可用。

theSelection=new QItemSelectionModel(tabModel);
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
        this,SLOT(on_currentChanged(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());
}

  为 tableView 设置数据模型与选择模型,为关系型字段设置缺省代理组件

ui->tableView->setModel(tabModel);
ui->tableView->setSelectionModel(theSelection);
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件

  查询数据,并设置一些 Action 的使能状态。

tabModel->select(); //打开数据表

ui->actOpenDB->setEnabled(false);
ui->actRecAppend->setEnabled(true);
ui->actRecInsert->setEnabled(true);
ui->actRecDelete->setEnabled(true);
ui->actFields->setEnabled(true);

4.实际字段代码表

  使用 QSqIRelationalTableModel 类设置代码字段的查询关系后,在 tableView 中以代码意义显示代码字段的内容,其实际字段也发生了改变,变成了关系表中的代码意义字段。

void MainWindow::on_actFields_triggered()
{//获取字段列表
    QSqlRecord  emptyRec=tabModel->record();//获取空记录,只有字段名
    QString  str;
    for (int i=0;i<emptyRec.count();i++)
        str=str+emptyRec.fieldName(i)+'\n';

    QMessageBox::information(this, "所有字段名", str,
                             QMessageBox::Ok,QMessageBox::NoButton);
}

5.其他功能–添加、插入、删除、保存、取消

5.1 添加

  添加功能是在数据表的末尾添加一行记录,并设置选择模型的索引来选中刚插入的这一行

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);//设置刚插入的行为当前选择行
}

5.2 插入

  插入功能是在当前选中行的上一行插入一行,并选中刚插入的这一行。

void MainWindow::on_actRecInsert_triggered()
{//插入记录
    QModelIndex curIndex=ui->tableView->currentIndex();
    tabModel->insertRow(curIndex.row(),QModelIndex());

    theSelection->clearSelection();//清除已有选择
    theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}

5.3 删除

  移除当前行并立即更新到数据库。

void MainWindow::on_actRecDelete_triggered()
{//删除当前记录
    tabModel->removeRow(theSelection->currentIndex().row());
    tabModel->submitAll(); //立即更新
}

5.4 保存

  保存功能即提交所有未更新的修改到数据库。

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

5.5 取消

  取消功能是取消所有未提交的修改。

void MainWindow::on_actRevert_triggered()
{//取消修改
    tabModel->revertAll();
    ui->actSubmit->setEnabled(false);
    ui->actRevert->setEnabled(false);
}
;