• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 558
  • Last Modified:

getUserObject returns null

I'm trying to change my JTree into a CheckBoxNodeTree.

I've added some print statements and it prints:

... In isCellEditable ...
... In isCellEditable:node:1.3.12.2.1107.5.1.4.54567.30000010080311570664000000016
... In isCellEditable:treeNode:1.3.12.2.1107.5.1.4.54567.30000010080311570664000000016
... In isCellEditable:userObject:null

The code for this is below.

What would be the reason for the userObject being null?

0
mock5c
Asked:
mock5c
  • 12
  • 10
  • 6
3 Solutions
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
Have you got the code for this???
0
 
objectsCommented:
how are you setting it?
0
 
mock5cAuthor Commented:
Well, I threw together this code which I believe shows userObject as null.  Most of the code is from a checkbox tree node sample I found online and I'm trying to incorporate that into my code.  This sample code however is not graphical.
import java.awt.event.*;
import java.awt.*;

import java.util.*;
import java.io.*;
import java.net.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.filechooser.*;
import javax.swing.SwingUtilities;
import javax.swing.tree.*;
import javax.swing.event.*;

public class MySample{
  public static void main(String args[]){

    MyTreeNode rootNode = new MyTreeNode();
    rootNode.setNodeName("Root");
    rootNode.setType("root");

    MyTreeNode chNode1 = new MyTreeNode();
    rootNode.setNodeName("ch1");
    rootNode.setType("leaf");

    MyTreeNode chNode2 = new MyTreeNode();
    rootNode.setNodeName("ch2");
    rootNode.setType("leaf");

    rootNode.add(chNode1);
    rootNode.add(chNode2);

    DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
    JTree tree = new JTree(treeModel);
    CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
    tree.setCellRenderer(renderer);
    tree.setCellEditor(new CheckBoxNodeEditor(tree));
    tree.setEditable(true);
    tree.setShowsRootHandles(true);
  }
}

class CheckBoxNodeRenderer implements TreeCellRenderer {

  private JCheckBox leafRenderer = new JCheckBox();
  private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
  Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground;

  protected JCheckBox getLeafRenderer()
  {
    return leafRenderer;
  }

  public CheckBoxNodeRenderer() {
    Font fontValue;
    fontValue = UIManager.getFont("Tree.font");
    if (fontValue != null) {
      leafRenderer.setFont(fontValue);
    }
    Boolean booleanValue = (Boolean) UIManager
        .get("Tree.drawsFocusBorderAroundIcon");
    leafRenderer.setFocusPainted((booleanValue != null)
        && (booleanValue.booleanValue()));

    selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
    selectionForeground = UIManager.getColor("Tree.selectionForeground");
    selectionBackground = UIManager.getColor("Tree.selectionBackground");
    textForeground = UIManager.getColor("Tree.textForeground");
    textBackground = UIManager.getColor("Tree.textBackground");
  }

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

      System.out.println("   VALUE1   " + value);
    Component returnValue;

    if (leaf) {
      String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);
      leafRenderer.setText(stringValue);
      leafRenderer.setSelected(false);

      System.out.println("   VALUE2   " + value);

      leafRenderer.setEnabled(tree.isEnabled());

      if (selected) {
        leafRenderer.setForeground(selectionForeground);
        leafRenderer.setBackground(selectionBackground);
      }
      else {
        leafRenderer.setForeground(textForeground);
        leafRenderer.setBackground(textBackground);
      }

      if (value != null && (value instanceof DefaultMutableTreeNode)) {
        System.out.println("This is a DefaultMutableTreeNode");

        Object userObject = ((DefaultMutableTreeNode) value)
            .getUserObject();
 
        System.out.println("value ***" + value);
        System.out.println("userObject ***" + userObject);

      }
      if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
        Object userObject = ((DefaultMutableTreeNode) value)
            .getUserObject();
        if (userObject instanceof CheckBoxNode) {
          CheckBoxNode node = (CheckBoxNode) userObject;
          leafRenderer.setText(node.getText());
          leafRenderer.setSelected(node.isSelected());
        }
      }
      returnValue = leafRenderer;
    }
    else {
      returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
          value, selected, expanded, leaf, row, hasFocus);
    }
    return returnValue;
  }
}

class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {

  CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
  ChangeEvent changeEvent = null;
  JTree tree;

  public CheckBoxNodeEditor(JTree tree) {
    this.tree = tree;
  }

  public Object getCellEditorValue() {
    System.out.println("... In getCellEditorValue ...");
    JCheckBox checkbox = renderer.getLeafRenderer();
    DefaultMutableTreeNode checkBoxNode = new DefaultMutableTreeNode();
    return checkBoxNode;
  }

  public boolean isCellEditable(EventObject event) {
    System.out.println("... In isCellEditable ...");
    boolean returnValue = false;
    if (event instanceof MouseEvent) {
      MouseEvent mouseEvent = (MouseEvent) event;
      TreePath path = tree.getPathForLocation(mouseEvent.getX(),
          mouseEvent.getY());
      if (path != null) {
        Object node = path.getLastPathComponent();
        System.out.println("... In isCellEditable:node:" + node);
        if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
          DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
          Object userObject = treeNode.getUserObject();
          System.out.println("... In isCellEditable:treeNode:" + treeNode);
          System.out.println("... In isCellEditable:userObject:" + userObject);
          returnValue = ((treeNode.isLeaf()) && (userObject instanceof DefaultMutableTreeNode));
        }
      }
    }
    return returnValue;
  }

  public Component getTreeCellEditorComponent(JTree tree, Object value,
      boolean selected, boolean expanded, boolean leaf, int row) {
    System.out.println("... In getTreeCellEditorComponent ...");

    Component editor = renderer.getTreeCellRendererComponent(tree, value,
        true, expanded, leaf, row, true);

    // editor always selected / focused
    ItemListener itemListener = new ItemListener() {
      public void itemStateChanged(ItemEvent itemEvent) {
        if (stopCellEditing()) {
          fireEditingStopped();
        }
      }
    };
    if (editor instanceof JCheckBox) {
      ((JCheckBox) editor).addItemListener(itemListener);
    }

    return editor;
  }
}

class CheckBoxNode {
  String text;

  boolean selected;

  public CheckBoxNode(String text, boolean selected) {
    this.text = text;
    this.selected = selected;
  }

  public boolean isSelected() {
    return selected;
  }

  public void setSelected(boolean newValue) {
    selected = newValue;
  }

  public String getText() {
    return text;
  }

  public void setText(String newValue) {
    text = newValue;
  }

  public String toString() {
    return getClass().getName() + "[" + text + "/" + selected + "]";
  }
}

class MyTreeNode extends DefaultMutableTreeNode
{

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

  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 boolean isSelected()
  {
    return selected;
  }

  public void setSelected(boolean newValue)
  {
    selected = newValue;
  }

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

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
> What would be the reason for the userObject being null?

Maybe, because you are setting userObject to anything?
0
 
objectsCommented:
you never set the user object (via setUserObject())
it is as the name suggests a user object, it does not get set for you. Its there for you to use however you see fit
Its useful for avoinding having to subclass DefaultMutableTreeNode
0
 
mock5cAuthor Commented:
In this code (http://www.java2s.com/Code/Java/Swing-JFC/CheckBoxNodeTreeSample.htm)

where is the userObject being set?  If I understand you correctly, this is why my sample code failed.  This is the code I'm trying to incorporate into my program.
0
 
objectsCommented:
the codes making the assumption that the tree data provided to create the tree will be set as the user object of the tree nodes (created inside the tree constructor).
0
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
To expand on what objects is saying, in the sample code the tree is being built by supplying it with a vector of vectors. Now I couldn't find it in the doco, but what is happening is that the JTree constructor that takes the vector argument, builds the tree nodes from the vectors contents and as it is doing so sets the user object to the current object from the vector that it is processing.

Whereas you are supplying the JTree constructor with the tree nodes already created and so it isn't doing anything else for you. The easiest way that I can see to make your program work would be to change the "if" block that is between lines 112 - 120 in the code that you posted, to the below... (i.e. don't worry about userObject at all, because the "value" object that is passed to you is the MyTreeNode object that you created at the start so you can just call the methods on that)


if ((value != null) && (value instanceof MyTreeNode)) {
        MyTreeNode node = (MyTreeNode) value;
        leafRenderer.setText(node.getNodeName());
        leafRenderer.setSelected(node.isSelected());
      }

Open in new window

0
 
mock5cAuthor Commented:
I've made those modifications, which make sense.  In my app., don't see the checkboxes changing checked to not check or vice versa.  I'm actually looking at the CheckBoxNodeTreeSample.java (from the link I sent) and don't see where it actually calls CheckBoxNode.setSelected().  There are calls to leafRenderer.setSelected() but that's a JCheckBox, not a CheckBoxNode.  I'm not sure how it is able to set this value in the node and remember the setting.

I'm upping the points.
0
 
mock5cAuthor Commented:
It seems that I have to have this userObject business in order to allow the checkboxes to be toggled.   In the CheckBoxNodeTreeSample.java code that I found on the web, I modifed the code below to what mccarl suggested and I can no longer check/uncheck the check box nodes.  

/*original code*/
      if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
        Object userObject = ((DefaultMutableTreeNode) value)
            .getUserObject();
        if (userObject instanceof CheckBoxNode) {
          CheckBoxNode node = (CheckBoxNode) userObject;
          leafRenderer.setText(node.getText());
          leafRenderer.setSelected(node.isSelected());
        }      
      }
/* new code */

      if ((value != null) && (value instanceof CheckBoxNode)) {
        CheckBoxNode node = (CheckBoxNode) value;
        leafRenderer.setText(node.getText());
        leafRenderer.setSelected(node.isSelected());
      }

So this leads me to ask if there's a way to get this userObject functionality without the whole vector arugment in the constructor.  I think having a vector will require too many modifications to my existing code.
0
 
objectsCommented:
code at that link works fine for me

problem with your code is that you don't create any CheckBoxNodes

your MyTreeNode class also seems redundant as it duplicates all the functionality already provided by the parent class
0
 
mock5cAuthor Commented:
MyTreeNode has additional private member variables and functions.  So I'm creating those instead of CheckBoxNodes.  Is there anything special about the CheckBoxNode class?  I'm not seeing anything.
0
 
objectsCommented:
> MyTreeNode has additional private member variables and functions.

yes but you also re-implement whats already in DMTN
The usual way to do what you are doing is to use the user object instead of subclassing (as has been done in the example you are using)

>  Is there anything special about the CheckBoxNode class?  I'm not seeing anything.

Yes, it indicates which nodes to render as checkboxes and includes the name and whether it is selected
0
 
objectsCommented:
>       if ((value != null) && (value instanceof CheckBoxNode)) {

There are no CheckBoxNodes in your tree so this will always be false
0
 
mock5cAuthor Commented:
The sample program I provided obviously doesn't help since it's not bringing up any GUI.  However, in the code to that link (CheckBoxNodeTreeSample.java), have you modified it and removed userObject and changed to

if ((value != null) && (value instanceof CheckBoxNode)) {
        CheckBoxNode node = (CheckBoxNode) value;
        leafRenderer.setText(node.getText());
        leafRenderer.setSelected(node.isSelected());
      }

Can you check/uncheck the nodes after doing that?
0
 
objectsCommented:
>   However, in the code to that link (CheckBoxNodeTreeSample.java), have you modified it and removed userObject and changed to

no theres no need, it works fine.

changing it to that will stop it working as the tree noes are DMTN's (not CheckBoxNode's)
0
 
mock5cAuthor Commented:
The reason I'm making the changes is simply just for testing purposes.  As mccarl said, "what is happening is that the JTree constructor that takes the vector argument, builds the tree nodes from the vectors contents and as it is doing so sets the user object to the current object from the vector that it is processing.", I figured I someone need these userObjects in order to get these checkboxes work.  I was simply trying to modify the code from the link so it did not have use the userObject code but still allow clicking.  It seems I need these userObjects to work with MyTreeNode the way I'm setting JTree.
0
 
objectsCommented:
you need something on your node to indicate whether it is selected or not
0
 
mock5cAuthor Commented:
I have boolean selected member data and void setSelected(boolean), boolean isSelected() methods.
0
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
On line 163, of the code that you posted above (note that the code that working with at the moment, that line will be at a different number) have you changed ...

returnValue = ((treeNode.isLeaf()) && (userObject instanceof DefaultMutableTreeNode));

to

returnValue = (treeNode.isLeaf());
0
 
objectsCommented:
>         CheckBoxNode node = (CheckBoxNode) value;

you should be casting it to your tree node subclass instead then

0
 
mock5cAuthor Commented:
Yes.  See the isCellEditable method below that I currently have.
public boolean isCellEditable(EventObject event) {
    System.out.println("... In isCellEditable ...");
    boolean returnValue = false;
    if (event instanceof MouseEvent) {
      MouseEvent mouseEvent = (MouseEvent) event;
      TreePath path = tree.getPathForLocation(mouseEvent.getX(),
          mouseEvent.getY());
      if (path != null) { 
        Object node = path.getLastPathComponent();

        if ((node != null) && (node instanceof MyTreeNode)) {
          MyTreeNode treeNode = (MyTreeNode) node;
          returnValue = treeNode.isLeaf();
        }       
      }
    }
    return returnValue;
  }

Open in new window

0
 
mock5cAuthor Commented:
by the way, I do see the checkbox nodes in the tree and when I click on them, they get depressed and everything.   I just can't seem to get the checkmarks to show up.  I'm trying to understand if this userObject is required for that.
0
 
objectsCommented:
no they won't because you need to change the renderer to work with your node subclass (instead of DMTN as in the example). See my earlier comment regards what you need to change

0
 
mock5cAuthor Commented:
I assume you're talking about casting to my tree node subclass.  This is the CheckBoxNodeRenderer code I've been using:
class CheckBoxNodeRenderer implements TreeCellRenderer {

  private JCheckBox leafRenderer = new JCheckBox();
  private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
  Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground;

  protected JCheckBox getLeafRenderer()
  {
    return leafRenderer;
  }

  public CheckBoxNodeRenderer() {
    Font fontValue;
    fontValue = UIManager.getFont("Tree.font");
    if (fontValue != null) {
      leafRenderer.setFont(fontValue);
    }
    Boolean booleanValue = (Boolean) UIManager
        .get("Tree.drawsFocusBorderAroundIcon");
    leafRenderer.setFocusPainted((booleanValue != null)
        && (booleanValue.booleanValue()));

    selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
    selectionForeground = UIManager.getColor("Tree.selectionForeground");
    selectionBackground = UIManager.getColor("Tree.selectionBackground");
    textForeground = UIManager.getColor("Tree.textForeground");
    textBackground = UIManager.getColor("Tree.textBackground");
  }

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

    Component returnValue;
  
    if (leaf) {       
      String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);
      leafRenderer.setText(stringValue);
      leafRenderer.setSelected(false);
      leafRenderer.setEnabled(tree.isEnabled());
                      
      if (selected) { 
        leafRenderer.setForeground(selectionForeground);
        leafRenderer.setBackground(selectionBackground);
      }
      else {
        leafRenderer.setForeground(textForeground);
        leafRenderer.setBackground(textBackground);
      }
      
      if (value != null && (value instanceof MyTreeNode)) {
        System.out.println("... instanceof This is a MyTreeNode");
        MyTreeNode node = (MyTreeNode) value;
        leafRenderer.setText(node.getNodeName());
        leafRenderer.setSelected(node.isSelected());
      }
      returnValue = leafRenderer;
    }   
    else {
      returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
          value, selected, expanded, leaf, row, hasFocus); 
    }   
    return returnValue;
  }     
}

Open in new window

0
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
I have been playing with this trying to work out what is going wrong (I can reproduce your symptoms) and I think I have found the answer.

In the CellEditor class, getCellEditorValue() is supposed to return a value which represents the newly edited state. However, the tree doesn't replace the tree nodes that you originally created with this value, it sets the value returned as the userObject.

So basically what your program is doing differently to the original sample code, is that your program keeps rendering a checkbox who's state never changes, whereas the sample code renders checkboxes who's state comes from the userObject, and it's this userObject that gets changed in the getCellEditorValue() method.

Since JTree obviously (after working all this out for myself) has a lot of assumptions on what the userObject is for, I would recommend that the best approach would be to refactor back to using the userObject. I have attached a slightly modified version of your originally posted code, that keeps your MyTreeNode class (for storing whatever attributes against it) but includes setting the userObject to a CheckBoxNode to keep track of the selected state. Notice the main differences from the sample code is that setUserObject is explicitly called on your MyTreeNodes at the start (hence emulating what the constructor with vector argument was doing)


import java.awt.event.*;
import java.awt.*;

import java.util.*;
import java.io.*;
import java.net.*;

import javax.swing.*;
import javax.swing.border.*;
import javax.swing.filechooser.*;
import javax.swing.SwingUtilities;
import javax.swing.tree.*;
import javax.swing.event.*;

public class MySample{
  public static void main(String args[]){

    MyTreeNode rootNode = new MyTreeNode();
    rootNode.setNodeName("Root");
    rootNode.setType("root");

    MyTreeNode chNode1 = new MyTreeNode();
    chNode1.setNodeName("ch1");
    chNode1.setType("leaf");
    chNode1.setUserObject(new CheckBoxNode("ch1", false));

    MyTreeNode chNode2 = new MyTreeNode();
    chNode2.setNodeName("ch2");
    chNode2.setType("leaf");
    chNode2.setUserObject(new CheckBoxNode("ch2", false));

    rootNode.add(chNode1);
    rootNode.add(chNode2);

    DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
    JTree tree = new JTree(treeModel);
    CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
    tree.setCellRenderer(renderer);
    tree.setCellEditor(new CheckBoxNodeEditor(tree));
    tree.setEditable(true);
    tree.setShowsRootHandles(true);

    JFrame frame = new JFrame("CheckBox Tree");
    JScrollPane scrollPane = new JScrollPane(tree);
    frame.getContentPane().add(scrollPane, BorderLayout.CENTER);
    frame.setSize(300, 150);
    frame.setVisible(true);
  }
}

class CheckBoxNodeRenderer implements TreeCellRenderer {

  private JCheckBox leafRenderer = new JCheckBox();
  private DefaultTreeCellRenderer nonLeafRenderer = new DefaultTreeCellRenderer();
  Color selectionBorderColor, selectionForeground, selectionBackground, textForeground, textBackground;

  protected JCheckBox getLeafRenderer()
  {
    return leafRenderer;
  }

  public CheckBoxNodeRenderer() {
    Font fontValue;
    fontValue = UIManager.getFont("Tree.font");
    if (fontValue != null) {
      leafRenderer.setFont(fontValue);
    }
    Boolean booleanValue = (Boolean) UIManager
        .get("Tree.drawsFocusBorderAroundIcon");
    leafRenderer.setFocusPainted((booleanValue != null)
        && (booleanValue.booleanValue()));

    selectionBorderColor = UIManager.getColor("Tree.selectionBorderColor");
    selectionForeground = UIManager.getColor("Tree.selectionForeground");
    selectionBackground = UIManager.getColor("Tree.selectionBackground");
    textForeground = UIManager.getColor("Tree.textForeground");
    textBackground = UIManager.getColor("Tree.textBackground");
  }

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

      System.out.println("   VALUE1   " + value);
    Component returnValue;

    if (leaf) {
      String stringValue = tree.convertValueToText(value, selected, expanded, leaf, row, false);
      leafRenderer.setText(stringValue);
      leafRenderer.setSelected(false);

      System.out.println("   VALUE2   " + value);

      leafRenderer.setEnabled(tree.isEnabled());

      if (selected) {
        leafRenderer.setForeground(selectionForeground);
        leafRenderer.setBackground(selectionBackground);
      }
      else {
        leafRenderer.setForeground(textForeground);
        leafRenderer.setBackground(textBackground);
      }

      if (value != null && (value instanceof DefaultMutableTreeNode)) {
        System.out.println("This is a DefaultMutableTreeNode");

        Object userObject = ((DefaultMutableTreeNode) value)
            .getUserObject();

        System.out.println("value ***" + value);
        System.out.println("userObject ***" + userObject);

      }
      if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
        Object userObject = ((DefaultMutableTreeNode) value)
            .getUserObject();
        if (userObject instanceof CheckBoxNode) {
          CheckBoxNode node = (CheckBoxNode) userObject;
          leafRenderer.setText(node.getText());
          leafRenderer.setSelected(node.isSelected());
        }
      }
      returnValue = leafRenderer;
    }
    else {
      returnValue = nonLeafRenderer.getTreeCellRendererComponent(tree,
          value, selected, expanded, leaf, row, hasFocus);
    }
    return returnValue;
  }
}

class CheckBoxNodeEditor extends AbstractCellEditor implements TreeCellEditor {

  CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
  ChangeEvent changeEvent = null;
  JTree tree;

  public CheckBoxNodeEditor(JTree tree) {
    this.tree = tree;
  }

  public Object getCellEditorValue() {
    System.out.println("... In getCellEditorValue ...");
    JCheckBox checkbox = renderer.getLeafRenderer();
    CheckBoxNode checkBoxNode = new CheckBoxNode(checkbox.getText(),
        checkbox.isSelected());
    return checkBoxNode;
  }

  public boolean isCellEditable(EventObject event) {
    System.out.println("... In isCellEditable ...");
    boolean returnValue = false;
    if (event instanceof MouseEvent) {
      MouseEvent mouseEvent = (MouseEvent) event;
      TreePath path = tree.getPathForLocation(mouseEvent.getX(),
          mouseEvent.getY());
      if (path != null) {
        Object node = path.getLastPathComponent();
        System.out.println("... In isCellEditable:node:" + node);
        if ((node != null) && (node instanceof DefaultMutableTreeNode)) {
          DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) node;
          Object userObject = treeNode.getUserObject();
          System.out.println("... In isCellEditable:treeNode:" + treeNode);
          System.out.println("... In isCellEditable:userObject:" + userObject);
          returnValue = ((treeNode.isLeaf()) && (userObject instanceof CheckBoxNode));
        }
      }
    }
    return returnValue;
  }

  public Component getTreeCellEditorComponent(JTree tree, Object value,
      boolean selected, boolean expanded, boolean leaf, int row) {
    System.out.println("... In getTreeCellEditorComponent ...");

    Component editor = renderer.getTreeCellRendererComponent(tree, value,
        true, expanded, leaf, row, true);

    // editor always selected / focused
    ItemListener itemListener = new ItemListener() {
      public void itemStateChanged(ItemEvent itemEvent) {
        if (stopCellEditing()) {
          fireEditingStopped();
        }
      }
    };
    if (editor instanceof JCheckBox) {
      ((JCheckBox) editor).addItemListener(itemListener);
    }

    return editor;
  }
}

class CheckBoxNode {
  String text;

  boolean selected;

  public CheckBoxNode(String text, boolean selected) {
    this.text = text;
    this.selected = selected;
  }

  public boolean isSelected() {
    return selected;
  }

  public void setSelected(boolean newValue) {
    selected = newValue;
  }

  public String getText() {
    return text;
  }

  public void setText(String newValue) {
    text = newValue;
  }

  public String toString() {
    return getClass().getName() + "[" + text + "/" + selected + "]";
  }
}

class MyTreeNode extends DefaultMutableTreeNode
{

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

  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 boolean isSelected()
  {
    return selected;
  }

  public void setSelected(boolean newValue)
  {
    selected = newValue;
  }

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

Open in new window

0
 
mock5cAuthor Commented:
mccarl, that did the trick.  I am able to tick/untick the checkboxes.  It seems that they are toggled whenever I highlight the node, whether I click on the node row or the checkbox.  Is it possible to have it so the checkbox is checked only if the checkbox itself is checked?
0
 
mccarlIT Business Systems Analyst / Software DeveloperCommented:
I think this is just standard JCheckbox behaviour, in that clicking the label or the box toggled the state (you can verify that in a normal Swing app)

The only thing I can think of is instead of creating a JCheckbox in your Renderer/Editor code, you define a custom component which is a JPanel which contains a JCheckbox with empty label and then a JLabel with the label that you want. You can therefore create instances of the custom component instead. Maybe you can find more info on the web about stopping hits on the label of a JCheckbox toggling the state.
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

  • 12
  • 10
  • 6
Tackle projects and never again get stuck behind a technical roadblock.
Join Now