I am trying to create a JTree I can edit later. So far I have the following code which generates the tree with root node as expected. But, when the button is clicked (triggering the action listener) it adds another node under the root node. What I would rather it do is modify the root node. Is there anyway to do this? I tried changing the various arguments; like a 0 to -1, (MutableTreeNode) treeModel.getRoot() to (MutableTreeNode) treeModel, etc.
Thanks for any help with this.
//Set first as Defualt Node
final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("You must log in first.");
final DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
tree_folderList = new JTree(treeModel);
tree_folderList.setEditable(true);
tree_folderList.setBorder(new BevelBorder(BevelBorder.LOWERED));
treescrollPane = new JScrollPane(tree_folderList);
tree_folderList.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
tree_folderList.setShowsRootHandles(true);
//treeModel.addTreeModelListener(new MyTreeModelListener());
ActionListener btn_RefreshMail_Listener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (sessionkey == null || sessionkey.contains("Invalid")) {
treeModel.insertNodeInto(new DefaultMutableTreeNode("Must be logged in first."), (MutableTreeNode) treeModel.getRoot(), 0);
}
else {
//txt_folderList.setText(DMD.getInbox(sessionkey));
treeModel.insertNodeInto(new DefaultMutableTreeNode("Logged in."), rootNode, 0);
}
}
};
I got it working with the following code. I hope this helps someone else struggling with the same problem. The secret was to create a new defaultnode and then use that with the setroot method.
ActionListener btn_RefreshMail_Listener = new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
if (sessionkey == null || sessionkey.contains("Invalid")) {
DefaultMutableTreeNode rootNode2 = new DefaultMutableTreeNode("You must log in first.");
treeModel.setRoot(rootNode2);
treeModel.reload();
}
else {
//txt_folderList.setText(DMD.getInbox(sessionkey));
DefaultMutableTreeNode rootNode2 = new DefaultMutableTreeNode("Logged in.");
treeModel.setRoot(rootNode2);
treeModel.reload();
}
}
};
Related
I'm having a lot of trouble dealing with TreeView, more specificcaly with the text shown per node.
Starting with an initializer for the Tree, where I expected a single node with the text, it might make the program more intuitive for the users:
private void defineEmpityTree(){
cbt.setModel(new DefaultTreeModel(
new DefaultMutableTreeNode("Relat\u00F3rios Individuais") {
{
}
}
));
}
and I add initialize the Tree:
cbt = new JCheckBoxTree();
defineEmpityTree();
scrollPane.setViewportView(cbt);
"Relatórios Individuais" aren't shown, Tree Ok, another bug
I ignored this problem and continued with the actual filling of the nodes, the user specifies his search and press "ok", thats when we get the Tree filled, 2nd image.
But then then another strange problem comes, if "ok" is pressed again, some texts go strange, 3rd image.
Heres the part of the cade where the nodes are created. For an array of files nodes are created for each type of report and each report lot, its not really important.
private void defineNewTree(ArrayList<File> files){
DefaultMutableTreeNode dmtRoot = new DefaultMutableTreeNode("Relat\u00F3rios Individuais");
DefaultMutableTreeNode dmtSubFolder = null;
DefaultMutableTreeNode dmtLotFolder = null;
int childsRoot = 0;
int childsSub = 0;
for(File f : files){
String subFolder = f.getName().substring(17,f.getName().length()-4);
String name = f.getName();
String lot = f.getName().substring(0, 3);
childsRoot = dmtRoot.getChildCount();
boolean subFoldExists = false;
boolean foldLotExists = false;
//creatingo folder reports:
for(int i = 0;i<childsRoot;i++){
if(dmtRoot.getChildAt(i).toString().equals(subFolder)){
dmtSubFolder = (DefaultMutableTreeNode) dmtRoot.getChildAt(i);
subFoldExists = true;
i=childsRoot;
}
}
if(!subFoldExists){
dmtSubFolder = new DefaultMutableTreeNode(subFolder);
dmtRoot.add(dmtSubFolder);
}
for(int j = 0;j<childsSub;j++){
if(dmtSubFolder.getChildAt(j).toString().equals(lot)){
dmtLotFolder = (DefaultMutableTreeNode) dmtSubFolder.getChildAt(j);
foldLotExists = true;
j=childsSub;
}
}
if(!foldLotExists){
dmtLotFolder = new DefaultMutableTreeNode("lote "+lot);
dmtSubFolder.add(dmtLotFolder);
}
dmtLotFolder.add(new DefaultMutableTreeNode(name));
}
DefaultTreeModel myTree = new DefaultTreeModel(dmtRoot);
cbt.setModel(myTree);
}
I think the real problem is that:
cbt.setModel(myTree);
Is that the correct way to define the Tree contents?
Edit.:
Button OK:
...
JButton btnOk = new JButton("OK");
btnOk.setBounds(161, 37, 49, 23);
btnOk.setActionCommand("ok");
btnOk.addActionListener(buttonListener);
panel.add(btnOk);
...
class ButtonListener implements ActionListener{
#Override
public void actionPerformed(ActionEvent a) {
switch(a.getActionCommand()){
case "ok":
search();
self.requestFocusInWindow();
break;
case "cancel":
dispose();
break;
case "print":
TreePath[] tp = cbt.getCheckedPaths();
for(TreePath t : tp){
System.out.println(t.getLastPathComponent().toString());
}
self.requestFocusInWindow();
break;
default:
break;
}
}
}
private void search(){
FileSeeker fs = new FileSeeker(textField.getText());
ArrayList<File> files = fs.getFiles();
defineNewTree(files);
}
Edit.:
CheckBoxCellRenderer:
private class CheckBoxCellRenderer extends JPanel implements TreeCellRenderer {
private static final long serialVersionUID = -7341833835878991719L;
JCheckBox checkBox;
public CheckBoxCellRenderer() {
super();
this.setLayout(new BorderLayout());
checkBox = new JCheckBox();
add(checkBox, BorderLayout.CENTER);
setOpaque(false);
}
#Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
Object obj = node.getUserObject();
TreePath tp = new TreePath(node.getPath());
CheckedNode cn = nodesCheckingState.get(tp);
if (cn == null) {
return this;
}
checkBox.setSelected(cn.isSelected);
checkBox.setText(obj.toString());
checkBox.setOpaque(cn.isSelected && cn.hasChildren && ! cn.allChildrenSelected);
return this;
}
}
So, for the first problem the solution is:
private void defineEmpityTree(){
DefaultMutableTreeNode dmtn = new DefaultMutableTreeNode("Relat\u00F3rios Individuais");
cbt.setModel(new DefaultTreeModel(dmtn));
((DefaultTreeModel) cbt.getModel()).nodeChanged(dmtn);
}
I simply had to notify that the node had changed.
For the truncation problem,
cbt.setLargeModel(true);
did the trick.
I have created a TreeView that contains many CheckBoxTreeCells. I also have a Button that I would like to check all of the CheckBoxTreeCells. I've been reading this tutorial, and I am a bit lost. Here is what I have so far:
Button Code:
public void fooMethod() {
/*selectAll is an instance variable*/
selectAll = new Button("Select All");
selectAll.setOnMouseClicked(e -> handleSelectAllButtonAction(e));
}
private void handlSelectAllButtonAction(MouseEvent e) {
/*Code goes here*/
}
TreeView Code:
public void fooMethod2() {
/*myTreeView is also an insance variable*/
myTreeView = new TreeView<String>();
CheckBoxTreeItem<String> root = new CheckBoxTreeItem<>();
CheckBoxTreeItem<String> branch1 = new CheckBoxTreeItem<>("Branch 1");
CheckBoxTreeItem<String> branch2 = new CheckBoxTreeItem<>("Branch 2");
CheckBoxTreeItem<String> branch3 = new CheckBoxTreeItem<>("Branch 3");
root.getChildren.add(branch1);
root.getChildren.add(branch2);
root.getChildren.add(branch3);
myTreeView.setCellFactory(CheckBoxTreeCell.forTreeView());
myTreeView.setRoot(root);
myTreeView.setShowRoot(false);
myTreeView.setEditable(true);
}
The example provided in the link is a bit more complex than what I need, and I think it is confusing me. How do I edit a CheckBoxTreeItems in a TreeView?
Unless there are independent CheckBoxTreeItems, its enough to select the root:
root.setSelected(true);
since this automatically selects the children.
Best way I could find was to do this:
private void handlSelectAllButtonAction(MouseEvent e) {
CheckBoxTreeItem<String> root = (CheckBoxTreeItem<String>)myTreeView.getRoot();
int numBranches = root.getChildren().size();
for(int i = 0; i < numBranches; i++) {
if(((CheckBoxTreeItem<String>)root.getChildren().get(i)).isSelected()) {
((CheckBoxTreeItem<String>)root.getChildren().get(i)).setSelected(false);
}
}
}
I have recently been working on a Java Swing project and today I get stuck when modifying childrens of a DefaultMutableTreeNode.
The following SSCCE illustrates the problem:
import java.awt.event.*;
import javax.swing.*;
import javax.swing.tree.*;
public class Test
{
private static boolean executed = false;
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//
final DefaultMutableTreeNode root = new DefaultMutableTreeNode("root");
final JTree tree = new JTree(root);
tree.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent ev)
{
if (ev.getClickCount() == 2)
{
root.removeAllChildren();
for (String s: get())
{
root.add(new DefaultMutableTreeNode(s));
System.out.println(s + " added");
}
System.out.println();
tree.expandPath(tree.getSelectionPath());
}
}
});
frame.add(tree);
frame.setSize(200,200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
static String[] get()
{
if (!executed)
{
executed = true;
return new String[]{"a","b","c"};
}
else return new String[]{"a","b","c","d"};
}
}
As you see, the first time the get() method is invoked it returns a 3-element array, and a 4-element one afterwards. When I double-click (actually press) the root node for the first time there should be three children nodes (a, b and c), and the program behaves as expected. When I double-click the root node again I suppose it would have four children nodes. However it doesn't. When you double-click for the second time there are still only three, not four children nodes.
Did I make a mistake? Thanks for help in advance.
you should notify the model about changes use reload() method
add this lines before expand path like bellow
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
model.reload(root); // notify changes to model
tree.expandPath(tree.getSelectionPath());
Im Trying to develop a small application that uses a gui to move files from anywhere on the system. I have the code to move the files and they do indeed move when selected and buttons pressed but I dont know how to refresh the filesystem viewer to reflect the change. The code I have to set up the system viewer is below:
public class FileMover {
//Start of Global Variables
private JTree tree;
private DefaultTreeModel treeModel;
private FileSystemView fileSystemView;
protected File currentFile;
protected LinkedList fileLocations;
protected JTree movedTree;
protected JPanel areaLeft;
protected JPanel areaRight;
protected JPanel areaMiddle;
protected final JFrame openFrame;
//end of global variables.
//Constructor for FileMover
public FileMover()
{
openFrame = new JFrame("File Mover");
createFileMover();
}
public void createFileMover(){
Container contentPane = this.openFrame.getContentPane();
fileLocations = new LinkedList();
contentPane.setLayout(new BorderLayout());
areaLeft = new JPanel();
areaRight = new JPanel();
areaMiddle = new JPanel();
contentPane.add(areaLeft, BorderLayout.WEST);
contentPane.add(areaRight, BorderLayout.EAST);
contentPane.add(areaMiddle, BorderLayout.CENTER);
areaLeft.add(createSystemView());
movedTree = new JTree(fileLocations.toArray());
JScrollPane movedPane = new JScrollPane(movedTree);
JButton moveRightButton = new JButton("->");
JButton moveLeftButton = new JButton("<-");
JButton refresh = new JButton("Refresh");
areaMiddle.setLayout(new GridLayout(1,2));
areaMiddle.add(moveRightButton);
areaMiddle.add(refresh);
areaMiddle.add(moveLeftButton);
//actualy move the file
moveRightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Moving file: "+ currentFile.getName());
fileLocations.add(currentFile);
try {
//move the file to the correct location.
moveFile(currentFile);
} catch (IOException ex) {
Logger.getLogger(FileMover.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println(fileLocations.getFirst().toString());
}
});
//refresh the gui
refresh.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
refresh();
}
});
//finish setting up the frame
openFrame.setSize(1280, 768);
openFrame.setLocationRelativeTo(null);
openFrame.setDefaultCloseOperation(3);
openFrame.setResizable(false);
openFrame.pack();
openFrame.setVisible(true);
}
/** Add the files that are contained within the directory of this node.
*/
private void showChildren(final DefaultMutableTreeNode node) {
tree.setEnabled(false);
SwingWorker<Void, File> worker = new SwingWorker<Void, File>() {
#Override
public Void doInBackground() {
File file = (File) node.getUserObject();
if (file.isDirectory()) {
File[] files = fileSystemView.getFiles(file, true); //!!
if (node.isLeaf()) {
for (File child : files) {
publish(child);
}
}
}
return null;
}
#Override
protected void process(List<File> chunks) {
for (File child : chunks) {
node.add(new DefaultMutableTreeNode(child));
}
}
#Override
protected void done() {
tree.setEnabled(true);
}
};
worker.execute();
}
/** Update the File details view with the details of this File. */
private void setFileDetails(File file) {
System.out.println("Path: "+ file.getPath());
System.out.println("Name: "+ fileSystemView.getSystemDisplayName(file));
}
private void refresh(){
//refresh the tree here
}
private JScrollPane createSystemView(){
//file syatem hierarchy
fileSystemView = FileSystemView.getFileSystemView();
// the File tree
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
TreeSelectionListener treeSelectionListener = new TreeSelectionListener() {
#Override
public void valueChanged(TreeSelectionEvent tse){
DefaultMutableTreeNode node =
(DefaultMutableTreeNode)tse.getPath().getLastPathComponent();
showChildren(node);
setFileDetails((File)node.getUserObject());
currentFile = (File)node.getUserObject();
}
};
// show the file system roots.
File[] roots = fileSystemView.getRoots();
for (File fileSystemRoot : roots) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(fileSystemRoot);
root.add( node );
File[] files = fileSystemView.getFiles(fileSystemRoot, true);
for (File file : files) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(file));
}
}
}
tree = new JTree(treeModel);
tree.setRootVisible(false);
tree.addTreeSelectionListener(treeSelectionListener);
tree.setCellRenderer(new FileTreeCellRenderer());
tree.expandRow(0);
JScrollPane treeScroll = new JScrollPane(tree);
tree.setVisibleRowCount(15);
Dimension preferredSize = treeScroll.getPreferredSize();
Dimension widePreferred = new Dimension(
200,
(int)preferredSize.getHeight());
treeScroll.setPreferredSize( widePreferred );
return treeScroll;
}
The move left button and the area right are not finished but what I need is when I select a node in the tree and click the right arrow button the file/folder the node reflects is moved internally by my moveFile code and that works. but that change is not reflected in the tree so how can show this change in the tree i.e refresh the tree to show the current state of the filesystem?
I've tried treeModel.reload(); but that doesnt seem to work and throws a null pointer exception.
I've tried :
areaLeft.removeAll();
areaLeft.add(createSystemView());
thinking that it may refresh it by recreating the system view but that doesnt seem to do anything.
Help here would be most appreciated!
Edit: Below is the requested code for the file tree renderer:
/** A TreeCellRenderer for a File. */
class FileTreeCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = -7799441088157759804L;
private FileSystemView fileSystemView;
private JLabel label;
FileTreeCellRenderer() {
label = new JLabel();
label.setOpaque(true);
fileSystemView = FileSystemView.getFileSystemView();
}
#Override
public Component getTreeCellRendererComponent(
JTree tree,
Object value,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
File file = (File)node.getUserObject();
label.setIcon(fileSystemView.getSystemIcon(file));
label.setText(fileSystemView.getSystemDisplayName(file));
label.setToolTipText(file.getPath());
if (selected) {
label.setBackground(backgroundSelectionColor);
label.setForeground(textSelectionColor);
} else {
label.setBackground(backgroundNonSelectionColor);
label.setForeground(textNonSelectionColor);
}
return label;
}
}
Since from your code it looks that you know what you're doing, I'll just show the elementary example which will only work for the first time you press the refresh button:
private DefaultMutableTreeNode someNode;
private void refresh(){
System.out.println(someNode);
treeModel.removeNodeFromParent(someNode);
}
and rewrite the part of createSystemView() like this:
int cnt = 0;
for (File file : files) {
if (file.isDirectory()) {
if ((cnt++) == 5) { //1
System.out.println(file.getPath());
node.add(someNode = new DefaultMutableTreeNode(file));
}
else {
node.add(new DefaultMutableTreeNode(file));
}
}
}
This will only work if you have at least six (comment 1) directories on your root. Run the file, count the directories from root - when you press the refresh button it'll remove the sixth directory. If you press the button again it will try to remove the already removed node so you'll get an IllegalArgumentException.
You need to call removeNodeFromParent on the treeModel:
Message this to remove node from its parent. This will message nodesWereRemoved to create the appropriate event. This is the preferred way to remove a node as it handles the event creation for you.
See this example also.
If you want to refresh the entire view you should recreate the model in the refersh function as you do in initialization, or just iterate the model and update as neccessary - but I'd suggest a breadth first traversal of the model in that case.
EDIT:
"so after every move refresh will show the FS again with the files where they should now be". Let's start with reinitializing the model, by that I solely mean the treeModel instance of DefaultTreeModel class.
So, in the refresh() method you create a new treeModel instance, and fill it with DefaultMutableTreeNode instances like you did in createSystemView() method:
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
treeModel = new DefaultTreeModel(root);
File[] roots = fileSystemView.getRoots();
for (File fileSystemRoot : roots) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(fileSystemRoot);
root.add( node );
File[] files = fileSystemView.getFiles(fileSystemRoot, true);
for (File file : files) {
if (file.isDirectory()) {
node.add(new DefaultMutableTreeNode(file));
}
}
}
We have prepared the model, now we need to set it to the tree, I believe that a mere:
tree.setModel(treeModel);
should suffice, notice that you do not need to add the listener, because the setModel method reattaches the listeners from old model to the new model and also notifies the JTree view to redraw itself accordingly - I checked the source. If it won't redraw (I doubt it, but I haven't tested this) force it in the next line like this:
treeModel.reload();
APIdoc for reload() method here.
If however you want to update the model in the refresh function, which I believe would be more natural operation for an action called "refresh", you'll need to obtain the new first level directories and then traverse the tree like this (since we're traversing all the root's children, it would be the mentioned breadth-first traversal):
int firstLevelCount = treeModel.getChildCount(root);
DefaultMutableTreeNode child;
for (int i=0; i < firstLevelCount; i++) {
child = treeModel.getChild(root, index);
// update logic part 1
}
// update logic part 2
treeModel.reload();
You'll need the DefaultMutableTreeNode.getUserObject() method which will return a file that that tree node represents.
Obviously, you ll want to remove all the nodes from the model that are not in the the new files array, and for all the files that don't have their correspondent node in the model, you'll want to add them to the model.
I would advise not to use the files array but list (so that you could benefit from the List.contains() method) e.g.
List<File> files = new ArrayList<File>(Arrays.asList(FileSystemView.getFileSystemView().getRoots()));
Also, rewrite a part of your renderer like this:
if (file != null) {
label.setIcon(fileSystemView.getSystemIcon(file));
label.setText(fileSystemView.getSystemDisplayName(file));
label.setToolTipText(file.getPath());
}
because the root node in your view doesn't have associated file so you'll most probably get an NPE at some time updating the model.
In the second variant I described, you might get tempted to remove the root child node from inside the loop (at the update logic 1 part) - if you do that you'll most probably get an ConcurrentModificationException. The solution is to make another
List<DefaultMutableTreeNode> toBeRemoved = new ArrayList<DefaultMutableTreeNode>();
and at //update logic part 1 place (insde the loop) instead of removing the nodes from the model, you put it in that list. When you're done iterating the loop, you simply iterate over that list and remove them from the model at //update logic part 2 place e.g.
for (DefaultMutableTreeNode node : toBeRemoved) {
treeModel.removeNodeFromParent(node);
}
As mentioned, this will automatically trigger the view (JTree) redraw, so see what best fits your need.
EDIT^2:
Regarding the second variant of your refresh method, you already have the
private DefaultTreeModel treeModel;
as a global variable, you obtain the root of the tree like this (getRoot())
DefaultMutableTreeNode root = (DefaultMutableTreeNode)treeModel.getRoot();
and as you already did, you obtain the current state of the filesystem like this:
FileSystemView.getFileSystemView().getRoots();
these are all the variables you need to write the refresh() method as described.
Regarding the move (the buttons with arrows (<- , ->)) operation, from inside your treeSelectionListener make this variable global:
DefaultMutableTreeNode node = (DefaultMutableTreeNode)tse.getPath().getLastPathComponent();
With this variable (let's call it selectedNode), you can make use of the DefaultTreeModel methods:
removeNodeFromParent(MutableTreeNode node)
insertNodeInto(MutableTreeNode newChild,MutableTreeNode parent,int index)
Note that both methods will trigger JTree redraw. This should be sufficient to implement the operations you described. Also, you could rewrite the moveButton actionListener method like this:
moveRightButton.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if (selectedNode != null) {
//all the move-code-refresh-tre-view-here
selectedNode = null;
}
}
});
the selectedNode will only be set by treeSelectionListener, so in this manner you are sure that the the file move operation will only take place if a file is actually selected in the tree view.
I'm creating this app that creates tabs and JTrees on button click events. The problem is when I try to add ne node to a JTree it doesn't refresh the JTree ( or it doesn't add the node to it ... I don't really know).
This is the functions that creates the tabs and trees:
jTabbedPane1.add(st,jSplitpane10);
int count = jTabbedPane1.getTabCount();
jTabbedPane1.setSelectedIndex(count-1);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("All Notebooks");
DefaultMutableTreeNode notebook1 = new DefaultMutableTreeNode("Notebook 1");
root.add(notebook1);
// Create tree
JTree tree = new JTree(root);
//Create Scroll Pane for the tree
JScrollPane sp = new JScrollPane(tree);
Global.trees.add(tree);
And this is the code that is supposed to add new node "Green" to a tree in the selected tab:
int i = jTabbedPane1.getSelectedIndex();
DefaultTreeModel model = (DefaultTreeModel)Global.trees.get(i).getModel();
// Find node to which new node is to be added
int startRow = 0;
String prefix = "J";
TreePath path = Global.trees.get(i).getNextMatch(prefix, startRow, Position.Bias.Forward);
MutableTreeNode node = (MutableTreeNode)path.getLastPathComponent();
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
model.reload(newNode);
Here's also the declaration of the global list of JTrees:
public class Global {
public java.util.List<JTree> trees = new ArrayList<JTree>();
}Global Global;
Any ideas why new nodes aren't showing in the trees???
JTree and JTable are the most complex Swing components.
I think is reloaded, but not expanded.
The JTree root node has many settings: how handler or not show root node or not and so on.
I am using a debug console listing where I dump the model data as text ( override the toString() in nodes too) and I can see easily,, what is there, but if you have just a few nodes not needed, it is enough with the Netbeans's debugger.
Also try to expand all rows in tree to have it visible.
Your code is good:
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
model.reload(newNode);
but probably it is not visible, you need to expand, how to do it, that is another question
Here is some code to add JTree programmatically:
Source:http://sickprogrammersarea.blogspot.in/2014/03/add-jtree-programmatically-in-java-swing.html
import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.tree.*;
public class MyTree extends JApplet
{
JTree t;
JLabel l1;
String lang[]={"C","C++","JAVA","PYTHON","AJAX","PHP"};
public void init()
{
try
{
SwingUtilities.invokeAndWait(new Runnable() {
public void run()
{
makeGUI();
}
});
} catch(Exception e){
System.out.println("Sorry some error occured "+e);
}
}
private void makeGUI()
{
DefaultMutableTreeNode top=new DefaultMutableTreeNode("Language");
DefaultMutableTreeNode a=new DefaultMutableTreeNode("Programming");
top.add(a);
DefaultMutableTreeNode a1=new DefaultMutableTreeNode("C");
a.add(a1);
DefaultMutableTreeNode a2=new DefaultMutableTreeNode("Java");
a.add(a2);
DefaultMutableTreeNode b=new DefaultMutableTreeNode("Web Based");
top.add(b);
DefaultMutableTreeNode b1=new DefaultMutableTreeNode("PHP");
b.add(b1);
DefaultMutableTreeNode b2=new DefaultMutableTreeNode("JSP");
b.add(b2);
t=new JTree(top);
JScrollPane scr=new JScrollPane(t);
add(scr);
setLayout(new FlowLayout());
l1=new JLabel("Choose a language");
add(l1,BorderLayout.SOUTH);
t.addTreeSelectionListener(new TreeSelectionListener () {
public void valueChanged(TreeSelectionEvent ae) {
l1.setText(ae.getPath()+" is selected");
}
});
}
}
I produced a small example application to test your issue. I found that the node was being added correctly, but not expanding. Also, the call to model.reload seems unnecessary.
I added a call to expandPath on the tree to cause the display to show the new node. You may need to double check this doesn't expand too much of the tree:
public class Example extends JFrame {
private JTree tree;
public Example() {
DefaultMutableTreeNode root = new DefaultMutableTreeNode("All Notebooks");
DefaultMutableTreeNode notebook1 = new DefaultMutableTreeNode("Notebook 1");
root.add(notebook1);
tree = new JTree(root);
JScrollPane sp = new JScrollPane(tree);
setLayout(new BorderLayout());
add(sp, BorderLayout.CENTER);
add(new JButton("Go") {
{
addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
Example.this.addNode();
}
});
}}, BorderLayout.SOUTH);
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
}
private void addNode() {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
// Find node to which new node is to be added
int startRow = 0;
String prefix = "N";
TreePath path = tree.getNextMatch(prefix, startRow,
Position.Bias.Forward);
MutableTreeNode node = (MutableTreeNode) path.getLastPathComponent();
// Create new node
MutableTreeNode newNode = new DefaultMutableTreeNode("green");
// Insert new node as last child of node
model.insertNodeInto(newNode, node, node.getChildCount());
tree.expandPath(path);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example().setVisible(true);
}
});
}
}