我正在尝试创建一个代理模型,该模型动态地映射来自源模型.的项。
在实现QIdentityProxyModel之后,我发现实际上不可能通过检查4个核心功能来复制它:
mapFromSource()
mapToSource()
index()
parent()考虑一下基于QIdentityProxyModel的这一点
mapFromSource()
QModelIndex ProxyModel::mapFromSource(const QModelIndex &sourceIndex) const
{
if(sourceIndex.isValid())
return createIndex(sourceIndex.row(), sourceIndex.column(), sourceIndex.internalPointer());
else
return QModelIndex();
}mapToSource()
QModelIndex ProxyModel::mapToSource(const QModelIndex &proxyIndex) const
{
if(proxyIndex.isValid())
return sourceModel()->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());
else
return QModelIndex();
}索引()
QModelIndex ProxyModel::index(int row, int column, const QModelIndex &parent) const
{
const QModelIndex sourceParent = mapToSource(parent);
const QModelIndex sourceIndex = sourceModel()->index(row, column, sourceParent);
return mapFromSource(sourceIndex);
}家长()
QModelIndex ProxyModel::parent(const QModelIndex &index) const
{
const QModelIndex sourceIndex = mapToSource(index);
const QModelIndex sourceParent = sourceIndex.parent();
return mapFromSource(sourceParent);
}THE ISSUE
问题在mapToSource()线上
return sourceModel()->createIndex(proxyIndex.row(), proxyIndex.column(), proxyIndex.internalPointer());QAbstractItemModel::createIndex是受保护的函数,除非调用者声明为朋友,否则不能使用。如果不直接修改QAbstractItemModel类,这显然不是一个选项。唯一的选择是使用常规的QAbstractItemModel::index,但这需要以QModelIndex的形式作为参数之一。然而,这样做:
return sourceModel()->index(proxyIndex.row(), proxyIndex.column(), proxyIndex.parent());由于parent()函数依赖于mapToSource() 而导致无限循环,反之亦然,现在是。
显示举个例子的替代方法依赖于在上述函数中查询的QPersistentModelIndex对象的存储映射。这种办法虽然可行,但有几个缺点:
因此,我提出以下问题:
是否有另一种方法可以动态地处理分层代理模型,而不依赖于createIndex(),并且不遇到无限循环的函数调用?
实际上,是否有必要相对于源结构在存储中创建和维护代理模型的结构,还是有一种方法来创建动态代理模型?
谢谢!
发布于 2016-05-29 11:51:56
也许这是一个迟来的答复,但我只是面临同样的问题。我通过将sourceModel()转换到我的模型来解决这个问题,同时我宣布我的ProxyModel是我的朋友。
这是我的mapToSource定义:
QModelIndex ProxyModel::mapToSource(const QModelIndex& proxyIndex) const
{
Model* pModel = qobject_cast<Model*>(sourceModel());
if (!pModel || !proxyIndex.isValid()) return QModelIndex();
...
return pModel->createIndex(row, col, proxyIndex.internalPointer());
}朋友宣言:
class Model : public QAbstractTableModel
{
Q_OBJECT
friend class ProxyModel;
...
};我理解您对于只使用QAbstractItemModel接口的担忧(相信我,我也使用过),但是让我们面对它-- ProxyModel只能与我的Model一起使用,而不能用于其他任何东西(至少根据我的实现)。所以我看不出这样的“友谊”有什么不好的地方。至于UB,这里也不应该有任何问题,因为如果提供了除我的模型之外的其他模型,qobject_cast将返回0。
发布于 2016-10-28 09:07:39
在前面回答的基础上,我想添加一些替代的方法。
首先,时间历史上最丑陋的黑客在大多数编译中都是安全的:
class HackyDummy : public QAbstractItemModel
{
friend class ProxyModel;
};
QModelIndex ProxyModel::createSourceIndex(int r, int c, void *i) {
return ((HackyDummy*) sourceModel())->createIndex(r,c,i);
}现在,当然,这是一个可怕的,可怕的黑客。它也不会在某些编译器中编译,因为C++规范对于从子类朋友访问父类、私有和受保护的方法不太清楚(或者至少被一些人误解了)。这使我们找到了一个更好的计划。但首先,有一点细节: QIdentityProxyModel几乎做到了这一点。QIdentityModel自己的mapToSource/mapFromSource是公共的,可重新实现的,它的createIndex也是如此。因此,可以使用一种方法执行内部/私有QIdentityProxyModel,通过访问QIdentityProxyModel本身包含的哈克,从行、列和内部指针创建我们的小源索引。
编辑:打字
发布于 2017-01-30 00:15:24
我只是继承了QIdentityProxyModel,并在我的mapToSourceMethod中使用了它的mapToSource方法。
QModelIndex PropertyModel::mapToSource(const QModelIndex & proxyIndex) const
{
if(hasNoModel())
{
return QModelIndex();
}
QModelIndex remapped = createIndex( /* transform proxyIndex here */ );
return QIdentityProxyModel::mapToSource(remapped);
}这意味着,如果您更改源模型类型并忘记更新强制转换,则不会出现可能导致代码崩溃的强制转换。
https://stackoverflow.com/questions/23896182
复制相似问题