2009-08-01 10 views
3

J'ai beaucoup de données (hiérarchiques) que je montre dans un TreeView (cela pourrait être d'environ 20K éléments ou plus, y compris les éléments enfants). Le problème particulier de mes données est que chaque objet affiché dans l'arborescence peut exister dans de nombreux éléments treeview. Ce que je veux dire par là que je pourrais avoir une hiérarchie comme celui-ci:Données hiérarchiques dans la technique de mise à jour TreeViews et TreeView

  1. Item_A -> Item_B -> ItemC
  2. Item_B -> Item_C
  3. ItemC

laisse supposer que Item_A contient Item_B qui contient Item_C tel qu'il apparaît au dessus. Cela signifie que ma liste montrera également la hiérarchie de Item_B et Item_C. Considérons maintenant que quelque chose arrive à un objet représenté Item_B (par exemple changement de nom). Ensuite, bien sûr, les deux éléments doivent être mis à jour. Considérez maintenant des milliers d'éléments dans l'arborescence avec des hiérarchies complexes. Quelle stratégie utiliseriez-vous pour mettre à jour l'arborescence? La vitesse est bien sûr la principale préoccupation ici, mais aussi la facilité d'utilisation et de maintenance. Actuellement, je place des mappages internes d'éléments de liste sur des objets et vice-versa pour trouver et mettre à jour des éléments rapidement. Est-ce une bonne stratégie? En recréant la liste après chaque mise à jour, je peux éliminer beaucoup de code, mais je ne saurais pas quels chemins d'éléments ont été développés ou réduits. Comment pourrais-je résoudre ce problème? Devrais-je stocker des chemins étendus dans un conteneur interne?

Merci. PS: le langage de programmation est C++, et la bibliothèque d'interface graphique est QT3.

Répondre

1

J'ai fait quelque chose de similaire il y a longtemps, en utilisant le contrôle commun de Windows TreeView. Ce que j'ai fait a été de définir l'indicateur CUSTOMDRAW, de garder une seule instance de chaque nœud différent possible et de faire pointer chaque nœud sur cette instance: Les 3 nœuds Item_C auraient chacun un pointeur vers la même instance Item_C. Donc, quand je change les données sur Item_C, j'ai juste besoin d'Invoquer InvalidateRect() sur les 3 nœuds Item_C afin de refléter les changements effectués sur les données (uniques) changées. Je suppose que vous pourriez appliquer la même stratégie ici.

1

Utilisez modèle/vue Qt4 si vous pouvez utiliser Qt4 dans votre projet.

Vous devrez écrire votre propre modèle qui peut être fastidieux si vous ne l'avez jamais fait, mais une fois installé, vous pouvez facilement référencer/mettre à jour plusieurs instances du même objet. Les sélections/sélection multiple peuvent être manipulées aussi.

Je ne suis pas un grand fan de modèle/la mise en œuvre de vue de Qt (modèle donné de conception modèle/vue/contrôleur est assez vieux), mais il aide à organiser les données dans Guis

1

mises à jour Désactiver à l'aide widget->setUpdatesEnabled(false), puis modifiez tous vous voulez, puis le renommer avec widget->setUpdatesEnabled(true). Voir le Qt documentation.

1

J'ai résolu un problème similaire en utilisant le contrôle d'arborescence wxWidgets. J'ai utilisé un compteur de référence singleton pour suivre les objets que je mettais dans le contrôle, et un itérateur pour les parcourir. Voici un exemple.

class ReferenceCounter 
{ 
public: 
    // Singleton pattern. Implementation left up to you. 
    static ReferenceCounter& get(); 

    void add(const TreeData& data) { 
     mCounter[data.getId()].push_back(&data); 
    } 

    void remove(const TreeData& data) { 
     const CounterType::const_iterator itr = mCounter.find(data.getId()); 
     if (itr != mCounter.end()) { 
      ItemType& items = itr->second; 
      items.erase(std::remove(items.begin(), items.end(), &data), items.end()); 
      if (items.empty()) { 
       mCounter.erase(itr); 
      } 
     } 
    } 

    typedef std::vector<TreeData*> ItemType; 
    ItemType::iterator begin(const TreeData& data) { 
     const CounterType::const_iterator itr = mCounter.find(data.getId()); 
     if (itr != mCounter.end()) { 
      return itr->second.begin(); 
     } 
     // Else condition handling left up to you. 
    } 

    ItemType::iterator end(const TreeData& data) { 
     const CounterType::const_iterator itr = mCounter.find(data.getId()); 
     if (itr != mCounter.end()) { 
      return itr->second.end(); 
     } 
     // Else condition handling left up to you. 
    } 

private:  
    typedef std::map<int, ItemType> CounterType; 
    CounterType mCounter; 
}; 

class TreeData 
{ 
public: 
    TreeData() { ReferenceCounter::get().add(*this); } 
    ~TreeData() { ReferenceCounter::get().remove(*this); } 

    // Get database rows or whatever your tree is tracking. 
    int getId() const; 
}; 

Donc, étant donné toute treedata, vous pouvez consulter toutes les autres années avec treedata correspondant ids dans le compteur de référence. Cela rend facile et rapide le maintien des noms et des choses à jour. Notre arbre gère plus de 1 000 000 nœuds sans problème. Dans ma mise en œuvre, j'ai enveloppé les choses d'itération dans une classe boost::iterator_facade pour une utilisation plus facile.

Questions connexes