由下图可以看到QSqlRelationalTableModel是QSqlTableModel的子类,QSqlRelationalTableModel可以处理关系数据表,所谓关系数据表,是指将主表里的某些字段存储为代码行变量,而代码的具体意义在另一个数据表里。
表 11-5 给出了 studInfo 的字段定义,studInfo 数据表实际存储的数据示例见表 11-12,字段departID和 majorID存储的是学院代码和专业代码。
学院代码字段 departID 的具体意义在数据表 departments 里定义,departments 表的字段结构见数据库文件,departments 表的示例数据见表11-13。
同样,专业数据表 majors 定义了专业代码及其专业名称,majors 表的字段结构见数据库文件,majors表的示例数据见表 11-14。majors 数据表不仅定义了专业代码的意义,还使用了学院代码字段departID,与departments 数据表发生关联。
在数据库设计中使用代码字段和代码表的好处:
QSqlRelationalTableModel 类专门用来编辑这种具有代码字段的数据表,可以很方便地将代码字段与关系数据表建立关系,在显示和编辑数据表时,直接使用关系数据表的代码意义字段的内容。实例 samp11_4演示关系型数据表使用的方法,图 11-8 是程序运行界面。
实例 samp11_4使用QSqlRelationalTableModel 作为 tableView 的数据源,显示和编辑 studInfo数据表。学院和专业两个字段与代码表建立了关系,tableView 中直接显示这两个字段的文字内容,编辑时有一个下拉列表框,列表框里是代码表里全部代码意义文字。
主窗口类定义如下,定义了一个QSqIRelationalTableModel 类型的变量 tabModel 作为数据模型。
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
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 ¤t, const QModelIndex &previous);
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
主窗口工具栏的“打开”按钮选择数据库文件 demodb.db3,然后调用 openTable()打开数据表,openTable()函数的代码如下:
void MainWindow::openTable()
{//打开数据表
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"));//专业
theSelection=new QItemSelectionModel(tabModel);
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),
this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
ui->tableView->setModel(tabModel);
ui->tableView->setSelectionModel(theSelection);
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件
tabModel->select(); //打开数据表
ui->actOpenDB->setEnabled(false);
ui->actRecAppend->setEnabled(true);
ui->actRecInsert->setEnabled(true);
ui->actRecDelete->setEnabled(true);
ui->actFields->setEnabled(true);
}
QSqlRelationalTableModel 类的主要函数与 QSqlTableModel 相同,有一个新的函数 setRelation()用于设置代码字段的关联数据表和关联字段。setRelation()函数的定义如下:
void QSqlRelationalTableModel::setRelation(int *column*, const [QSqlRelation](qsqlrelation.html) &*relation*)
其中 column 是主表中代码字段的序号,relation 是 QSqlRelation 类型的表示关联数据表的关系。设置代码字段 departID 的关系的代码如下:
//设置代码字段的查询关系数据表
tabModel->setRelation(3,QSqlRelation("departments","departID","department")); //学院
第1个参数(数字3)是 departID 字段在 studInfo 表中的字段序号。
第2个参数用QSqlRelation(“departments”,“departID”,“department”)创建了一个QSqlRelation类型对象,其中,参数"departments"是代码表 departments,参数"departID"是代码字段名称,参数”department"是代码意义字段名称。
openTable()函数中还有关键的一行:
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(ui->tableView)); //为关系型字段设置缺省代理组件
这是在 tableView 中为代码字段创建缺省的关系型代理组件,这样在 tableView 中编辑代码字段的内容时,才会出现一个下拉列表框,列出代码表的所有可选内容。
使用 QSqlRelationalTableModel 类设置代码字段的关系后,在 tableView 中以代码意义显示代码字段的内容,其实际字段有没有变化呢?
工具栏上的按钮“字段列表”列出了 tabModel 的所有字段的名称,其代码如下:
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);
}
代码运行后的对话框如下图所示,可以看到两个代码字段departID和majorID被代码表中的代码意义字段department和major替换,但是在界面上修改参数后,数据能以代码的形式保存到原数据中。
工具栏上其他“添加”“插入”“删除”“保存”“取消”等按钮的功能的实现与实例samp11_1相同,自定义槽函数on_currentChanged()的实现也与 samp11_1相同,这些功能的实现就不具体介绍了