使用 QSortFilterItemProxy 保持结构
Keep structure using QSortFilterItemProxy
所以我使用了一个稍微自定义的 QSortFilterProxyModel
(刚刚实现了 filterAcceptsRows
)来过滤来自 QStandardItemModel
的元素。目前它使用 setFilterRegExp
完美过滤,但我遇到的问题是,由于 ProxyModel
只搜索元素,我失去了结构。例如假设我有这个结构:
Root Folder 1
|----Sub Folder 1
|-----Item 1
|-----Item 2
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
Root Folder 2
|----Sub Folder 1
|-----Item 1
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
完成过滤后,如果 items
名称包含“2”,我会得到
Item 2
Item 2
Item 2
最好我希望它输出:
Root Folder 1
|----Sub Folder 1
|-----Item 2
|----Sub Folder 2
|-----Item 2
Root Folder 2
|----Sub Folder 2
|-----Item 2
我正在考虑使用原始模型,如果元素不匹配就删除它们,但这显然是错误的方法。我试过在 filterAcceptsRows
中获取父项,但它似乎总是空的。
这似乎是一件容易做的事情,或者只是我错过的一个设置,但我们将不胜感激任何帮助!
谢谢!
你似乎想要的是 filterAcceptsRow
应该 return 如果行本身通过测试 或 它的任何后代通过测试.
基于此,您可能想尝试一些相当基本的东西,例如...
class sort_filter_proxy: public QSortFilterProxyModel {
public:
virtual bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const
{
if (!source_parent.isValid())
return true;
return test(source_parent.model()->index(source_row, 0, source_parent));
}
private:
bool test (const QModelIndex &source_index) const
{
if (!filterRegExp().isValid())
return true;
/*
* Test source_index itself.
*/
if (source_index.data(filterRole()).toString().contains(filterRegExp()))
return true;
/*
* Test the children of source_index.
*/
for (int row = 0; row < source_index.model()->rowCount(source_index); ++row)
if (test(source_index.model()->index(row, 0, source_index)))
return true;
/*
* Neither source_index nor any of its descendants passed the test.
*/
return false;
}
};
有点'brute force',因为同一行最终可能会被多次测试,但如果您的模型不是太大,那应该不是问题。更好的算法会在用户定义的模型角色中使用额外数据来缓存调用 sort_filter_proxy::test
.
生成的结果
所以我使用了一个稍微自定义的 QSortFilterProxyModel
(刚刚实现了 filterAcceptsRows
)来过滤来自 QStandardItemModel
的元素。目前它使用 setFilterRegExp
完美过滤,但我遇到的问题是,由于 ProxyModel
只搜索元素,我失去了结构。例如假设我有这个结构:
Root Folder 1
|----Sub Folder 1
|-----Item 1
|-----Item 2
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
Root Folder 2
|----Sub Folder 1
|-----Item 1
|-----Item 3
|----Sub Folder 2
|-----Item 1
|-----Item 2
|-----Item 3
完成过滤后,如果 items
名称包含“2”,我会得到
Item 2
Item 2
Item 2
最好我希望它输出:
Root Folder 1
|----Sub Folder 1
|-----Item 2
|----Sub Folder 2
|-----Item 2
Root Folder 2
|----Sub Folder 2
|-----Item 2
我正在考虑使用原始模型,如果元素不匹配就删除它们,但这显然是错误的方法。我试过在 filterAcceptsRows
中获取父项,但它似乎总是空的。
这似乎是一件容易做的事情,或者只是我错过的一个设置,但我们将不胜感激任何帮助!
谢谢!
你似乎想要的是 filterAcceptsRow
应该 return 如果行本身通过测试 或 它的任何后代通过测试.
基于此,您可能想尝试一些相当基本的东西,例如...
class sort_filter_proxy: public QSortFilterProxyModel {
public:
virtual bool filterAcceptsRow (int source_row, const QModelIndex &source_parent) const
{
if (!source_parent.isValid())
return true;
return test(source_parent.model()->index(source_row, 0, source_parent));
}
private:
bool test (const QModelIndex &source_index) const
{
if (!filterRegExp().isValid())
return true;
/*
* Test source_index itself.
*/
if (source_index.data(filterRole()).toString().contains(filterRegExp()))
return true;
/*
* Test the children of source_index.
*/
for (int row = 0; row < source_index.model()->rowCount(source_index); ++row)
if (test(source_index.model()->index(row, 0, source_index)))
return true;
/*
* Neither source_index nor any of its descendants passed the test.
*/
return false;
}
};
有点'brute force',因为同一行最终可能会被多次测试,但如果您的模型不是太大,那应该不是问题。更好的算法会在用户定义的模型角色中使用额外数据来缓存调用 sort_filter_proxy::test
.