Solved

Changing node text color when member data changes

Posted on 2010-11-13
14
386 Views
Last Modified: 2012-05-10
I've attached some code for your review.  Basically, I have a JTree which I have popup menus for the nodes.  When the node is right-clicked, the user can select "mark/unmark".  When they do this, the MyTreeNode member boolean uploadStatus is changed to true or false.  On change, I would like to change the text color of that node.

My first approach was this line:

      this.setCellRenderer(new MyTreeCellRenderer(mytn));

but found that I'm getting very odd results such as the root node changing color or a different sibling node changing.  Then I realized that that perhaps I should not be doing a setCellRenderer() and instead should invoking treeNodesChanged(TreeModelEvent e).  Can you provide sample code for doing this?

By treeNodesChanges, does that include the node's  member data such as boolean uploadStatus changing value?


class MyJTree extends JTree implements ActionListener
{
  private MyTreeModel treeModel;

  JPopupMenu popup;
  JMenuItem mi;

  MyJTree(MyTreeModel mytm)
  {
    super(mytm);

    treeModel = mytm;

    // define the popup
    popup = new JPopupMenu();

    mi = new JMenuItem("Mark/Unmark upload");
    mi.addActionListener(this); 
    mi.setActionCommand("upload");
    popup.add(mi);
    popup.setOpaque(true);
    popup.setLightWeightPopupEnabled(true);

    addMouseListener(
      new MouseAdapter() {
        public void mouseReleased(MouseEvent e) {
          if (e.isPopupTrigger()) {
            popup.show((JComponent)e.getSource(), e.getX(), e.getY());
          }       
        }       
      }
    );
  }

  public void actionPerformed(ActionEvent ae) {
    MyTreeNode mytn, node;

    TreePath path = this.getSelectionPath();
    mytn = (MyTreeNode) path.getLastPathComponent();
    if (ae.getActionCommand().equals("upload"))
    {
      System.out.println("Upload status before = " + mytn.getUploadStatus());
      if (mytn.getUploadStatus()) {
        mytn.setUploadStatus(false);
      }
      else {  
        mytn.setUploadStatus(true);
      }

      System.out.println("Upload status after = " + mytn.getUploadStatus());

      this.setCellRenderer(new MyTreeCellRenderer(mytn));

    }
  }
}
//--------------------
class MyTreeCellRenderer extends DefaultTreeCellRenderer {

  private MyTreeNode m_node;

  MyTreeCellRenderer(MyTreeNode node)
  {
    m_node = node;
  }

  public Component getTreeCellRendererComponent(
                      JTree tree,
                      Object value,
                      boolean sel,
                      boolean expanded,
                      boolean leaf,
                      int row,
                      boolean hasFocus) {

    super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    MyTreeNode mytn = (MyTreeNode) value;

    if (mytn.isLeaf() && mytn.getUploadStatus()) {
        setTextNonSelectionColor(Color.blue);
    }
    else {
        setTextNonSelectionColor(Color.black);
    }

    return this;
  }
}
//---------------------

...
    tree = new MyJTree(treeModel);

    treeModel.addTreeModelListener(new TreeModelListener()
      {
        public void treeNodesChanged(TreeModelEvent e)
        {
          DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) tree.getCellRenderer();
          MyTreeCellRenderer renderer = (MyTreeCellRenderer) tree.getCellRenderer();
          System.out.println("in treeNodeChanged.");
          renderer.setTextNonSelectionColor(Color.blue);
        }
        public void treeNodesInserted(TreeModelEvent e)
        {
        }
        public void treeNodesRemoved(TreeModelEvent e)
        {
        }
        public void treeStructureChanged(TreeModelEvent e)
        {
        }
      }
    );
...

Open in new window

0
Comment
Question by:mock5c
  • 7
  • 7
14 Comments
 
LVL 92

Expert Comment

by:objects
Comment Utility
you only need to set the node renderer once when you setup the tree.
you don't need to call it everytime

and you don't need that TreeModelListener
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
and yes you need to fire an eventIf you're using the DefaultTreeModel you can call the nodeChanged() method

model.nodeChanged(node);

http://download.oracle.com/javase/6/docs/api/javax/swing/tree/DefaultTreeModel.html#nodeChanged(javax.swing.tree.TreeNode)
0
 

Author Comment

by:mock5c
Comment Utility
I had already tried treeModel.nodeChanged(mytn);

I had this line before:

this.setCellRenderer(new MyTreeCellRenderer(mytn));

in the actionPerformed code I pasted.

Is this nodeChanged line in the wrong place?  I figured it would be called after mytn.setUploadStatus() was called.

You mentioned I don't need TreeModelListener.  But isn't this invoked when I call nodeChanged()?
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
> Is this nodeChanged line in the wrong place?  I figured it would be called after mytn.setUploadStatus() was called.

yes thats the right place

> You mentioned I don't need TreeModelListener.  But isn't this invoked when I call nodeChanged()?

it is, but theres nothing you need to do
the tree will get notified of the change and repaint the cell (using your renderer)
0
 

Author Comment

by:mock5c
Comment Utility
hmmm, I'm still getting odd behavior.  I would expect that the node I right-clicked on and marked (uploadStatus got set to true) would change color.  Instead, I see the sibling node change color and then just clicking on different nodes and not marking them results in the root node and other nodes changing color.
0
 

Author Comment

by:mock5c
Comment Utility
A link I found (http://www.thatsjava.com/java-swing/4572/) describes a similar method that I'm trying to do.  I do not want to do drag and drop, I just want to do some action (e.g. change node text color) when the node uploadStatus value is changed to true.  This should be for specific nodes.  The link above provides some great suggestions but there is no response to the last post which says that the modifications to the tree are made but to ALL nodes of the tree.  Unfortunately, there is no further solution provided.

In my case, not all nodes are being modified but the specific node is not being modified, only sibling and ancestor nodes.
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
what you are doing should work. If you can put together a small example I could run that demonstrates the problem hen  I'll have a look at it for you
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:mock5c
Comment Utility
I'll put together a small example.  In the meantime, can you look at the new code I'm posting?   This is the TreeModelListener.  I know when I call treeModel.nodeChanged(mytn), it will enter this listener.  Now I can see with the print statements that it actually prints the parent node's name of the node I selected (right clicked and marked for upload).  How do I make sure it's the node I selected?

Also, is it correct that I getCellRenderer() in this listener so that I can change the node text color when this listener is invoked via nodeChanged()?
treeModel.addTreeModelListener(new TreeModelListener() 
      {
        public void treeNodesChanged(TreeModelEvent e)
        {       
          MyTreeNode node = (MyTreeNode) e.getTreePath().getLastPathComponent();

          System.out.println("In treeNodeChanged ...");
          System.out.println("Node name = " + node.getNodeName());

          if (node.isLeaf() && node.getUploadStatus()) {
            node.setNodeName("new name"); 
        
            MyTreeCellRenderer renderer = (MyTreeCellRenderer) tree.getTreeCellRenderer();
        
            renderer.setTextNonSelectionColor(Color.blue);
          }       
        }       
        public void treeNodesInserted(TreeModelEvent e)
        {       
        }       
        public void treeNodesRemoved(TreeModelEvent e)
        {       
        }       
        public void treeStructureChanged(TreeModelEvent e)
        {       
        }       
      }
    );

Open in new window

0
 
LVL 92

Expert Comment

by:objects
Comment Utility
>             MyTreeCellRenderer renderer = (MyTreeCellRenderer) tree.getTreeCellRenderer();
    >             renderer.setTextNonSelectionColor(Color.blue);

you shouldn't be doing that
0
 

Author Comment

by:mock5c
Comment Utility
Here's some code that should be sufficient to demonstrate my problem.
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.event.*;
import java.awt.*;
import java.util.*;
import javax.swing.event.*;

public class TreeWithPopup extends JPanel {
    
    MyTreeNode root, node1, node2, node1a, node1b, node2a, node2b;
    DefaultTreeModel treeModel = null;
    
    public TreeWithPopup() {
        MyJTree tree;
        root = new MyTreeNode("root","root");
        node1 = new MyTreeNode("node 1","branch");
        node1a = new MyTreeNode("node 1a","leaf");
        node1b = new MyTreeNode("node 1b","leaf");
        node2 = new MyTreeNode("node 2","branch");
        node2a = new MyTreeNode("node 2a","leaf");
        node2b = new MyTreeNode("node 2b","leaf");
        root.add(node1);
        node1.add(node1a);
        node1.add(node1b);
        root.add(node2);
        node2.add(node2a);
        node2.add(node2b);
        setLayout(new BorderLayout());
        treeModel = new DefaultTreeModel(root);
        tree = new MyJTree(treeModel);

        tree.setCellRenderer(new MyTreeCellRenderer(root));

         treeModel.addTreeModelListener(new TreeModelListener()
           {
             public void treeNodesChanged(TreeModelEvent e)
             {
                // there's nothing in here for when nodeChanged(node) is called!
                System.out.println("In treeNodesChanged");
             }
             public void treeNodesInserted(TreeModelEvent e)
             {
             }
             public void treeNodesRemoved(TreeModelEvent e)
             {
             }
             public void treeStructureChanged(TreeModelEvent e)
             {
             }
           }
         );

        add(new JScrollPane(tree),"Center");
    }
    
    // Size of the window
    public Dimension getPreferredSize(){
        return new Dimension(300, 300);
    }
    
    public static void main(String s[]){
        JFrame frame = new JFrame("Tree With Popup");
        TreeWithPopup panel = new TreeWithPopup();
        
        frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        frame.setForeground(Color.black);
        frame.setBackground(Color.lightGray);
        frame.getContentPane().add(panel,"Center");
        
        frame.setSize(panel.getPreferredSize());
        frame.setVisible(true);
        frame.addWindowListener(new WindowCloser());
    }
}

class WindowCloser extends WindowAdapter {
    public void windowClosing(WindowEvent e) {
        Window win = e.getWindow();
        win.setVisible(false);
        System.exit(0);
    }
}

class MyJTree extends JTree implements ActionListener{

    private DefaultTreeModel treeModel;

    JPopupMenu popup;
    JMenuItem mi;
    
    MyJTree(DefaultTreeModel dtm) {
        super(dtm);

        treeModel = dtm;

        // define the popup
        popup = new JPopupMenu();

        mi = new JMenuItem("mark/unmark");  
        mi.addActionListener(this);
        mi.setActionCommand("upload");
        popup.add(mi);
        popup.setOpaque(true);
        popup.setLightWeightPopupEnabled(true);
        
        addMouseListener(
                new MouseAdapter() {
            public void mouseReleased( MouseEvent e ) {
                if ( e.isPopupTrigger()) {
                    popup.show( (JComponent)e.getSource(), e.getX(), e.getY() );
                }
            }
        }
        );
    }

    public void actionPerformed(ActionEvent ae) {
        MyTreeNode mytn;
        
        TreePath path = this.getSelectionPath();
        mytn = (MyTreeNode) path.getLastPathComponent();
        if (ae.getActionCommand().equals("upload")) {
            System.out.println("Upload status before = " + mytn.getUploadStatus());
            if (mytn.getUploadStatus()){
                mytn.setUploadStatus(false); // was true, make it false
            }
            else{
                mytn.setUploadStatus(true); // make it true
            }
            System.out.println("Upload status after = " + mytn.getUploadStatus());

            treeModel.nodeChanged(mytn);
        }
    }
}

class MyTreeNode implements TreeNode
{

  private String type = null;
  private String nodeName = null;
  private ArrayList<TreeNode> children = new ArrayList();
  private TreeNode parent = null;
  private String nodeId = null;
  private boolean uploadStatus = false;

  public MyTreeNode(String name, String nodetype)
  {
    nodeName = name;
    type = nodetype;
  }

  public void setNodeId(String nodeId)
  {
    this.nodeId = nodeId;
  }

  public String getNodeId()
  {
    return nodeId;
  }

  public void setType(String type)
  {
    this.type = type;
  }

  public String getType()
  {
    return this.type;
  }


  public void setNodeName(String name)
  {
    this.nodeName = name;
  }

  public String getNodeName()
  {
    return this.nodeName;
  }

  public void add(MyTreeNode node)
  {
    if (children == null)
    {
      children = new ArrayList();
    }
    System.out.println("adding :" + node.getNodeName() + " to " + nodeName);
    children.add(node);
    System.out.println("Child count for :" + nodeName + " is now: " + children.size());
  }

  public void setParent(TreeNode parent)
  {
    this.parent = parent;
  }

  public Enumeration children()
  {
    Enumeration e = Collections.enumeration(children);
    System.out.println("children() :" + nodeName + " : " + e);
    return e;
  }

  public boolean getAllowsChildren()
  {
    System.out.println("getAllowsChildren() :" + nodeName);
    boolean retVal = true;

    if (type.equals("leaf"))
    {
      retVal = false;
    }     

    return true;
  }

  public TreeNode getChildAt(int childIndex)
  {
    System.out.println("getChildAt() :" + nodeName);
    TreeNode retVal = null;

    if (childIndex < children.size() && childIndex >= 0)
    {
      retVal = children.get(childIndex);
    }

    return retVal;
  }

  public int getChildCount()
  {
    System.out.println("getChildCount() :" + nodeName + " : " + children.size());
    int retVal = 0;
    
    if (children != null)
    {
      retVal = children.size();
    }

    return retVal;
  }

  public int getIndex(TreeNode node)
  {
    System.out.println("getIndex() :" + nodeName);
    int retVal = -1;

    if (children != null)
    {
      for (int i=0; i < children.size(); i++)
      {
        TreeNode childNode = children.get(i);
        if (childNode == node)
        {
          retVal = i;
          break;
        }
      }
    }  
 
    return retVal;
  }

  public TreeNode getParent()
  {
    System.out.println("getParent() :" + nodeName);
    return parent;
  }

  public boolean isLeaf()
  {
    boolean retVal = false;

    if (type.equals("leaf"))
    {
      retVal = true;
    }

    System.out.println("isLeaf() :" + nodeName + " : " + retVal);
    return retVal;
  }

  public void setUploadStatus(boolean status)
  {
    this.uploadStatus = status;
  }

  public boolean getUploadStatus()
  {
    return this.uploadStatus;
  }

  public String toString()
  {
    return this.nodeName;
  }
}

class MyTreeCellRenderer extends DefaultTreeCellRenderer
{
  private MyTreeNode m_node;

  MyTreeCellRenderer(MyTreeNode node)
  {
    m_node = node;
  }

  public Component getTreeCellRendererComponent(
                      JTree tree,
                      Object value,
                      boolean sel,
                      boolean expanded,
                      boolean leaf,
                      int row,
                      boolean hasFocus) {

    super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
    MyTreeNode mytn = (MyTreeNode) value;

    System.out.println("In MyTreeCellRenderer");

    //if (mytn.isLeaf() && mytn.getUploadStatus()) {
    if (mytn.getUploadStatus()) {
        setTextNonSelectionColor(Color.blue);
    }
    else {
        setTextNonSelectionColor(Color.black);
    }

    return this;
  }
}

Open in new window

0
 
LVL 92

Accepted Solution

by:
objects earned 500 total points
Comment Utility
you need to set the non-selection colour *before* you call parent class


    MyTreeNode mytn = (MyTreeNode) value;

    System.out.println("In MyTreeCellRenderer");

    //if (mytn.isLeaf() && mytn.getUploadStatus()) {
    if (mytn.getUploadStatus()) {
        setTextNonSelectionColor(Color.blue);
    }
    else {
        setTextNonSelectionColor(Color.black);
    }

    super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);
0
 

Author Comment

by:mock5c
Comment Utility
That worked.  Such a small change and something I did not understand clearly.

If you don't mind me asking, when would the TreeModelListener() treeNodeChanged(TreeModelEvent e) be used?  Is that when I don't have my own renderer?
0
 
LVL 92

Expert Comment

by:objects
Comment Utility
its used when you want to take some action (excluding updating your tree) when the data in your tree changes.
0
 

Author Comment

by:mock5c
Comment Utility
OK, thanks for your help.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
This tutorial explains how to use the VisualVM tool for the Java platform application. This video goes into detail on the Threads, Sampler, and Profiler tabs.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now