Ordre des enfants QObject (question de stratégie)
Question
Pour un de mes projets que j'ai un arbre de QObject dérivé des objets, qui utilisent la fonctionnalité parent QObject / enfant pour construire l'arbre.
Ceci est très utile, car je utilise des signaux et des machines à sous, utilisez les pointeurs de Qt et gardés attendre les objets parents à supprimer les enfants lorsqu'ils sont supprimés.
Jusqu'à présent, si bon. Malheureusement, maintenant mon projet me oblige à gérer / modifier l'ordre des enfants. QObject ne fournit aucun moyen de changer l'ordre de ses enfants (exception: la fonction raise () de QWidget - mais qui est inutile dans ce cas). Alors maintenant, je suis à la recherche d'une stratégie de contrôle de l'ordre des enfants J'ai eu quelques idées, mais je ne suis pas sûr de leurs avantages et inconvénients.
Option A: index tri personnalisé variable membre
Utilisez une variable membre int m_orderIndex
comme une clé de tri et de fournir une méthode de sortedChildren()
qui retourne une liste de QObjects triées par cette touche.
- Facile à mettre en œuvre dans la structure de l'objet existant.
- Problématiques lorsque la méthode de
QObject::children()
est outrepassée -. Entraînera des problèmes lors de boucles lorsque l'ordre des éléments est changé, aussi est plus cher que la mise en œuvre par défaut - tomberions à l'ordre d'objet QObject si toutes les clés de tri sont égales ou 0 / default.
Option B: Liste redondante des enfants
Maintenir une liste redondante des enfants dans un QList
, et ajouter les enfants quand ils sont créés et détruits.
- nécessite un suivi coûteux ajoutés / supprimés objets. Cela conduit essentiellement à un second suivi des enfants / parents et beaucoup de signaux / slots. QObject fait tout cela en interne déjà, il pourrait ne pas être une bonne idée de le faire à nouveau. se sent aussi comme beaucoup de ballonnement est ajouté pour une chose simple comme changer l'ordre des enfants.
- Une bonne flexibilité, puisqu'une QList des enfants peut être modifiée au besoin.
- permet à un enfant d'être dans le QList plus d'une fois, ou pas du tout (même si elle est peut-être encore un enfant du QObject)
Option C: ...
Toutes les idées ou commentaires, en particulier des personnes qui ont déjà résolu ce problème dans leurs propres projets, est très apprécié. Bonne année!
La solution
J'ai passé beaucoup de temps à passer par toutes ces options dans les derniers jours et en ont discuté soigneusement avec d'autres programmeurs. Nous avons décidé d'aller pour A .
Chacun des objets que nous gérons est un enfant d'un objet parent. Puisque Qt ne fournit aucun moyen de re-commander ces objets, nous avons décidé d'ajouter une propriété int m_orderIndex
à chaque objet, qui est par défaut à 0.
Chaque objet a une fonction accesseur sortedChildren()
qui retourne un QObjectList
des enfants. Ce que nous faisons dans cette fonction est:
- Utilisez la fonction
QObject::chilren()
normale pour obtenir une liste de tous les objets enfants disponibles. -
dynamic_cast
tous les objets à notre "classe de base", qui fournit la propriétém_orderIndex
. - Si l'objet est coulable, l'ajouter à une liste d'objets temporaires.
- Utilisation
qSort
avec une fonction deLessThan
personnalisé pour savoir si qSort a besoin de changer l'ordre de deux objets. - Retour à la liste des objets temporaires.
Nous avons fait cela pour les raisons suivantes:
- Code existant (en particulier propre code de Qt) peut continuer à utiliser
children()
sans avoir à se soucier des effets secondaires. - Nous pouvons utiliser la fonction
children()
normale dans des endroits où l'ordre n'a pas d'importance, sans avoir aucune perte de performance. - Dans les endroits où nous avons besoin de la liste ordonnée des enfants, nous remplaçons simplement
children()
parsortedChildren()
et obtenir l'effet désiré.
L'une des bonnes choses au sujet de cette approche est que l'ordre des enfants ne change pas si tous les indices de tri sont mis à zéro.
Désolé pour répondre à ma propre question, l'espoir que les gens avec le éclaire même problème. ;)
Autres conseils
Qu'en est-il quelque chose comme ...
- QList ListChildren = (QList) enfants ();
- trier ListChildren
- foreach ListChildren setParent (TempParent)
- foreach ListChildren setParent (OriginalParent)
Un hack méchant: QObject :: enfants () retourne une référence -à-const. Vous pouvez rejetterai la const-ness et manipuler ainsi la liste interne directement.
est assez mal cependant, et a le risque de vicier itérateurs qui QObject maintient en interne.
Je n'ai pas une option séparée C, mais en comparant l'option A et B, vous parlez ~ 4 octets (pointeur 32 bits, nombre entier de 32 bits) dans les deux cas, alors je partirais avec l'option B, comme vous pouvez garder cette liste triée.
Pour éviter la complexité supplémentaire des enfants de suivi, vous pouvez tricher et garder votre liste triée et bien rangé, mais le combiner avec une méthode sortedChildren qui filtre tous les non-enfants. La complexité sage, ce aught pour mettre fin autour de O (nlogm) (n = enfants, m = entrées de la liste, en supposant que m> = n, à savoir les enfants sont toujours ajoutés) à moins que vous avez un grand revirement sur les enfants. Appelons cette option C.
Quicksort, dans votre option Suggéré A, vous donne O (n2) (wc), mais exige également que pour récupérer les pointeurs, les tracer, retreive un entier, etc. La méthode combinée n'a besoin que d'une liste des pointeurs (aught pour être O (n)).
J'ai eu le même problème et je l'ai résolu par l'option B. Le suivi est pas difficile, il suffit de créer une méthode « addChild void (type * ptr); » et un autre pour supprimer un childitem.
Vous ne souffrez pas de redondance du mal si vous stockez exclusivly les enfants dans le childlist privé / public (QList) de chaque élément et déposez la base QObject. Son assez facile à mettre en œuvre sans auto-enfant gratuit (mais qui nécessite un pointeur parent supplémentaire).