描述
QSqlRelationalDelegate
链接: https://blog.csdn.net/MrHHHHHH/article/details/134690139
QSqlRelationalTableModel
类为单个数据库表提供了一个可编辑的数据模型,并支持外键。
QSqlRelationalTableModel
的行为类似于QSqlTableModel
,但允许将列设置为其他数据库表的外键。
左边的屏幕截图显示了QTableView
中一个普通的QSqlTableModel
。外键(城市和国家)不能解析为人类可读的值。
右边的屏幕截图显示了一个QSqlRelationalTableModel
,外键被解析为人类可读的文本字符串。
下面的代码片段展示了如何建立QSqlRelationalTableModel
:
model->setTable("employee");
model->setRelation(2, QSqlRelation("city", "id", "name"));
model->setRelation(3, QSqlRelation("country", "id", "name"));
setRelation()
函数调用在两个表之间建立关系。第一个调用指定表employee
中的第2列是一个外键,它映射表city的字段id,并且视图应该向用户显示城市的名称字段。第二个调用对列3执行类似的操作。
如果使用读写的QSqlRelationalTableModel
,可能希望在视图上使用QSqlRelationalDelegate
。与默认委托不同,QSqlRelationalDelegate
为作为其他表的外键的字段提供了一个组合框。要使用该类,只需在带有QSqlRelationalDelegate
实例的视图上调用QAbstractItemView::setItemDelegate()
:
QTableView *view = new QTableView;
view->setModel(model);
view->setItemDelegate(new QSqlRelationalDelegate(view));
relationaltablemodel
示例演示了如何将QSqlRelationalTableModel
与QSqlRelationalDelegate
结合使用,为表提供外键支持。
注意:
- 表必须声明主键。
- 表的主键可能不包含对另一个表的关系。
- 如果关系表包含引用引用表中不存在的行的键,则包含无效键的行将不通过模型公开。用户或数据库有责任维护引用完整性。
- 如果关系的显示列名称也用作关系表中的列名称,或者如果它在多个关系中用作显示列名称,则会被别名。别名是关系的表名、显示列名和一个唯一的id,用下划线连接(例如
tablename_columnname_id
)。QSqlRecord::fieldName()将
返回别名列名。当检测到重复时,所有重复显示列名的出现都会被别名,但不会对主表中的列名进行任何别名操作。别名对QSqlRelation
没有影响,因此QSqlRelation::displayColumn()
将返回原始显示列名。 - 参考表名称被别名。别名是单词"relTblAl"和关联的列索引用下划线连接(例如,
relTblAl_2
)。别名可用于过滤表(例如,setFilter("relTblAl_2='Oslo' OR relTblAl_3='USA'")
)。 - 使用
setData()
时,角色应始终为Qt::EditRole
,使用data()
时,角色应始终为Qt::DisplayRole
。
常用方法
- 枚举:
enum JoinMode
常量 | 值 | 描述 | 解释 |
---|---|---|---|
QSqlRelationalTableModel::InnerJoin | 0 | - Inner join mode, return rows when there is at least one match in both tables. | — 内部连接模式,当两个表中至少有一个匹配时返回行。 |
QSqlRelationalTableModel::InnerJoin | 1 | - Left join mode, returns all rows from the left table (table_name1), even if there are no matches in the right table (table_name2). | — 左连接模式,返回左表(table_name1)中的所有行,即使右表(table_name2)中没有匹配。 |
void setJoinMode(QSqlRelationalTableModel::JoinMode joinMode)
设置SQL joinMode
以显示或隐藏外键为NULL
的行。在InnerJoin
模式(默认)中,这些行将不会显示:如果想显示它们,请使用LeftJoin
模式。
QSqlRelation relation(int column) const
返回列的关系,如果没有设置关系,则返回无效关系。
QSqlTableModel* relationModel(int column) const
返回一个QSqlTableModel
对象,用于访问列为外键的表,如果给定列没有关系,则返回0。
返回的对象归QSqlRelationalTableModel
所有。
void setRelation(int column, const QSqlRelation &relation)
让指定的列是由关系指定的外索引。
Ex:
model->setTable("employee");
model->setRelation(2, QSqlRelation("city", "id", "name"));
setRelation()
调用指定employee
表中的第2列是一个外键,它映射表city
的字段id
,并且视图应该向用户显示城市的名称字段。
注意:表的主键不能包含与另一个表的关系。
void clear()
重新实现QSqlQueryModel::clear()
方法。用于清除模型数据。
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const
为索引引用的项返回存储在给定角色下的数据。
注意:如果没有要返回的值,则返回无效的QVariant,而不是返回
0`。
bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
在支持此功能的模型上,从模型中删除从parent
下给定列开始的计数列。
如果列已成功删除,则返回true;否则返回false。
基类实现不做任何事情并返回false。
如果实现了自己的模型,如果希望支持删除,则可以重新实现此函数。或者,可以提供自己的API来修改数据。
bool select()
使用通过setTable()
设置的表中的数据填充模型,使用指定的筛选和排序条件,如果成功则返回true;否则返回false。
注意:调用select()
将恢复所有未提交的更改并删除所有插入的列。
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
从QAbstractItemModel::setData()
重新实现。
将具有指定索引的项中角色的数据设置为给定的值。根据编辑策略的不同,值可以立即应用于数据库,也可以缓存在模型中。
如果值可以设置,则返回true,如果出现错误(例如,如果索引超出边界)则返回false。
对于关系列,value必须是索引,而不是显示值。索引也必须存在于被引用的表中,否则函数返回false。
示例
在.pro
中添加QT += sql
;
包含头文件
#include <QtWidgets>
#include <QtSql>
#include <QMessageBox>
#include <QSqlDatabase>
#include <QSqlError>
#include <QSqlQuery>
- // 创建表及插入数据
static bool createConnection()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
// 创建在内存中
db.setDatabaseName(":memory:");
if (!db.open()) {
QMessageBox::critical(0, qApp->tr("Cannot open database"),
qApp->tr("Unable to establish a database connection.\n"
"This example needs SQLite support. Please read "
"the Qt SQL driver documentation for information how "
"to build it.\n\n"
"Click Cancel to exit."), QMessageBox::Cancel);
return false;
}
// 使用SqlQuery进行表创建及数据添加
QSqlQuery query;
query.exec("create table person (id int primary key, "
"firstname text, lastname int)");
query.exec("insert into person values(0, '0', 0)");
query.exec("insert into person values(1, '1', 1)");
query.exec("insert into person values(4, '2', 2)");
query.exec("insert into person values(3, '3', 3)");
query.exec("create table itemF (id int primary key,"
"firstName varchar(20))");
query.exec("insert into itemF "
"values(0, '小明')");
query.exec("insert into itemF "
"values(2, '小华')");
query.exec("insert into itemF "
"values(3, '小芳')");
query.exec("insert into itemF "
"values(1, '小诸葛')");
query.exec("create table itemL (id int, lastName varchar(20))");
query.exec("insert into itemL values(0, '赵')");
query.exec("insert into itemL values(1, '钱')");
query.exec("insert into itemL values(2, '孙')");
query.exec("insert into itemL values(3, '李')");
return true;
}
- // 初始化模型
void initializeModel(QSqlRelationalTableModel *model)
{
// 设置表名
model->setTable("person");
// 手动提交
model->setEditStrategy(QSqlTableModel::OnManualSubmit);
// 设置外键
model->setRelation(1, QSqlRelation("itemF", "id", "firstName"));
model->setRelation(2, QSqlRelation("itemL", "id", "lastName"));
// 添加表头
model->setHeaderData(0, Qt::Horizontal, QObject::tr("id"));
model->setHeaderData(1, Qt::Horizontal, QObject::tr("firstName"));
model->setHeaderData(2, Qt::Horizontal, QObject::tr("lastName"));
// 刷新
model->select();
}
上述代码:
- 创建了一个名为
person
的表,并添加了一些数据。 - 创建了两个名为
itemF
和itemL
的表,并添加了一些具有id
和firstName
或lastName
属性的数据 - 这些表和数据将用于后面的
QSqlRelationalTableModel
示例 - 最后,该函数返回
true
。
- // 创建视图
QTableView *createView(const QString &title, QSqlTableModel *model)
{
QTableView *view = new QTableView;
// 设置模型
view->setModel(model);
// 设置委托,这样可以下拉框显示
view->setItemDelegate(new QSqlRelationalDelegate(view));
view->setWindowTitle(title);
return view;
}
上述代码:
- 定义了一个名为
createView
的函数,函数用于创建一个新的QTableView
。 - 函数使用一个标题和一个
QSqlTableModel
对象作为参数,并使用传入的QSqlTableModel
对象设置view
的模型。 - 使用
QSqlRelationalDelegate
设置view
的委托,以便在需要显示下拉列表时使用。 - 最后,函数设置
view
的窗口标题,并将view
返回给调用者。
- // 调用
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
if (!createConnection())
return 1;
QSqlRelationalTableModel model;
initializeModel(&model);
QTableView *view = createView(QObject::tr("Relational Table Model"), &model);
view->show();
return app.exec();
}
结果
注意
- 表必须声明主键
- 使用
setRelation()
方法时,关联的表和外键需存在,不然,错误的行不会加载到模型中,不会在视图中显示 - 使用
setItemDelegate(new QSqlRelationalDelegate(view))
时,可以将单元格以下拉框方式显示
结论
重剑无锋,大巧不工
。