I've got a JTree which I'm using to display some (unsurprisingly) hierarchical data. Part of the spec is that the user can change the data source (atm it's just between files). Now, when this happens, I can rebuild the data and the tree nodes with no problem. But, I'm having substantial difficulties getting the tree to update the changes. I tried removing it from it's scrollpane and replacing with a new JTree, but I didn't see any such. I've tried removing all from the JTree and didn't see any effect.
How can I make the JTree display changes after it's been constructed?
Ninjedit: Yes, I did call updateUI().
Another edit:
I also wanted to replace the tree's current data with my new data. However, I don't see any methods that will take the DefaultMutableTreeNode that I constructed with. Even if I just remove the JTree and call updateUI on it's containing ScrollPane, nothing happens. Or if I use repaint instead.
It could be that the proper events (the JTree internal events) are not being fired. For example, you can add nodes either by using node.add(...) or even better, model.insertNodeInto(...) (assuming you're using the DefaultTreeModel). In this case, the latter method is preferred as it will fire appropriate events that will cause the view (the JTree) to update correctly. It's possible that your problem isn't with redrawing the UI, but in fact notifying the view that the model has changed.
So, I would suggest looking in to how you're dynamically modifying your JTree, and if possible I'd suggest using the DefaultTreeModel as your model to drive the view.
And just to make sure, you've read through the Sun JTree tutorials, right?
Related
I am using the JTree Swing utility to represent a Tree that actually have loops. I have a single node called root, but some of the children will eventually point back to other parts of the tree, thus not making it a true tree, but rather a graph.
My Java application keeps locking up, (no exceptions being thrown, no stack overflow... etc) when I try to use the little gray arrows to expand and contract parts of the graph.
My question is, does JTree require that none of the DefaulMutableTreeNodes not contain a loop?
If so, how do we represent something like that using a JTree utility. For example, when you are debugging an application say in eclipse, and you can infinitely use the variable tree in debug mode to keep on looking through a looped object. That is the behavior I am looking for.
Any suggestions?
I don't think it's a problem that nodes in a Jtree loop on themselves. Apparently you have a problem only with an "expand all" button, which makes sense because an expand all method will go recursively through the nodes until they have no sons.
Jtree does not have an expand all button by default, so I'm guessing yours is already customized...? My suggestion would be either remove the button, or customize the code to stop the expansion if findind a node that was already expanded higher in the hierarchy.
I am trying to remove nodes from a DefaultTreeModel. If I try to remove a single node, it doesn't get removed from the GUI. If I remove 2 nodes, only 1 of them is getting removed, etc.
I am using removeNodeFromParent(node); to remove the nodes.
Could someone please help me with this problem.
It sounds like your tree isn't detecting the nodesWereRemoved event that should be triggered by the removeNodeFromParent(node); method.
Are you using the standard DefaultTreeModel and JTree objects? If so, they should automatically refresh when doing a removal. If you've written a custom of either class, you're probably not handling the nodesWereRemoved event (in your custom JTree), or you're not triggering the event (in your custom DefaultTreeModel).
If you're using the standard objects, try calling JTree.revalidate(); and JTree.repaint(); after you remove the node, to force the tree to be repainted from your model change.
A final suggestion, have you tried any of the removeXXX() methods of JTree instead?
I read many topics about this but still have some problems.
I'm using java desktop project from NB. I have created tree from palette and now after every click of button I want to create new tree and refresh it. So I have event action performed where I want make new jTree add some DefaultMutableTreeNode's and show this in window. Any ideas?
Maybe in other words how should I create Jtree to modify it content? I make something like this now:
in initComponents jTree1 = new JTree(nodeF);
where nodeF is my field (DefaultMutableTreeNode) initialised before initComponents
and then I want to modify this node element adding and removing another nodes.
I'm able to refresh tree ((DefaultTreeModel) jTree1.getModel()).reload(); but I'm unable to create new instance of nodeF
I fell like I'm making some stupid mistake.. dont know how to create gui right..
First idea, get away from Netbeans. Using a GUI editor prevents you from learning important parts of Swing, and generates code that is awful to debug or customize.
Second idea, it sounds like you could get away with just refreshing the existing tree and removing the current content by setting the root. That way you don't have to create a new tree each time.
Is the tree structure actually changing? Or are you just expanding/collapsing nodes in the tree? My guess is the latter.
You should probably change your data model objects to implement TreeNode. The JTree will query your TreeNode objects as needed to determine which ones have children, what the children are, etc.
To expand/contract nodes in the tree without using the built-in tree controls, use the methods in JTree, e.g. expandPath or expandRow.
I'm trying to use dynamically JTree component.
Under root node I have four nodes and one of them ("Operations") can have 0 to many children. This is set by user via editable list in separate window opened on users request. After editing this list user hits button 'Save' and then magic should happen. Edited list is sent to server(on the same machine actually, so it doesn't take to long), the window with list is closed but right before that the main window (with jtree) is told to refresh itself, and I can see that it does what is told in log output, but the changes don't show on the screen.
I am using DefaultTreeModel, this method is called to create model at the beginning(when first opening the window) and after the change to update the new model with new structure.
with dmtn.getLeafCount() I can see that newly downloaded structure from server is the right one with the changed number of leaves under 'Operations'
public DefaultTreeModel getDataStructure() {
int dataID = task.getData().getId();
LoggerUtility.logger.info("Data ID: " + dataID);
DefaultMutableTreeNode dmtn = Manager.manager.getDataStructure(task.getId());
LoggerUtility.logger.info("DTMN created "+dmtn.getLeafCount());
return new DefaultTreeModel(dmtn);
}
the method used to refresh the jtree looks like this (it's very messy):
public void updateTree(){
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel)taskDataTree.getModel()).reload();
this.revalidate();
this.repaint();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
}
It's very messy because I have tried to put in there every possible solution to my problem that I have found on forums,
I also tried with my own treemodel implementation which would call fireTreeStructureChanged(...) but it also didn't change.
I should probably also add that I'm using Netbeans GUI Builder to build my gui although I don't know if it has anything to do with that.
I would be very grateful for any help with that
BR
Lucja
EDIT!!!
I also tried puting it in another thread like that:
public void updateTree() {
SwingWorker sw = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel) taskDataTree.getModel()).reload();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
return null;
}
};
sw.execute();
}
but it also didn't help.
tree.setModel( anotherModel );
Is the only line of code that you need.
If it doesn't work then it means that the tree variable does not contain a reference to the tree that was added to the GUI. Maybe you have a class variable and a local variable of the same name.
From my point of view the own TreeModel implementation was a good approach. But I know that creating an TreeModelEvent with the correct data isn't that simple.
I would suggest to update your question with your TreeModel implementation so that we can find the problem with it.
In principle it should work this way (when you set a new Model, the tree reloads itself). (This is not the most efficient way, better let the model send appropriate events when it changes.)
If this does not work, make sure you are calling the setModel method in the AWT Event Dispatch Thread (with EventQueue.invokeLater (or SwingUtilities.invokeLater, which is the same), for example. I think you should not need all your revalidate(), repaint() etc. calls (and updateUI should only be done if you changed the look-and-feel configuration).
I have been looking into JTree and TreeCellRenderer. It seems in general, the application (with one JTree) has only one instance of TreeCellRenderer. The application makes multiple calls to TreeCellRenderer's getTreeCellRendererComponent method to decide how each TreeCell is drawn, and such call are made in many occasions (when a cell is selected, deselected, move over, when scrolling, etc.). Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell??
I am trying to make a JTree where each cell contains a checkbox. The checkbox can be checked/unchecked by the user. Then, the TreeNode userObject's values are set base on the state of these checkboxes. But, from the current JTree design this is impossible - since there is only one instance of JCheckBox, and is only used to show how the Cell looks like (you can't really check it). In some sense I want to separate selection of the TreeCell and the checking of the boxes.
I have some workarounds (implementing MouseAdapter and checking if the mouse click is close by where the checkbox is rendered, then emulate a check on the box by changing its appearence in TreeCellRenderer), but still I want to know if this can be done more directly. Thanks!
Why did they decide to do that instead of having multiple instances of TreeCellRenderer, each responsible for one cell?
This is a nice example of the flyweight pattern.
For a check box tree, I like org.netbeans.swing.outline.Outline, mentioned here, but other examples are available.
Addendum: Reading your question more closely, you ask:
In some sense I want to separate selection of the TreeCell and the checking of the boxes.
This is the correct instinct: The data (checked or unchecked) should be stored in the model (TreeModel), not the view (JCheckBox). The example uses instances of CheckBoxNode in it's (implicit) model, accordingly.