Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
?
Solved

Changing node text color when member data changes

Posted on 2010-11-13
14
Medium Priority
?
400 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
ID: 34129553
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
ID: 34129575
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
ID: 34129786
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
LVL 92

Expert Comment

by:objects
ID: 34129795
> 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
ID: 34129835
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
ID: 34131565
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
ID: 34132537
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
 

Author Comment

by:mock5c
ID: 34132675
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
ID: 34132703
>             MyTreeCellRenderer renderer = (MyTreeCellRenderer) tree.getTreeCellRenderer();
    >             renderer.setTextNonSelectionColor(Color.blue);

you shouldn't be doing that
0
 

Author Comment

by:mock5c
ID: 34133054
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 2000 total points
ID: 34133145
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
ID: 34133241
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
ID: 34133301
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
ID: 34133306
OK, thanks for your help.
0

Featured Post

[Webinar On Demand] Database Backup and Recovery

Does your company store data on premises, off site, in the cloud, or a combination of these? If you answered “yes”, you need a data backup recovery plan that fits each and every platform. Watch now as as Percona teaches us how to build agile data backup recovery plan.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
In this post we will learn how to connect and configure Android Device (Smartphone etc.) with Android Studio. After that we will run a simple Hello World Program.
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
This theoretical tutorial explains exceptions, reasons for exceptions, different categories of exception and exception hierarchy.
Suggested Courses
Course of the Month12 days, 7 hours left to enroll

564 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