【发布时间】:2015-12-22 08:23:06
【问题描述】:
我正在开发一个 GUI 应用程序,它有一个 TreeView(如 Win32 Regedit 的左侧面板)用于显示大量项目的小部件, 这是应用程序中最重要的部分。
+----------------------------------+-+
|[root] |#|
| +item |#|
| -item |#|
| +item | |
| -item | |
| item | |
| item | |
| ... | |
| +item | |
| +item | |
| ... | |
| +item | |
| +item | |
| ... | |
+----------------------------------+-+
目前此应用程序是基于 Qt 构建的。我的列表视图是 继承自 QTreeView,而我的 ListModel 继承自 QAbstractItemModel。他们一起工作。做了一些之后 对代码进行了优化,效率比 之前,但它仍然低于我除外。根据我的 测试,插入操作可以在几乎恒定的时间内完成, 所以这不是问题。问题是绘图。作图时, 如果有新的,将调用 QTreeView 的 doItemsLayout 方法 项目。如果有更多的项目将需要更多的时间。在 一开始,微不足道。如果有的话,我可以感觉到 GUI 的延迟 插入时超过 300K 项。 doItemsLayout 方法 如果有 1M 个项目,将需要 80 多毫秒。经验 在 GUI 上不好。另一个问题是 QTreeView 会用完 32 位 Windows(或 Wow64)上的 2GB 用户空间,如果有超过 1M 项目,进程刚刚崩溃。也许2GB不是很大 问题,因为我可以提供 64 位构建。
经过深思熟虑,我得出要解决的问题是 this:使用当前行索引定位项目。
TreeView 的垂直滚动条为我们提供了一个索引 - 第一个 项目的索引。我们必须先找到并绘制这个项目,然后简单地 预购走树以获得其余的物品。只有几个项目 在给定时间需要,因为 TreeView 的高度是 有限的。听起来不错,但没那么简单。
开头只有一个根项。新项目将 在运行时频繁插入。 TreeView 的一个项目可能是 如果它有子项(子项),则由用户展开或折叠。所以 项目的行索引经常变化。 Qt的doItemsLayout很慢 因为它将所有项目插入到矢量容器中,并且 使用向量的下标索引作为项目的行索引。什么时候 行索引将被更改,这个向量容器 变化。所以这需要 O(n) 时间。
如何优化这是我的问题。我不是在谈论 Qt,我 我在谈论一个常见的 GUI 问题。我可以在 Qt 或其他方面工作 GUI 库,这不是问题。我的目标是支持更多 TreeView 中的项目数超过 1M(越多越好)。
是否有任何数据结构或算法可以提供帮助?有什么建议吗?
编辑
如果您的建议是将项目分成几部分,并且只有部分 树立即可见,这件事已经完成。这 垂直滚动条和视口正是您所说的 关于。另外我会提供filter、finder等工具 对用户来说,用户不需要处理所有的项目 一次。所以这不是什么大问题。
【问题讨论】:
-
不要一次插入所有项目。如果可能,仅插入根项及其子项,并在节点扩展时添加扩展节点的子项/孙子项。
-
用户将如何处理 1M 项?它们不能同时全部可见,因此也许您可以只填充树的一部分并在用户四处移动时展开/折叠。
-
@BoPersson 用户不需要处理所有项目。他会使用过滤器、查找器或其他工具来定位他关心的项目。并且在给定时间,视口中只有几个项目,因此“部分”已经完成。
-
@marom 在极端情况下,只有根项及其子项,但子项的数量很大。是的,项目是分批插入的。
-
@amanjiang 你应该自己写一个支持数据获取的
QAbstractItemModel。
标签: c++ qt user-interface treeview