QObject 子对象的顺序(策略问题)
对于我的一个项目,我有一棵 QObject 派生对象树,它利用 QObject 的父/子功能来构建树。
这非常有用,因为我使用信号和槽,使用 Qt 的受保护指针,并期望父对象在子对象被删除时也将其删除。
到目前为止,一切都很好。不幸的是,现在我的项目要求我管理/更改子项的顺序。 QObject 不提供任何更改其子级顺序的方法(例外:QWidget 的 raise() 函数 - 但在这种情况下毫无用处)。 所以现在我正在寻找一种控制孩子顺序的策略。我有一些想法,但我不确定他们的优点和缺点。缺点:
选项A:自定义排序索引成员变量
使用int m_orderIndex
成员变量作为排序键并提供sortedChildren()< /code> 方法返回按此键排序的 QObject 列表。
- 易于实现到现有的对象结构中。
- 当
QObject::children()
方法被重写时会出现问题 - 当项目的顺序更改时,将导致循环期间出现问题,而且比默认实现更昂贵。 - 如果所有排序键都相等或 0/默认,则应回退到 QObject 对象顺序。
选项B:子项冗余列表
在QList
中维护子项冗余列表,并在创建和销毁子项时向其中添加子项。
- 需要昂贵的成本来跟踪添加/删除的对象。这基本上会导致第二个子/父跟踪和大量信号/槽。 QObject 已经在内部完成了所有这些工作,因此再次执行可能不是一个好主意。还感觉像改变孩子的顺序这样简单的事情就增加了很多臃肿。
- 良好的灵活性,因为可以根据需要修改子级的 QList。
- 允许子项多次出现在 QList 中,或者根本不出现(即使它可能仍然是 QObject 的子项)
选项 C:...?
任何想法或反馈,尤其是来自已经在自己的项目中解决了这个问题的人的想法或反馈,我们都将受到高度赞赏。新年快乐!
For one of my projects I have a tree of QObject derived objects, which utilize QObject's parent/child functionality to build the tree.
This is very useful, since I make use of signals and slots, use Qt's guarded pointers and expect parent objects to delete children when they are deleted.
So far so good. Unfortunately now my project requires me to manage/change the order of children. QObject does not provide any means of changing the order of its children (exception: QWidget's raise() function - but that's useless in this case). So now I'm looking for a strategy of controlling the order of children. I had a few ideas, but I'm not sure about their pros & cons:
Option A: Custom sort index member variable
Use a int m_orderIndex
member variable as a sort key and provide a sortedChildren()
method which returns a list of QObjects sorted by this key.
- Easy to implement into existing object structure.
- Problematic when
QObject::children()
method is overriden - will lead to problems during loops when items' order is changed, also is more expensive than default implementation. - Should fall back to QObject object order if all sort keys are equal or 0/default.
Option B: Redundant list of children
Maintain a redundant list of children in a QList
, and add children to it when they are created and destroyed.
- Requires expensive tracking of added/deleted objects. This basically leads to a second child/parent tracking and lot of signals/slots. QObject does all of this internally already, so it might not be a good idea to do it again. Also feels like a lot of bloat is added for a simple thing like changing the order of children.
- Good flexibility, since a QList of children can be modified as needed.
- Allows a child to be in the QList more than one time, or not at all (even though it might be still a child of the QObject)
Option C: ...?
Any ideas or feedback, especially from people who already solved this in their own projects, is highly appreciated. Happy new year!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
在过去的几天里,我花了很多时间研究所有这些选项,并与其他一些程序员仔细讨论。我们决定选择选项A。
我们管理的每个对象都是父对象的子对象。由于 Qt 不提供任何对这些对象重新排序的方法,因此我们决定为每个对象添加一个 int m_orderIndex 属性,该属性默认为 0。
每个对象都有一个访问器函数 sortedChildren() 返回子级的
QObjectList
。我们在该函数中所做的是:dynamic_cast
所有对象到我们的“基类”,它提供m_orderIndex
属性。qSort
与自定义LessThan
函数结合使用来确定 qSort 是否需要更改两个对象的顺序。我们这样做的原因如下:
children()
而不必担心副作用。children()
函数,而不会造成任何性能损失。children()
替换为sortedChildren()
即可获得所需的效果。这种方法的好处之一是,如果所有排序索引都设置为零,则子级的顺序不会改变。
抱歉回答我自己的问题,希望能给有同样问题的人带来启发。 ;)
I spent a lot of time going through all these options in the past days and discussed them carefully with some other programmers. We decided to go for Option A.
Each of the objects we are managing is a child of a parent object. Since Qt does not provide any means of re-ordering these objects, we decided to add a
int m_orderIndex
property to each object, which defaults to 0.Each object has an accessor function
sortedChildren()
which returns aQObjectList
of the children. What we do in that function is:QObject::chilren()
function to get a list of all available child objects.dynamic_cast
all objects to our "base class", which provides them_orderIndex
property.qSort
with a customLessThan
function to find out if qSort needs to change the order of two objects.We did this for the following reasons:
children()
without having to worry about side effects.children()
function in places where the order does not matter, without having any performance loss.children()
bysortedChildren()
and get the desired effect.One of the good things about this approach is, that the order of children does not change if all sort indices are set to zero.
Sorry for answering my own question, hope that enlightens people with the same problem. ;)
怎么样...
What about something like...
一个令人讨厌的黑客: QObject::children() 返回一个引用-常量。您可以放弃常量,从而直接操作内部列表。
但这是相当邪恶的,并且存在使 QObject 内部保留的迭代器无效的风险。
A nasty hack: QObject::children() returns a reference-to-const. You could cast away the const-ness and thus manipulate the internal list directly.
This is pretty evil though, and has the risk of invalidating iterators which QObject keeps internally.
我没有单独的选项 C,但比较选项 A 和 B,无论哪种情况,你都说 ~4 个字节(32 位指针,32 位整数),所以我会选择选项 B,因为你可以保留该列表已排序。
为了避免跟踪子项的额外复杂性,您可以作弊并保持列表排序和整洁,但将其与过滤掉所有非子项的排序子项方法结合起来。从复杂性角度来看,这一切最终都会约为 O(nlogm)(n = 子项,m = 列表条目,假设 m >= n,即总是添加子项),除非您对子项有很大的周转。我们称此选项为 C。
在您建议的选项 A 中,快速排序为您提供了 O(n2) (wc),但也要求您检索指针、跟踪它们、检索整数等。组合方法只需要一个列表指针(应该是 O(n))。
I do not have an separate option C, but comparing option A and B, you are speaking ~4 bytes (32-bit pointer, 32-bit integer) in either case, so I'd go with option B, as you can keep that list sorted.
To avoid the additional complexity of tracking children, you could cheat and keep your list sorted and tidy, but combine it with a sortedChildren method that filters out all the non-children. Complexity wise, this aught to end up around O(nlogm) (n = children, m = list entries, assuming that m >= n, i.e. children are always added) unless you have a large turnaround on children. Let's call this option C.
Quicksort, in your suggested option A, gives you O(n2) (wc), but also requires you to retreive pointers, trace them, retreive an integer, etc. The combined method only needs a list of the pointers (aught to be O(n)).
我遇到了同样的问题,我通过选项 B 解决了它。跟踪并不那么困难,只需创建一个方法“void addChild(Type *ptr);”另一个用于删除子项目。
如果您将子项专门存储在每个项目的私有/公共子列表 (QList) 中并删除 QObject 基础,则不会遭受邪恶冗余。实际上,在 free 上实现 auto-child-free 非常容易(尽管这需要额外的父指针)。
I had the same problem and I solved it by Option B. Tracking isn't that difficult, just create a method "void addChild(Type *ptr);" and another one to delete a childitem.
You don't suffer from evil redundancy if you exclusivly store the children within the private/public childlist (QList) of each item and drop the QObject base. Its actually quite easy to implement auto-child-free on free (though that requires an extra parent pointer).