I have a DefaultMutableTreeNode("birds") which has n number of children. Now I want to add this node to 2 different parents DefaultMutableTreeNode("animals") & DefaultMutableTreeNodes("animals2").
But as the add or insert method of DefaultMutableTreeNode removes the child from it's parent first. The DefaultMutableTreeNode("birds") is getting added in only one of the parent node. Whichever is the called later.
Is there any way around this?
DefaultMutableTreeNode birds = new DefaultMutableTreeNode("birds");
DefaultMutableTreeNode animals = new DefaultMutableTreeNode("animals");
DefaultMutableTreeNode animals2 = new DefaultMutableTreeNode("animals2");
animals.add(birds);
animals2.add(birds);
If I correct understand your problem the best way is to create a method which provides "birds-hierarchy":
private DefaultMutableTreeNode createBirdsNode() {
DefaultMutableTreeNode birds = new DefaultMutableTreeNode("birds");
// add another nodes to birds node.
return birds;
}
And later you can use this method to add the complete hierarchy.
animals.add(createBirdsNode());
animals2.add(createBirdsNode());
I finally ended up with below solution
JTree.DynamicUtilTreeNode.createChildren(DefaultMutableTreeNode parent, Object children)
JTree myTree = new JTree(parent)
This takes a root node as input and children object can be either an array, vector or hashtable. I used hashtable initially to store all the tree's children(birds) and then added them to 2 different root nodes(animals & animals2).
Related
Let's assume that I have a JTree similar to the picture I provided, in which the number of leaves and nodes will vary every time I run the code. Now how could I remove the nodes that are empty (AKA have no children) since I can't check so see if its going to be empty as I add them to the tree?
I have tried using an enumeration to traverse the tree and check for every node to check how many children it has but that didn't help because even if I could tell that the node I am at is a node that needs to be removed I have to tell his parent to remove him I cant tell him to remove himself from his parent node.
What do I need to use to achieve what I am looking for?
Now how could I remove the nodes that are empty...so i want a node to either have only other nodes or only leaves but not both at the same time
Traverse the tree and check for nodes which have the following criteria
Is a leaf
Has siblings that are not leafs.
even if I could tell that the node I am at is a node that needs to be removed I have to tell his parent to remove him I cant tell him to remove himself from his parent node.
That is what the DefaultTreeModel.removeNodeFromParent() method does. So you can traverse the tree recursively and just remove nodes based upon your given criteria.
DefaultMutableTreeNode root = new DefaultMutableTreeNode ("Root");
//other code
DefaultTreeModel treeModel = new DefaultTreeModel(root);
JTree tree = new JTree(treeModel);
//populate tree
recurseTree(root, treeModel);
//method to recursively remove leaf nodes that have non-leaf siblings
private void recurseTree(MutableTreeNode node, DefaultTreeModel treeModel){
if ( node.isLeaf() ){
TreeNode parent = node.getParent();
for ( int i = 0; i < parent.getChildCount(); i++ ){
if ( !parent.getChildAt(i).isLeaf() ){
treeModel.removeNodeFromParent(node);
break;
}
}
}else{
for ( int i = 0; i < node.getChildCount(); i++ ){
recurseTree((MutableTreeNode)node.getChildAt(i), treeModel);
}
}
}
All this being said, it looks like a long route around the initial addition of those nodes. Without knowing the underlying data structure to populate the tree one can only guess as to how to go about preventing those nodes from being added in the first place.
The spark list and grid components must take an iList as the dataprovider. Instead of providing them with an XML list, we must now use XMLListCollection. Sorting an XMLListCollection is easy, but when I attempt to then take to first x number of elements, they are returned unsorted.
How can one first sort, then take the first x elements from the XMLListCollection?
Example sort code:
var nameSort:Sort = new Sort();
var nameSortField:SortField = new SortField( sortField, true);
nameSort.fields = [nameSortField];
pDataCollection = new XMLListCollection(filteredData);
pDataCollection.sort = nameSort;
pDataCollection.refresh();
The sort is easy now to splice from the first element.
I have a list populated with duplicate entries. I am using a hash to store each unique entry from this list. Each key will then point to an object of type DefaultMutableTreeNode which represents the JTree node. My goal is to have this node point to all entries from the list which have the same node-same as the parent.
I have added these parent-nodes without problems but when the children nodes are added (via insertNodeInto), only parent nodes appear. A code-snippet is below; am very appreciative for advice / time.
// an unsorted list of items
List<MyObject>list = hash.get(key);
// clause to check for size
if (list.size() > 0) {
// iterate through each item in the list and fetch obj
for (int i=0; i < list.size(); i++) {
MyObject be = list.get(i);
// if object is not in hash, add to hash and point obj to new node
if (!hashParents.containsKey(be)) {
DefaultMutableTreeNode parent =
new DefaultMutableTreeNode(be.getSequence());
// add the key and jtree node to hash
hashParents.put(be, parent);
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
new DefaultMutableTreeNode("parent node"),
root.getChildCount());
((DefaultTreeModel)(tree.getModel())).reload();
}
// now that a parent-node exists, create a child
DefaultMutableTreeNode child = new DefaultMutableTreeNode("child");
// insert the new child to the parent (from the hash)
((DefaultTreeModel)(tree.getModel())).insertNodeInto(child, hashParents.get(be),
hashParents.get(be).getChildCount());
// render the tree visible
((DefaultTreeModel)(tree.getModel())).reload();
}
}
You make mistake here
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
new DefaultMutableTreeNode("parent node"),
root.getChildCount());
You already create node parent above, but don't use it. You insert in tree another node, but child nodes you still insert in parent. That's why they don't appear in tree.
This code fragment look like
// insert node to tree, relead model
((DefaultMutableTreeNode)(root)).insert(
parent,
root.getChildCount());
I'm working with a large set of hierarchical taxonomic terms, where each term ("203") has a matching "term203" movie clip on the stage, and am having trouble getting a recursive function to return all of a given term's descendants.
There is a main Dictionary() object with the following nested organization for each term:
{ [object Movie Clip] : { "tid":203, "parent":99, "name":"Culture", selected:false, "otherData":"etc" } }
...where the [object Movie Clip]'s instance name would be "term203". All of these object:subObjectArray items ("terms") are stored in a master taxonomy:Dictionary() object.
I've been trying to make a recursive function (which is in itself already a little above my head) that takes the click.target of a movie clip and returns a new Dictionary() object with all of the children and grandchildren and great grandchildren (etc) of that term, in the same, nested organization described above.
The code below traces the right number of recursive loops, but the returned Dictionary() object only contains the first run's terms (only the immediate children of the requested term).
var taxonomy:Dictionary = new Dictionary();
// ...Term info is loaded into taxonomy from a JSON-style text file)
// ...MOUSE_OVER event listeners are added to each
function revealChildren(hvr:MouseEvent):void {
trace("Spotlighting " + taxonomy[hvr.target].name + "'s children...");
for(var key:Object in getAllChildren(taxonomy[hvr.target].tid)) {
trace("Animating " + taxonomy[key].tid); // Traces only immediate children
var revealTween = new Tween(key, "alpha", Regular.easeInOut, key.alpha, 1, 1, true);
}
}
function getAllChildren(origin):Dictionary {
var children:Dictionary = new Dictionary();
for(var element:Object in taxonomy) {
if(taxonomy[element].parent == origin) {
var subSet = getAllChildren(taxonomy[element].tid);
children[element] = subSet; // *CAN'T ACCESS 'subSet' PROPERLY*
trace("Parent = " + origin);
trace("Matched! Adding " + taxonomy[element].tid + " as key and setting its value to " + subSet); // Traces correct amount of times, one for each descendent
}
else {
}
}
return children;
}
I certainly do not claim to be the most efficient AS3 programmer, so I am open to alternative configurations. However, after trying static and nested Arrays, I would prefer to continue using the Dictionary() object as my main pool.
As noted, only the immediate children end up animating in the revealChildren() function. It's mystifying to me then, that in the getAllChildren() function, all of the descendants trace sequentially (well in no particular order) in the output window.
Also I can't get any sort of name or property out of the subSet Object. That could be the problem.
I've only tested it as far as 'two generations,' but it seems that only the first round of calling the function successfully adds those terms to the new Dictionary() object and returns it intact to the animating function.
Too bad dict.filter(getDescendants) won't work. Please help!
To simplify things, I've added an output parameter called children. This is the Dictionary into which our function will store its results. It has a default value, so you don't need to specify one. In that case, it will create a new instance for itself.
function getAllChildren(origin:*, children:Dictionary = null):Dictionary {
if (children = null) children = new Dictionary();
for(var element:* in taxonomy) {
if(taxonomy[element].parent == origin) {
children[element] = taxonomy[element];
getAllChildren(taxonomy[element].tid, children);
}
}
return children;
}
When a child is discovered, it is copied over exactly: children[element] = taxonomy[element];
Next, the function calls itself recursively, supplying it the same output dictionary as it has been using.
Edit:
In response to your comment... Your code originally said this after finding a child named element:
children[element] = getAllChildren(taxonomy[element].tid);
You're making children[element] equal to a Dictionary object here. What you create is a tree structure, mapping MovieClip objects to Dictionary objects containing a similar mapping of its children. Using a for in loop on this structure will only give you the top-level children. It will not recursively traverse the entire tree.
var e1 = new E1();
e1.e2s.Add(new e2()); //e2s is null until e1 is saved, i want to save them all at the same time
context.e1s.imsertonsubmit(e1);
context.submitchanges();
The sub items will be saved along with the main item, and even identities will be set properly, if you give your DataClasses an association between these classes.
You do this by adding LoadOptions to your O/R-Designer DataClasses like this:
MyDataContext mydc = new MyDataContext();
System.Data.Linq.DataLoadOptions lo = new System.Data.Linq.DataLoadOptions();
lo.LoadWith<E1>(p => p.e2s);
mydc.LoadOptions = lo;
This way LINQ will take care of adding the sub-items, you don't need to InsertOnSubmit every one by itself.
A side effect: upon loading the item, the subitems will be retrieved, too.
Well - I don't know if your initial code block would work, but I'm guessing you have to mark your new e2 as insert on submit. Thus:
var e1 = new E1();
var e2 = new e2();
e1.e2s.Add(e2); //e2s is null until e1 is saved, i want to save them all at the same time
context.e1s.insertonsubmit(e1);
context.e2s.insertonsubmit(e2);
context.submitchanges();
there we go, apparently when you create another ctor, you have to actually call the no arg ctor in order for the stuff in the ctor to happen