描述
QSqlRelationalDelegate类
提供了一个委托,用于显示和编辑来自QSqlRelationalTableModel
的数据。
与默认委托不同,QSqlRelationalDelegate
为作为其他表的外键的字段提供了一个组合框。
要使用该类,只需在带有QSqlRelationalDelegate
实例的视图上调用QAbstractItemView::setItemDelegate()
;
Ex:
cpp
QSqlRelationalTableModel* pModel = new QSqlRelationalTableModel();
pModel->setTable("person");
pModel->setRelation(2, QSqlRelation("items", "id", "itemtype"));
ui->tableView->setModel(pModel);
ui->tableView->setItemDelegate(new QSqlRelationalDelegate());
pModel->select();
关系表模型示例(如下所示)演示了如何将QSqlRelationalDelegate
与QSqlRelationalTableModel
结合使用,为表提供外键支持。
重写
有两个重写方法:
QWidget *QSqlRelationalDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
void QSqlRelationalDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
createEditor
cpp
QWidget *createEditor(QWidget *aParent,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
const QSqlRelationalTableModel *sqlModel = qobject_cast<const QSqlRelationalTableModel *>(index.model());
QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0;
if (!childModel)
return QItemDelegate::createEditor(aParent, option, index);
QComboBox *combo = new QComboBox(aParent);
combo->setModel(childModel);
combo->setModelColumn(childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn()));
combo->installEventFilter(const_cast<QSqlRelationalDelegate *>(this));
return combo;
}
- 上述代码实现了自定义委托的
createEditor
函数,用于创建一个QComboBox
作为单元格的编辑器 - 通过
index.model()
获取主数据模型,并将其qobject_cast
转换为QSqlRelationalTableModel
类型(如果成功转换,则说明该数据模型具有关联模型) - 使用
sqlModel->relationModel(index.column())
获取与该列关联的子数据模型。如果该列没有关联模型,它将返回0
,这意味着将使用默认的委托(QItemDelegate
)来创建单元格编辑器。
如果存在关联模型,则创建一个QComboBox
,并将其设置为该列的单元格编辑器。
- 子模型是通过
combo->setModel(childModel)
设置的,其中childModel
是通过sqlModel->relationModel(index.column())
获取的 - 使用
sqlModel->relation(index.column()).displayColumn()
获取子模型中用于显示选择项的列,并将其设置为QComboBox
的模型列,即combo->setModelColumn
- 为
ComboBox
安装一个事件过滤器,使得在编辑完成后能够正确更新主数据模型 - 最后,返回ComboBox作为单元格编辑器。
setModelData
cpp
void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
if (!index.isValid())
return;
QSqlRelationalTableModel *sqlModel = qobject_cast<QSqlRelationalTableModel *>(model);
QSqlTableModel *childModel = sqlModel ? sqlModel->relationModel(index.column()) : 0;
QComboBox *combo = qobject_cast<QComboBox *>(editor);
if (!sqlModel || !childModel || !combo) {
QItemDelegate::setModelData(editor, model, index);
return;
}
int currentItem = combo->currentIndex();
int childColIndex = childModel->fieldIndex(sqlModel->relation(index.column()).displayColumn());
int childEditIndex = childModel->fieldIndex(sqlModel->relation(index.column()).indexColumn());
sqlModel->setData(index,
childModel->data(childModel->index(currentItem, childColIndex), Qt::DisplayRole),
Qt::DisplayRole);
sqlModel->setData(index,
childModel->data(childModel->index(currentItem, childEditIndex), Qt::EditRole),
Qt::EditRole);
}
- 上述代码实现了自定义委托的
setModelData
函数,用于将编辑器中的数据更新到主数据模型中 - 首先,检查
index
是否有效,如果无效,则直接返回 - 通过
qobject_cast
将数据模型转换为QSqlRelationalTableModel
类型,并使用index.column()
获取正在编辑的列的索引 - 通过
sqlModel->relationModel(index.column())
获取与该列关联的子数据模型,如果该列没有关联模型,则将其设置为0 - 通过
qobject_cast
将编辑器转换为QComboBox
类型,并检查它们是否存在。如果不存在,则说明该列没有关联子模型或者使用默认委托编辑器,就调用默认委托的setModelData
函数来更新数据模型,然后返回。
如果存在关联子模型和ComboBox
编辑器,它就使用combo->currentIndex()
获取当前ComboBox
选中项的索引,使用sqlModel->setData
将选中项的值设置到主数据模型的index
位置。这里使用了两次sqlModel->setData
,分别将选中项的"显示值"和"编辑值"设置到主数据模型中,其中"显示值"是通过sqlModel->relation(index.column()).displayColumn()
获取的子模型中的列数据,而"编辑值"是通过sqlModel->relation(index.column()).indexColumn()
获取的子模型中指定的列数据
- 最后,完成了所有数据更新操作
注意
如果需要下拉框功能,就直接用就行。
先进行自定义信号发送,则需要子类化操作。
结论
记住,你是最好的!如果有人比你好,那就假装没看见他们
。