使用自定义 QSortFilterProxyModel 在 QTreeView 上错误的 QModelIndex
Wrong QModelIndex on QTreeView using custom QSortFilterProxyModel
我有一个基于 QStandardItemModel
的 QTreeView
,其中充满了子类 QStandardItem
。 Item-sublcass 只多了两个数据指针,不会以任何其他方式影响项目,因此 PTSModelItem
的行为类似于 QStandardItem
。
我通过子类化 filterAcceptsRow()
使用自定义 QSortFilterProxyModel
以启用对自定义数据指针的过滤。
treeView
显示正确,直到我启用过滤器。然后 List 元素永远不会被过滤掉,子元素在列表中完全缺失(不是子匹配项)或完全显示(至少一个子匹配项)。
我遇到的问题,filterAcceptsRow()
中生成的索引始终是列表元素(rootItem
的子元素),即使 source_row 增加。
参数值为 filterAcceptsRow(int source_row, QModelIndex source_parent)
的模型:
RootItem (invisible)
|-List1
| |-Child1
| |-Child2
| |-Child3
|-List2
| |-Child1
| |-Child4
问题是,独立于源行,调用
QModelIndex itemIndex = sourceModel()->index(source_row,i,source_parent);
if(!itemIndex.isValid())
continue;
PTSModelItem* item = static_cast<PTSModelItem*>(itemIndex.internalPointer());
返回的项总是 List1
或 List2
,即使 source_row 为 0,1,2。
填充模型(listitem 仅包含文本和 QList
of "childText"
:
QStandardItemModel *model = new QStandardItemModel();
QStandardItem *rootItem = model->invisibleRootItem();
foreach(PTSItem* listItem, modelItemList)
{
PTSModelItem *item = new PTSModelItem(tr("List: %1").arg(listItem->getListNumber()),listItem,0,PTSModelItem::ITEM_TYPE_LISTNUMBER);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->appendRow(item);
PTSModelItem *identTitle = new PTSModelItem("",listItem,0,PTSModelItem::ITEM_TYPE_IDENTEMPTY);
identTitle->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),1,identTitle);
PTSModelItem *readDateItem = new PTSModelItem(tDateString,listItem,0,PTSModelItem::ITEM_TYPE_CREATED);
readDateItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),2,readDateItem);
PTSModelItem *writeDateItem = new PTSModelItem(tDateString,listItem,0,PTSModelItem::ITEM_TYPE_LASTSET);
writeDateItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),3,writeDateItem);
for(int i=0; i<listItem->size();i++)
{
QList<QStandardItem*> childItems;
PTSModelItem *toolItem = new PTSModelItem(tr("T%1").arg(listItem->getToolNumber(i)),listItem,i,PTSModelItem::ITEM_TYPE_TOOLNUMBER);
toolItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(toolItem);
PTSModelItem *identItem = new PTSModelItem(listItem->getIdentNumber(i),listItem,i,PTSModelItem::ITEM_TYPE_IDENTNUMBER);
identItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(identItem);
PTSModelItem *readDate = new PTSModelItem("",listItem,i,PTSModelItem::ITEM_TYPE_CREATEDVALID);
readDate->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(readDate);
PTSModelItem *writeDate = new PTSModelItem("",listItem,i,PTSModelItem::ITEM_TYPE_LASTSETVALID);
writeDate->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(writeDate);
item->appendRow(childItems);
}
}
过滤器实现:
bool PTSFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex itemIndex = sourceModel()->index(source_row,0,source_parent);
if(!itemIndex.isValid())
return false;
PTSModelItem* item = static_cast<PTSModelItem*>(itemIndex.internalPointer());
QString text = item->text(); // THIS always return ListN
if(item->type() == QStandardItem::Type)
{
if(item == static_cast<QStandardItemModel*>(sourceModel())->invisibleRootItem())
return true;
}
//Custom filtering starts here but breaks, since item is always only the List-element
}
QStandardItemModel 要求您不使用 internalPointer()
方法,而是
QStandardItemModel::itemFromIndex()
因此,通过将 filterAcceptsRow 中的项目检索更改为:
解决了问题
PTSModelItem* item = static_cast<PTSModelItem*>(static_cast<QStandardItemModel*>(sourceModel())->itemFromIndex(usedIndex));
答案是mapToSource。
QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const
用法示例:
QModelIndex realIndex = mapToSource(index);
我有一个基于 QStandardItemModel
的 QTreeView
,其中充满了子类 QStandardItem
。 Item-sublcass 只多了两个数据指针,不会以任何其他方式影响项目,因此 PTSModelItem
的行为类似于 QStandardItem
。
我通过子类化 filterAcceptsRow()
使用自定义 QSortFilterProxyModel
以启用对自定义数据指针的过滤。
treeView
显示正确,直到我启用过滤器。然后 List 元素永远不会被过滤掉,子元素在列表中完全缺失(不是子匹配项)或完全显示(至少一个子匹配项)。
我遇到的问题,filterAcceptsRow()
中生成的索引始终是列表元素(rootItem
的子元素),即使 source_row 增加。
参数值为 filterAcceptsRow(int source_row, QModelIndex source_parent)
的模型:
RootItem (invisible)
|-List1
| |-Child1
| |-Child2
| |-Child3
|-List2
| |-Child1
| |-Child4
问题是,独立于源行,调用
QModelIndex itemIndex = sourceModel()->index(source_row,i,source_parent);
if(!itemIndex.isValid())
continue;
PTSModelItem* item = static_cast<PTSModelItem*>(itemIndex.internalPointer());
返回的项总是 List1
或 List2
,即使 source_row 为 0,1,2。
填充模型(listitem 仅包含文本和 QList
of "childText"
:
QStandardItemModel *model = new QStandardItemModel();
QStandardItem *rootItem = model->invisibleRootItem();
foreach(PTSItem* listItem, modelItemList)
{
PTSModelItem *item = new PTSModelItem(tr("List: %1").arg(listItem->getListNumber()),listItem,0,PTSModelItem::ITEM_TYPE_LISTNUMBER);
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->appendRow(item);
PTSModelItem *identTitle = new PTSModelItem("",listItem,0,PTSModelItem::ITEM_TYPE_IDENTEMPTY);
identTitle->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),1,identTitle);
PTSModelItem *readDateItem = new PTSModelItem(tDateString,listItem,0,PTSModelItem::ITEM_TYPE_CREATED);
readDateItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),2,readDateItem);
PTSModelItem *writeDateItem = new PTSModelItem(tDateString,listItem,0,PTSModelItem::ITEM_TYPE_LASTSET);
writeDateItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
rootItem->setChild(item->row(),3,writeDateItem);
for(int i=0; i<listItem->size();i++)
{
QList<QStandardItem*> childItems;
PTSModelItem *toolItem = new PTSModelItem(tr("T%1").arg(listItem->getToolNumber(i)),listItem,i,PTSModelItem::ITEM_TYPE_TOOLNUMBER);
toolItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(toolItem);
PTSModelItem *identItem = new PTSModelItem(listItem->getIdentNumber(i),listItem,i,PTSModelItem::ITEM_TYPE_IDENTNUMBER);
identItem->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(identItem);
PTSModelItem *readDate = new PTSModelItem("",listItem,i,PTSModelItem::ITEM_TYPE_CREATEDVALID);
readDate->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(readDate);
PTSModelItem *writeDate = new PTSModelItem("",listItem,i,PTSModelItem::ITEM_TYPE_LASTSETVALID);
writeDate->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
childItems.append(writeDate);
item->appendRow(childItems);
}
}
过滤器实现:
bool PTSFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
QModelIndex itemIndex = sourceModel()->index(source_row,0,source_parent);
if(!itemIndex.isValid())
return false;
PTSModelItem* item = static_cast<PTSModelItem*>(itemIndex.internalPointer());
QString text = item->text(); // THIS always return ListN
if(item->type() == QStandardItem::Type)
{
if(item == static_cast<QStandardItemModel*>(sourceModel())->invisibleRootItem())
return true;
}
//Custom filtering starts here but breaks, since item is always only the List-element
}
QStandardItemModel 要求您不使用 internalPointer()
方法,而是
QStandardItemModel::itemFromIndex()
因此,通过将 filterAcceptsRow 中的项目检索更改为:
解决了问题PTSModelItem* item = static_cast<PTSModelItem*>(static_cast<QStandardItemModel*>(sourceModel())->itemFromIndex(usedIndex));
答案是mapToSource。
QModelIndex QSortFilterProxyModel::mapToSource(const QModelIndex &proxyIndex) const
用法示例:
QModelIndex realIndex = mapToSource(index);