我尝试在Qt 5.15.3中为一个游戏文件系统制作一个文件浏览器,左边是目录树视图,右边是文件表视图,当在树中选中一个目录时,表中应该显示该目录的子目录,但只有文件,没有其他嵌套目录。
我已经实现了两个QSortFilterProxyModels
,每个视图一个,对于树视图,代理模型的filterAcceptsRow()
实现只是检查模型索引是否代表一个目录,但是表视图的代理模型要稍微复杂一些,因为当选择不同的目录时,表使用的活动根索引会发生变化:
void FileSystemBrowserWidget::onDirectoryActivated(const QModelIndex& index)
{
// Since the proxy model filters based on the source model, we get
// the source index to use for filtering. The index we have
// been passed is from the tree view's proxy model.
const QModelIndex sourceIndex = m_treeProxyModel->mapToSource(index);
// Tell the table's proxy model about this new root.
m_tableProxyModel->setRootForFiltering(sourceIndex);
// Set the table view's root to display from.
// The table view shows the proxy model, so we map to this model.
m_fileSystemTableView->setRootIndex(m_tableProxyModel->mapFromSource(sourceIndex));
}
表代理模型的setRootForFiltering()
函数存储这个新的根,并使过滤器无效,我发现我必须这样做,因为如果表视图的根索引改变了,过滤器需要重新评估,这是因为通常目录不会通过过滤器显示在表中,所以如果它被选为表视图的根,该过滤将分层地应用,并且将不显示目录的子文件。
void FileSystemBrowserTableProxyModel::setRootForFiltering(const QModelIndex& sourceIndex)
{
if (m_rootForFiltering == sourceIndex)
{
return;
}
m_rootForFiltering = sourceIndex;
invalidateFilter();
}
为了解决过滤问题,表代理模型的filterAcceptsRow()
函数允许与已设置的根索引匹配的项:
bool FileSystemBrowserTableProxyModel::filterAcceptsRow(
int sourceRow,
const QModelIndex& sourceParent) const
{
QAbstractItemModel* src = sourceModel();
const QModelIndex srcIndex = src->index(sourceRow, 0, sourceParent);
if (srcIndex == m_rootForFiltering)
{
// Always allowed, or children don't show up.
return true;
}
// Allow if this index represents a file and not a directory.
return itemAtIndexIsAFile(srcIndex);
}
这似乎允许过滤正常工作。然而,如果我在表格视图中选择一个项目,然后在树视图中选择一个不同的目录,会出现一个奇怪的问题。QSortFilterProxyModel: index from wrong model passed to mapFromSource
被垃圾邮件发送到我的终端9次,然后我得到如下崩溃:
___lldb_unnamed_symbol11407 (@___lldb_unnamed_symbol11407:41)
QSortFilterProxyModel::flags(QModelIndex const&) const (@QSortFilterProxyModel::flags(QModelIndex const&) const:43)
QAbstractItemView::focusInEvent(QFocusEvent*) (@QAbstractItemView::focusInEvent(QFocusEvent*):41)
QWidget::event(QEvent*) (@QWidget::event(QEvent*):763)
QFrame::event(QEvent*) (@QFrame::event(QEvent*):14)
QApplicationPrivate::notify_helper(QObject*, QEvent*) (@QApplicationPrivate::notify_helper(QObject*, QEvent*):42)
... call stack continues ...
我已经检查了代码,关于索引来自错误模型的错误似乎不是由我自己进行的调用触发的。我只能假设我在某种程度上误用了代理模型,但我不确定具体是如何误用的。我没有向模型添加或删除项,因此底层数据应该不会更改。
如果我删除了对invalidateFilter()
的调用,这个问题就不会发生。还应该注意的是,我不能简单地打开recursiveFilteringEnabled
:这意味着任何可见的子目录也将使其父目录可见,这将导致任何包含文件的目录通过过滤器并显示在表格视图中.如果它有用,我正在Kubuntu上开发和测试这个实现.
1条答案
按热度按时间taor4pac1#
经过进一步的研究,我想我已经解决了这个问题。如果一个嵌套目录显示在表视图中,那么链中父目录的所有模型索引也需要通过过滤器,否则什么都不会显示。我不太清楚确切的问题是什么,但我怀疑表视图期望一定数量的索引,但由于我没有满足前面提到的规则,它无法获得这些索引。在此状态下与视图交互会导致某种未定义的行为。
在对上述规则执行检查之后,似乎又可以正常工作了。