2010-10-03 6 views
4

J'ai une classe DefaultMutableTreeNode personnalisée conçue pour prendre en charge des connexions robustes entre plusieurs types d'attributs de données (pour moi, ces attributs peuvent être des chaînes, des balises définies par l'utilisateur ou des horodatages). Comme je regroupe des données, je voudrais donner à l'utilisateur un aperçu en direct des données stockées que nous avons vu jusqu'à présent. Pour des raisons d'efficacité, je souhaite conserver uniquement une copie d'un attribut particulier, qui peut avoir de nombreuses connexions avec d'autres attributs. Exemple: L'étiquette définie par l'utilisateur "LOL" apparaît à cinq moments différents (représentés par TimeStamps). Donc, mon JTree (la classe qui affiche cette information) aura cinq nœuds parents (un pour chaque fois que cette balise est apparue). Ces nœuds parents doivent TOUS PARTAGER UNE INSTANCE du DefaultMutableTreeNode défini pour la balise "LOL".Partage d'enfants entre parents dans un JTree

Malheureusement, en utilisant le module complémentaire (MutableTreeNode newChild) Retire newChild de QUELQUE le nœud parent actuel. C'est vraiment dommage, puisque je veux que TOUS les nœuds parents aient le même nœud enfant.

Voici une photo de FAISANT MAL (Curtis est l'auteur et il doit apparaître POUR TOUS LES FILLES):

alt text

Comment puis-je accomplir cela facilement en Java?

Mise à jour

J'ai regardé le code pour DefaultMutableTreeNode.add() ... et je suis surpris que cela fonctionne comme il le fait (les commentaires sont les miens):

public void add(MutableTreeNode child) 
{ 
    if (! allowsChildren) 
     throw new IllegalStateException(); 

    if (child == null) 
     throw new IllegalArgumentException(); 

    if (isNodeAncestor(child)) 
     throw new IllegalArgumentException("Cannot add ancestor node."); 

    // one of these two lines contains the magic that prevents a single "pointer" from being 
    // a child within MANY DefaultMutableTreeNode Vector<MutableTreeNode> children arrays... 
    children.add(child); // just adds a pointer to the child to the Vector array? 
    child.setParent(this); // this just sets the parent for this particular instance 
} 
+0

Par ailleurs, tout cela peut être résolu par clonage DefaultMutableTreeNode., mais cela irait à l'encontre de l'objectif de partager une seule instance d'un enfant –

Répondre

3

Si vous voulez facilement, vous devriez probablement renoncer à partager TreeNodes réels eux-mêmes. Le modèle entier est construit sur l'hypothèse que chaque noeud Je me concentrerais plutôt sur la conception de votre TreeNode personnalisé de sorte que plusieurs nœuds puissent tous lire leurs données à partir du même endroit, en les gardant ainsi synchronisés

+0

J'ai écrit un écouteur d'extension d'arbre qui fait à peu près ceci. –

+0

Sur un sujet similaire, j'ai pensé faire une structure en forme d'arbre (en dehors de Jtrees) avec plusieurs parents comme modèle. Cela devient impossible si l'objectif est de pouvoir passer à un parent. Même si vous vérifiez qu'un parent donné a un objet en tant qu'enfant, vous ne pouvez pas savoir avec certitude dans quelle branche vous vous trouvez. Ainsi, le clonage ou la liaison de données est probablement le chemin à suivre, ce qui dans le cas présent aurait quelque chose comme avoir la même référence dans un objet utilisateur mais des TreeNodes différents. –

0

Malheureusement, je crois que la réponse est non. Afin de faire ce dont vous parlez, vous devez avoir un objet utilisateur interne DefaultMutableTreeNode être un pointeur à une certaine chaîne, de sorte que tous les DefaultMutableTreeNode correspondants puissent pointer vers et partager le même objet String.

Cependant, vous ne pouvez pas appeler DefaultMutableTreeNode.setUserObject() avec un tel pointeur String, car Java n'a pas un tel concept au niveau de C ou C++. Découvrez this outstanding blog article sur les idées fausses confuses au sujet de la valeur de passage et de la référence de passage en Java.

Mise à jour: Répondre à votre commentaire ici dans l'espace de réponse, afin que je puisse inclure un exemple de code. Oui, il est vrai que Java fonctionne avec des pointeurs en interne ... et parfois vous devez cloner une référence d'objet pour éviter les modifications non désirées de l'original. Cependant, pour faire une histoire courte (lire l'article de blog ci-dessus), ce n'est pas une de ces occasions.

public static void main(String[] args) { 

    // This HashMap is a simplification of your hypothetical collection of values, 
    // shared by all DefaultMutableTreeNode's 
    HashMap<String, String> masterObjectCollection = new HashMap<String, String>(); 
    masterObjectCollection.put("testString", "The original string"); 

    // Here's a simplification of some other method elsewhere making changes to 
    // an object in the master collection 
    modifyString(masterObjectCollection.get("testString")); 

    // You're still going to see the original String printed. When you called 
    // that method, a reference to you object was passed by value... the ultimate 
    // result being that the original object in you master collection does 
    // not get changed based on what happens in that other method. 
    System.out.println(masterObjectCollection.get("testString")); 
} 

private static void modifyString(String theString) { 
    theString += "... with its value modified"; 
} 

Vous pouvez consulter the JIDE Swing extensions, dont certains composants sont commerciaux tandis que d'autres sont open source et libre comme dans la bière. Vous pourriez trouver une sorte de composant qui se rapproche d'accomplir exactement ce que vous voulez.

+0

Java a des pointeurs, c'est très gentil à leur sujet. vous ne clonez pas de données, vous finirez par remarquer des choses bizarres dans votre programme, car tout le temps vous avez partagé une seule instance. Dans ce cas, j'ajoute le même DefaultMutableTreeNode en tant qu'enfant à plusieurs DefaultMutableTreeNodes. Malheureusement, les données DOIVENT être clonées, ou reflétées, ou quelque chose, parce que le comportement n'est pas du tout ce à quoi je m'attendais. N'y a-t-il pas une sorte de classe Graph dans la spécification Java? –

2

Je ne suis pas sûr qu'il soit considéré comme facile, mais vous pouvez regarder Creating a Data Model en mettant en œuvre TreeModel, qui « ne requiert pas que les noeuds soient représentés par DefaultMutableTreeNode objets, ou même que les noeuds mettent en œuvre l'interface TreeNode.«En plus de l'exemple tutoriel, il y a un exemple de système de fichiers cité here.

+0

Cela fonctionnera pour l'affichage. Il ne supportera probablement pas les changements de nœud sans perdre l'état d'expansion. –

+0

Bon point; Je pense qu'une implémentation de 'valueForPathChanged()' fera l'affaire; lien mis à jour. – trashgod

+0

Je ne suis pas certain non plus. On dirait un super lien. Je vais vérifier. Sans entrer dans le problème des parents multiples (la suggestion de @ bemace est probablement le chemin à parcourir ...), j'ai essayé d'implémenter un TreeModel avec des instances simples de type entité et il ne semble pas possible de mettre à jour l'interface sans perdre d'expansion. Je soupçonne qu'il y a quelque chose de spécifique entre le modèle et TreeNodes quand un DefaultTreeModel est utilisé. En outre, DefaultMutableTreeNode prend en charge un objet utilisateur afin qu'il soit possible d'y stocker une classe et d'ajuster CellRenderers et d'autres composants en conséquence. –

Questions connexes