6

对于我的一个项目,我有一个 QObject 派生对象树,它利用 QObject 的父/子功能来构建树。

这非常有用,因为我使用信号和槽,使用 Qt 的受保护指针并期望父对象在删除子对象时删除它们。

到现在为止还挺好。不幸的是,现在我的项目需要我管理/更改孩子的顺序。QObject 没有提供任何改变其子级顺序的方法(例外:QWidget 的 raise() 函数——但在这种情况下这没有用)。所以现在我正在寻找一种控制孩子顺序的策略。我有一些想法,但我不确定它们的优缺点:



选项 A:自定义排序索引成员变量

使用int m_orderIndex成员变量作为排序键并提供一个sortedChildren()方法,该方法返回按此键排序的 QObject 列表。

  • 易于实施到现有的对象结构中。
  • QObject::children()方法被覆盖时会出现问题 - 当项目的顺序改变时会导致循环期间出现问题,也比默认实现更昂贵。
  • 如果所有排序键都相等或 0/默认值,则应回退到 QObject 对象顺序。

选项 B:子项冗余列表

在 a 中维护一个冗余子级列表QList,并在创建和销毁时将子级添加到其中。

  • 需要昂贵的跟踪添加/删除的对象。这基本上会导致第二个孩子/父母跟踪和大量信号/插槽。QObject 已经在内部完成了所有这些操作,因此再次执行此操作可能不是一个好主意。也感觉像改变孩子的顺序这样简单的事情增加了很多臃肿。
  • 良好的灵活性,因为可以根据需要修改子项的 QList。
  • 允许一个孩子多次出现在 QList 中,或者根本不出现(即使它可能仍然是 QObject 的一个孩子)

选项 C:...?

任何想法或反馈,尤其是来自已经在自己的项目中解决此问题的人,都将受到高度赞赏。新年快乐!

4

5 回答 5

7

在过去的几天里,我花了很多时间研究所有这些选项,并与其他一些程序员仔细讨论了它们。我们决定选择选项 A

我们管理的每个对象都是父对象的子对象。由于 Qt 没有提供任何重新排序这些对象的方法,我们决定为int m_orderIndex每个对象添加一个属性,默认为 0。

每个对象都有一个访问器函数sortedChildren(),它返回一个QObjectList子对象。我们在该函数中所做的是:

  1. 使用 normalQObject::chilren()函数获取所有可用子对象的列表。
  2. dynamic_cast所有对象到我们的“基类”,它提供了m_orderIndex属性。
  3. 如果对象是可铸造的,请将其添加到临时对象列表中。
  4. qSort与自定义函数一起使用LessThan以确定 qSort 是否需要更改两个对象的顺序。
  5. 返回临时对象列表。

我们这样做的原因如下:

  • 现有代码(尤其是 Qt 自己的代码)可以继续使用children()而不必担心副作用。
  • 我们可以children()在顺序无关紧要的地方使用 normal 函数,而不会造成任何性能损失。
  • 在我们需要孩子的有序列表的地方,我们简单地替换children()sortedChildren()并得到想要的效果。

这种方法的好处之一是,如果所有排序索引都设置为零,则子级的顺序不会改变。

很抱歉回答我自己的问题,希望能启发有同样问题的人。;)

于 2010-01-09T00:57:09.373 回答
1

诸如此类的东西呢...

  1. QList listChildren = (QList)children();
  2. 排序列表儿童
  3. foreach listChildren setParent( TempParent )
  4. foreach listChildren setParent(OriginalParent)
于 2013-06-03T16:18:47.943 回答
0

一个讨厌的 hack:QObject::children()返回一个对 const 的引用。您可以抛弃 const-ness,从而直接操纵内部列表。

虽然这是非常邪恶的,并且有使 QObject 内部保留的迭代器无效的风险。

于 2010-01-02T14:50:22.640 回答
0

我没有单独的选项 C,但比较选项 A 和 B,无论哪种情况,您都在说 ~4 个字节(32 位指针,32 位整数),所以我会选择选项 B,因为您可以保留该列表已排序。

为了避免跟踪孩子的额外复杂性,您可以作弊并保持列表排序和整洁,但将其与过滤掉所有非孩子的 sortedChildren 方法结合使用。复杂性方面,这最终会在 O(nlogm) 左右(n = 孩子,m = 列表条目,假设 m >= n,即总是添加孩子),除非你对孩子有很大的周转。我们称这个选项为 C。

在您建议的选项 A 中,快速排序为您提供 O(n2) (wc),但还要求您检索指针、跟踪它们、检索整数等。组合方法只需要一个指针列表(应该是 O (n))。

于 2010-01-02T21:42:56.440 回答
0

我遇到了同样的问题,我通过选项 B 解决了。跟踪并不难,只需创建一个方法“void addChild(Type *ptr);” 另一个删除子项。

如果您将孩子排他性地存储在每个项目的私有/公共子列表 (QList) 中并删除 QObject 基础,您就不会遭受邪恶的冗余。在 free 上实现 auto-child-free 实际上很容易(尽管这需要一个额外的父指针)。

于 2010-01-05T12:59:04.487 回答