Saving value from JComboBox in custom TreeCellEditor - java

I've got a JTree with a custom TreeModel and a custom TreeCellEditor displaying (for now) a JComboBox through the getTreeCellEditorComponent() override. The tree is displayed properly, with the nodes going into edit mode and displaying the JComboBox when I click on them.
Whenever I edit a node, changing the value from the dropdown, and then proceed to select another node from the three, I can see the TreeCellEditor's cancelCellEditing() being triggered.
What's the "correct" way to stop editing in stead of cancelling it, thus (hopefully?) making sure the model's valueForPathChanged() get's triggered?

After further investigation in the source code I found the answer inside the JTree class:
Setting JTree#setInvokesStopCellEditing(true) means editing is stopped in stead of cancelled whenever I change focus from one node to another. This also means my TreeModel#valueForPathChanged() gets called.

Related

JTree selection without generating event

I have a JTree, a JTable and a JList which displays the same set of objects, but in different order and with different information. If an item is selected from one of the Component, I want to select the same object on the other two Components (meaning they should be highlighted). Naturally I monitor the selection events with a Listener. Here is the problem, when a Component retrieves the selected object, I'll have to make sure the object is selected on the other Components by calling selection methods on them. This, will then notify the selection listeners on the other two components. But each of those events will in turn call selection events on components other than itself, causing an infinite loop going among the three Components.
I see one solution is to use a boolean flag, and make the listeners not propagate the selection if the flag is set. However, this seems cumbersome and not elegant. Is there a way to simply tell JTree, JTable and JList to make the selection but not fire any events (as oppose to fire an event and then catching and stopping it with a boolean flag)?
Take a look at SharedModelDemo. I think it does what you're looking for.
I would use a flag indicating whether it's user changes or internal changes but yu can also remove listeners before selection call and add them after to prevent events firing.

Using JTable for a JTree cell editor

I would like to use a JTable for editing a JTree, I extended DefaultTreeCellEditor and implemented isCellEditable getTreeCellEditorComponent, in getTreeCellEditorComponent I return a JTable. Everything works up to this point when a node is edited swing displays the JTable filled with the objects content however when editing is complete, valueForPathChanged of DefaultTreeModel never gets called. If I use a text field for editing which is the default everything works fine.
JTextField has a notifyAction, named "notify-field-accept" and typically bound to KeyEvent.VK_ENTER, that signals the CellEditor to stopEditing() and ultimately invokes the DefaultTreeCellEditor method, valueForPathChanged().
It's not clear how you indicate that editing is complete for your JTable. You should be able to do something similar with the JTextField in a CellEditorListener that is added to your custom editor via addCellEditorListener().
Incidentally, valueForPathChanged() mentions that "If you use custom user objects in the TreeModel you're going to need to subclass this and set the user object of the changed node to something meaningful."

Java- updating JTree

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?

Design for TreeCellRenderer

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.

Java Problem with the clearselection() method

I have 2 trees in my program. Iam using JTree's clearselection() method to clear the selection in 1 tree when something in the other tree is selected. The main code is something like this:(inside a valueChanged event listener and tree being the one on which the current selection has been triggered)
if ( tree == tree1 ){
tree2.clearSelection();
} else {
tree1.clearSelection();
}
When I select for the first time, it works fine. But when I try to select from a different tree after this, it appears the valueChanged method is getting called twice. Any solution?
Did you use the code I gave you in this question?
This included a flag to get round the problem of introducing an infinite loop, and should also ignore subsequent selection events when it is processing the current one.
BTW Given this relates directly to the previous question you may have been better off just commenting on the previous post. That way all the context is kept in one place.
clearSelection() triggers valueChanged as well, so you need a workaround, add some flag and do not clear selection when it's true.
EDIT. Seems like using some flag is tricky. Can you use MouseListener instead and run same code within mouseClicked event?

Categories