Results 1 to 12 of 12
  1. #1
    aneesahamedaa is offline Member
    Join Date
    Jul 2008
    Posts
    26
    Rep Power
    0

    Default JcheckBoxes as JTree Nodes

    I want to display my contacts in a JTree. Contacts can be inside a group and there can be contacts which do not belong to any groups. I want to bring this concept into a JTree. Only JCheckboxes should be there as nodes for selecting; ie; even to the side of a groupname and for every others, it has to be a JCheckbox and not any conventional Jtree nodes. I have zero idea as to how to implement this. Please help.
    Regards,
    Anees

  2. #2
    Niveditha's Avatar
    Niveditha is offline Senior Member
    Join Date
    May 2008
    Posts
    307
    Rep Power
    7

    Default

    Hi,
    Check the code in the following link
    CheckBox Node Tree Sample : Tree*«*Swing JFC*«*Java
    To finish sooner, take your own time....
    Nivedithaaaa

  3. #3
    aneesahamedaa is offline Member
    Join Date
    Jul 2008
    Posts
    26
    Rep Power
    0

    Default

    I have got that code 3-4 days before. Anyway, thanks Niveditha.
    Based on that code only, I made the point Only JCheckboxes should be there as nodes specific. If anyone knows how to make the parent nodes there(Accessibility, browsing) to JCheckboxes, please help.

    Anees

  4. #4
    skaspersen is offline Member
    Join Date
    Jul 2008
    Posts
    31
    Rep Power
    0

    Default

    In the getTreeCellRendererComponent() method remove the if(leaf){} condition. and get rid of the else{} statement

  5. #5
    aneesahamedaa is offline Member
    Join Date
    Jul 2008
    Posts
    26
    Rep Power
    0

    Default

    1) How to open the node on single click upon parent names(Accessibility, Browsing).
    2) How to make all the child nodes automatically checked, when the parent node gets checked.
    Please suggest some methods, as to how to implement these.

  6. #6
    hardwired's Avatar
    hardwired is offline Senior Member
    Join Date
    Jul 2007
    Posts
    1,576
    Rep Power
    9

    Default

    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.font.*;
    import java.util.EventObject;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.*;
    import javax.swing.plaf.basic.BasicGraphicsUtils;
    import javax.swing.tree.*;
    
    public class CheckTree {
        private JScrollPane getContent() {
            JTree tree = new JTree(getTreeModel());
            tree.setEditable(true);
            CheckPanelRenderer renderer = new CheckPanelRenderer();
            tree.setCellRenderer(renderer);
            tree.setCellEditor(new CheckPanelEditor(tree, renderer));
            expand(tree);
            tree.addTreeExpansionListener(new ExpansionMonitor());
            return new JScrollPane(tree);
        }
    
        private TreeModel getTreeModel() {
            String[][] ids = {
                { "colors", "blue", "violet", "red", "yellow" },
                { "sports", "basketball", "soccer", "football", "hockey" },
                { "food", "hot dogs", "pizza", "haggis", "bananas" }
            };
            CheckStore store = new CheckStore("JTree", false);
            DefaultMutableTreeNode root = new DefaultMutableTreeNode(store);
            for(int i = 0; i < ids.length; i++) {
                String[] s = ids[i];
                DefaultMutableTreeNode parent =
                    new DefaultMutableTreeNode(new CheckStore(s[0], false));
                root.add(parent);
                DefaultMutableTreeNode n;
                for(int j = 1; j < s.length; j++) {
                    store = new CheckStore(s[j], false);
                    parent.add(n = new DefaultMutableTreeNode(store));
                }
            }
            return new DefaultTreeModel(root);
        }
    
        private void expand(JTree tree) {
            DefaultMutableTreeNode root =
                (DefaultMutableTreeNode)tree.getModel().getRoot();
            java.util.Enumeration e = root.breadthFirstEnumeration();
            while(e.hasMoreElements()) {
                DefaultMutableTreeNode node =
                    (DefaultMutableTreeNode)e.nextElement();
                if(node.isLeaf()) continue;
                int row = tree.getRowForPath(new TreePath(node.getPath()));
                tree.expandRow(row);
            }
        }
    
        public static void main(String[] args) {
            CheckTree test = new CheckTree();
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(test.getContent());
            f.setSize(400,400);
            f.setLocation(200,200);
            f.setVisible(true);
        }
    }
    
    class ExpansionMonitor implements TreeExpansionListener {
        public void treeCollapsed(TreeExpansionEvent e) {} 
    
        public void treeExpanded(TreeExpansionEvent e) {
            JTree tree = (JTree)e.getSource();
            TreePath path = e.getPath();
            DefaultMutableTreeNode node =
                (DefaultMutableTreeNode)path.getLastPathComponent();
            if(node.getLevel() == 1) {
                // Select all children of level one nodes on expansion.
                if(tree.isExpanded(path)) {
                    selectAllChildren(path);
                }
            }
        }
    
        private void selectAllChildren(TreePath path) {
            TreeNode node = (TreeNode)path.getLastPathComponent();
            select(node);
            if (node.getChildCount() > 0) {
                java.util.Enumeration e = node.children();
                while(e.hasMoreElements()) {
                    TreeNode n = (TreeNode)(TreeNode)e.nextElement();
                    select(n);
                    selectAllChildren(path.pathByAddingChild(n));
                }
            }
        }
    
        private void select(TreeNode node) {
            DefaultMutableTreeNode n = (DefaultMutableTreeNode)node;
            CheckStore cs = (CheckStore)n.getUserObject();
            cs.state = true;
        }
    }
    
    class CheckPanelEditor extends AbstractCellEditor
                           implements TreeCellEditor, ActionListener {
        JTree tree;
        CheckPanelRenderer renderer;
        JLabel label;
        EditorPanel panel;
        JCheckBox checkBox;
        CheckStore checkStore;
        protected transient int offset;
        protected int clickCountToStart = 1;
    
        public CheckPanelEditor(JTree tree, CheckPanelRenderer cpr) {
            this.tree = tree;
            renderer = cpr;
            label = new JLabel();
            checkBox = new JCheckBox();
            checkBox.setBorder(null);
            checkBox.setBackground(renderer.getBackgroundNonSelectionColor());
            checkBox.addActionListener(this);
            checkBox.setRequestFocusEnabled(false);
            panel = new EditorPanel();
            panel.setBorder(null);
            panel.setBackground(renderer.getBackgroundNonSelectionColor());
            panel.add(label);
            panel.add(checkBox);
        }
    
        public Component getTreeCellEditorComponent(JTree tree,
                                                    Object value,
                                                    boolean isSelected,
                                                    boolean expanded,
                                                    boolean leaf,
                                                    int row) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
            checkStore = (CheckStore)node.getUserObject();
            label.setText(checkStore.toString());
            checkBox.setSelected(checkStore.getState());
    
            if(leaf) {
                label.setIcon(renderer.getLeafIcon());
            } else if(expanded) {
                label.setIcon(renderer.getOpenIcon());
            } else {
                label.setIcon(renderer.getClosedIcon());
            }
            return panel;
        }
    
        public Object getCellEditorValue() {
            checkStore.text = label.getText();
            checkStore.state = checkBox.isSelected();
            return checkStore;
        }
    
        public boolean isCellEditable(EventObject anEvent) {
            if(anEvent != null && anEvent instanceof MouseEvent &&
                  ((MouseEvent)anEvent).getClickCount() >= clickCountToStart) {
                TreePath path = tree.getPathForLocation(
                                     ((MouseEvent)anEvent).getX(),
                                     ((MouseEvent)anEvent).getY());
                int row = tree.getRowForPath(path);
                Object value = path.getLastPathComponent();
                boolean isSelected = tree.isRowSelected(row);
                boolean expanded = tree.isExpanded(path);
                boolean leaf = tree.getModel().isLeaf(value);
                determineOffset(tree, value, isSelected, expanded, leaf, row);
                Rectangle pb = tree.getPathBounds(path);
                Rectangle target = new Rectangle(offset, pb.y,
                                                 pb.x+pb.width-offset,
                                                 pb.height);
                Point p = ((MouseEvent)anEvent).getPoint();
                if(target.contains(p)) {
    	        tree.startEditingAtPath(path);
                    return true;
                }
            }
            return false;
        }
    
        public void actionPerformed(ActionEvent e) {
            super.stopCellEditing();
        }
    
        protected void determineOffset(JTree tree, Object value,
                                 boolean isSelected, boolean expanded,
                                 boolean leaf, int row) {
            int x0 = tree.getPathBounds(tree.getPathForRow(row)).x;
            int hgap = renderer.getHgap();
            offset = x0 + hgap;
            Icon editingIcon = null;
            if(leaf)
                editingIcon = renderer.getLeafIcon();
            else if(expanded)
                editingIcon = renderer.getOpenIcon();
            else
                editingIcon = renderer.getClosedIcon();
            if(editingIcon != null)
                offset += editingIcon.getIconWidth() +
                              renderer.getIconTextGap();
    	String stringValue = tree.convertValueToText(value, isSelected,
    					    expanded, leaf, row, false);
            Font font = tree.getFont();
            FontRenderContext frc = new FontRenderContext(null, false, false);
            int width = (int)font.getStringBounds(stringValue, frc).getWidth();
            offset += width + hgap;
        }
    
        private class EditorPanel extends JPanel {
            Color treeBGColor;
            Color focusBGColor;
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Color bColor = renderer.getBackgroundSelectionColor();
    
                int imageOffset = -1;
                if(bColor != null) {
                    Icon currentI = label.getIcon();
    
                    imageOffset = renderer.getLabelStart();
                    g.setColor(bColor);
                    g.fillRect(imageOffset, 0, getWidth() - imageOffset,
                               getHeight());
                }
    
                if(renderer.drawsFocusBorderAroundIcon) {
                    imageOffset = 0;
                } else if(imageOffset == -1) {
                    imageOffset = renderer.getLabelStart();
                }
                paintFocus(g, imageOffset, 0, getWidth() - imageOffset,
                           getHeight(), bColor);
            }
    
            private void paintFocus(Graphics g, int x, int y,
                                    int w, int h, Color notColor) {
                Color bsColor = renderer.getBorderSelectionColor();
    
                if (bsColor != null) {
                    g.setColor(bsColor);
                    g.drawRect(x, y, w - 1, h - 1);
                }
                if (renderer.drawDashedFocusIndicator && notColor != null) {
                    if (treeBGColor != notColor) {
                        treeBGColor = notColor;
                        focusBGColor = new Color(~notColor.getRGB());
                    }
                    g.setColor(focusBGColor);
                    BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
                }
            }
        }
    }
    
    class CheckPanelRenderer extends JPanel implements TreeCellRenderer {
        JLabel label;
        JCheckBox checkBox;
        protected boolean selected;
        protected boolean hasFocus;
        public boolean drawsFocusBorderAroundIcon;
        public boolean drawDashedFocusIndicator;
        private Color treeBGColor;
        private Color focusBGColor;
        transient protected Icon closedIcon;
        transient protected Icon leafIcon;
        transient protected Icon openIcon;
        protected Color backgroundSelectionColor;
        protected Color backgroundNonSelectionColor;
        protected Color borderSelectionColor;
    
        public CheckPanelRenderer() {
            loadDefaults();
            label = new JLabel();
            checkBox = new JCheckBox();
            checkBox.setBorder(null);
            checkBox.setBackground(getBackgroundNonSelectionColor());
            setBorder(null);
            setBackground(getBackgroundNonSelectionColor());
            add(label);
            add(checkBox);
        }
    
        private void loadDefaults() {
            setClosedIcon(UIManager.getIcon("Tree.closedIcon"));
            setLeafIcon(UIManager.getIcon("Tree.leafIcon"));
            setOpenIcon(UIManager.getIcon("Tree.openIcon"));
            setBackgroundSelectionColor(UIManager.getColor(
                                            "Tree.selectionBackground"));
            setBackgroundNonSelectionColor(UIManager.getColor(
                                               "Tree.textBackground"));
            setBorderSelectionColor(UIManager.getColor(
                                        "Tree.selectionBorderColor"));
            Object value = UIManager.get("Tree.drawsFocusBorderAroundIcon");
            drawsFocusBorderAroundIcon =
                (value != null && ((Boolean)value).booleanValue());
            value = UIManager.get("Tree.drawDashedFocusIndicator");
            drawDashedFocusIndicator = 
                (value != null && ((Boolean)value).booleanValue());
        }
    
        public void setClosedIcon(Icon newIcon) {
            closedIcon = newIcon;
        }
    
        public Icon getClosedIcon() { return closedIcon; }
    
        public void setLeafIcon(Icon newIcon) {
            leafIcon = newIcon;
        }
    
        public Icon getLeafIcon() {	return leafIcon; }
    
        public void setOpenIcon(Icon newIcon) {
            openIcon = newIcon;
        }
    
        public Icon getOpenIcon() { return openIcon; }
    
        public void setBackgroundSelectionColor(Color newColor) {
            backgroundSelectionColor = newColor;
        }
    
        public Color getBackgroundSelectionColor() {
            return backgroundSelectionColor;
        }
    
        public void setBackgroundNonSelectionColor(Color newColor) {
            backgroundNonSelectionColor = newColor;
            treeBGColor = newColor;
        }
    
        public Color getBackgroundNonSelectionColor() {
            return backgroundNonSelectionColor;
        }
    
        public void setBorderSelectionColor(Color newColor) {
            borderSelectionColor = newColor;
        }
    
        public Color getBorderSelectionColor() {
            return borderSelectionColor;
        }
    
        public Component getTreeCellRendererComponent(JTree tree,
                                                      Object value,
                                                      boolean selected,
                                                      boolean expanded,
                                                      boolean leaf,
                                                      int row,
                                                      boolean hasFocus) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
            CheckStore cs = (CheckStore)node.getUserObject();
            label.setText(cs.toString());
            checkBox.setSelected(cs.getState());
    
            this.selected = selected;
            this.hasFocus = hasFocus;
            if(leaf) {
                label.setIcon(getLeafIcon());
            } else if(expanded) {
                label.setIcon(getOpenIcon());
            } else {
                label.setIcon(getClosedIcon());
            }
            return this;
        }
    
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Color bColor;
            if(selected) {
                bColor = getBackgroundSelectionColor();
            } else {
                bColor = getBackgroundNonSelectionColor();
                if (bColor == null) {
                    bColor = getBackground();
                }
            }
    
            int imageOffset = -1;
            if(bColor != null) {
                Icon currentI = label.getIcon();
    
                imageOffset = getLabelStart();
                g.setColor(bColor);
                g.fillRect(imageOffset, 0, getWidth() - imageOffset,
                           getHeight());
            }
    
            if(hasFocus) {
                if(drawsFocusBorderAroundIcon) {
                    imageOffset = 0;
                } else if(imageOffset == -1) {
                    imageOffset = getLabelStart();
                }
                paintFocus(g, imageOffset, 0, getWidth() - imageOffset,
                           getHeight(), bColor);
    	}
        }
    
        private void paintFocus(Graphics g, int x, int y,
                                int w, int h, Color notColor) {
            Color bsColor = getBorderSelectionColor();
    
            if (bsColor != null && (selected || !drawDashedFocusIndicator)) {
                g.setColor(bsColor);
                g.drawRect(x, y, w - 1, h - 1);
            }
            if (drawDashedFocusIndicator && notColor != null) {
                if (treeBGColor != notColor) {
                    treeBGColor = notColor;
                    focusBGColor = new Color(~notColor.getRGB());
                }
                g.setColor(focusBGColor);
                BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
            }
        }
    
        public int getLabelStart() {
    	Icon currentI = label.getIcon();
    	if(currentI != null && label.getText() != null) {
    	    return currentI.getIconWidth() +
                           Math.max(0, label.getIconTextGap() - 1) + getHgap();
    	}
    	return 0;
        }
    
        public int getIconTextGap() {
            return label.getIconTextGap();
        }
    
        public int getHgap() {
            return ((FlowLayout)getLayout()).getHgap();
        }
    }
    
    class CheckStore {
        String text;
        boolean state;
    
        public CheckStore(String text, boolean state) {
            this.text = text;
            this.state = state;
        }
    
        public boolean getState() { return state; }
    
        public String toString() { return text; }
    }

  7. #7
    TrueBear is offline Member
    Join Date
    Jan 2009
    Posts
    5
    Rep Power
    0

    Default Additional questions

    The changes specified to make all nodes in the tree appear as checkboxes in the original sample code code works, but the checked state can't be changed unless the node is a leaf node. It appears that this is because the non-leaf nodes are not initially created as checkbox nodes. I've made changes to the isCellEditable() method in the CheckBoxNodeEditor so that it returns true if the user object from the DefaultMutableTreeNode is non-null and this appears to fix that.

    In my implementation I want to detect when a check box is selected or deselected. If it is a non-leaf node, I want to select or deselect all child nodes. I've also set up a MouseListener to detect when the user clicks over a tree node and this appears to handle the case correctly. However, any non-leaf chlid nodes at this time aren't configured as CheckBoxNodes but as NamedVectors. This change-over doesn't appear to occur until after the user checks on a node. How can the original code be changed so that the nodes created as NamedVectors are created as CheckBoxNodes instead?
    Last edited by TrueBear; 01-20-2009 at 12:32 AM.

  8. #8
    hardwired's Avatar
    hardwired is offline Senior Member
    Join Date
    Jul 2007
    Posts
    1,576
    Rep Power
    9

    Default

    The changes specified to make all nodes in the tree appear as checkboxes in the original sample code code works, but the checked state can't be changed unless the node is a leaf node.
    In the code posted in #6 all nodes have checkBoxes and can be edited as–is.

    It appears that this is because the non-leaf nodes are not initially created as checkbox nodes.
    In the #6 code all nodes are created as DefaultMutableTreeNodes with a CheckStore userObject and all nodes are rendered with a checkBox and are editable.

    In my implementation I want to detect when a check box is selected or deselected. If it is a non-leaf node, I want to select or deselect all child nodes.
    See example below for a demonstration of this.

    I've also set up a MouseListener to detect when the user clicks over a tree node and this appears to handle the case correctly. However, any non-leaf chlid nodes at this time aren't configured as CheckBoxNodes but as NamedVectors. This change-over doesn't appear to occur until after the user checks on a node.
    This is not the case with the code in #6 or in the example below.

    How can the original code be changed so that the nodes created as NamedVectors are created as CheckBoxNodes instead?
    They are (all created as checkBox nodes) in the code in #6 above. You may have to copy and paste the #6 code into a new folder, compile and run it there to avoid trouble with old class files. Or you can change all the class names.

    This example:
    • has all nodes with checkBoxes (as before)
    • all checkBoxes are editable (also as before), and
    • editing of any level–one node checkBox results in all of its child node checkBoxes changing to the same state as the parent (unlike before).

    The ExpansionMonitor class has been discarded.
    In its place is the LeafSelectionHandler class.
    There are no changes to the CheckPanelRenderer and CheckStore classes as posted in #6 above.
    Java Code:
    import java.awt.*;
    import java.awt.event.*;
    import java.awt.font.*;
    import java.util.*;
    import javax.swing.*;
    import javax.swing.border.*;
    import javax.swing.event.*;
    import javax.swing.plaf.basic.BasicGraphicsUtils;
    import javax.swing.tree.*;
    
    public class CheckTree {
        private JScrollPane getContent() {
            JTree tree = new JTree(getTreeModel());
            tree.setEditable(true);
            CheckPanelRenderer renderer = new CheckPanelRenderer();
            tree.setCellRenderer(renderer);
            tree.setCellEditor(new CheckPanelEditor(tree, renderer));
            expand(tree);
            return new JScrollPane(tree);
        }
    
        private TreeModel getTreeModel() {
            String[][] ids = {
                { "colors", "blue", "violet", "red", "yellow" },
                { "sports", "basketball", "soccer", "football", "hockey" },
                { "food", "hot dogs", "pizza", "haggis", "bananas" }
            };
            CheckStore store = new CheckStore("JTree", false);
            DefaultMutableTreeNode root = new DefaultMutableTreeNode(store);
            for(int i = 0; i < ids.length; i++) {
                String[] s = ids[i];
                DefaultMutableTreeNode parent =
                    new DefaultMutableTreeNode(new CheckStore(s[0], false));
                root.add(parent);
                DefaultMutableTreeNode n;
                for(int j = 1; j < s.length; j++) {
                    store = new CheckStore(s[j], false);
                    parent.add(n = new DefaultMutableTreeNode(store));
                }
            }
            return new DefaultTreeModel(root);
        }
    
        private void expand(JTree tree) {
            DefaultMutableTreeNode root =
                (DefaultMutableTreeNode)tree.getModel().getRoot();
            Enumeration e = root.breadthFirstEnumeration();
            while(e.hasMoreElements()) {
                DefaultMutableTreeNode node =
                    (DefaultMutableTreeNode)e.nextElement();
                if(node.isLeaf()) continue;
                int row = tree.getRowForPath(new TreePath(node.getPath()));
                tree.expandRow(row);
            }
        }
    
        public static void main(String[] args) {
            CheckTree test = new CheckTree();
            JFrame f = new JFrame();
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.add(test.getContent());
            f.setSize(400,400);
            f.setLocation(200,200);
            f.setVisible(true);
        }
    }
    
    class LeafSelectionHandler {
        JTree tree;
    
        public LeafSelectionHandler(JTree tree) {
            this.tree = tree;
        }
    
        public void checkForNonLeafSelection(TreePath path, boolean selected) {
            Object value = path.getLastPathComponent();
            DefaultMutableTreeNode node =
                (DefaultMutableTreeNode)path.getLastPathComponent();
            if(!node.isLeaf() && node.getLevel() == 1) {
                selectAllChildren(path, selected);
                int[] indices = getChildIndices(node);
                ((DefaultTreeModel)tree.getModel()).nodesChanged(node, indices);
            }
        }
    
        private void selectAllChildren(TreePath path, boolean select) {
            TreeNode node = (TreeNode)path.getLastPathComponent();
            select(node, select);
            if (node.getChildCount() > 0) {
                Enumeration e = node.children();
                while(e.hasMoreElements()) {
                    TreeNode n = (TreeNode)(TreeNode)e.nextElement();
                    selectAllChildren(path.pathByAddingChild(n), select);
                }
            }
        }
    
        private void select(TreeNode node, boolean select) {
            DefaultMutableTreeNode n = (DefaultMutableTreeNode)node;
            CheckStore cs = (CheckStore)n.getUserObject();
            cs.state = select;
        }
    
        private int[] getChildIndices(TreeNode node) {
            int[] indices = new int[node.getChildCount()];
            for(int i = 0; i < indices.length; i++) {
                indices[i] = i;
            }
            return indices;
        }
    }
    
    class CheckPanelEditor extends AbstractCellEditor
                           implements TreeCellEditor, ActionListener {
        JTree tree;
        CheckPanelRenderer renderer;
        LeafSelectionHandler handler;
        JLabel label;
        EditorPanel panel;
        JCheckBox checkBox;
        CheckStore checkStore;
        protected transient int offset;
        protected int clickCountToStart = 1;
    
        public CheckPanelEditor(JTree tree, CheckPanelRenderer cpr) {
            this.tree = tree;
            renderer = cpr;
            handler = new LeafSelectionHandler(tree);
            label = new JLabel();
            checkBox = new JCheckBox();
            checkBox.setBorder(null);
            checkBox.setBackground(renderer.getBackgroundNonSelectionColor());
            checkBox.addActionListener(this);
            checkBox.setRequestFocusEnabled(false);
            panel = new EditorPanel();
            panel.setBorder(null);
            panel.setBackground(renderer.getBackgroundNonSelectionColor());
            panel.add(label);
            panel.add(checkBox);
        }
    
        public Component getTreeCellEditorComponent(JTree tree,
                                                    Object value,
                                                    boolean isSelected,
                                                    boolean expanded,
                                                    boolean leaf,
                                                    int row) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode)value;
            checkStore = (CheckStore)node.getUserObject();
            label.setText(checkStore.toString());
            checkBox.setSelected(checkStore.getState());
    
            if(leaf) {
                label.setIcon(renderer.getLeafIcon());
            } else if(expanded) {
                label.setIcon(renderer.getOpenIcon());
            } else {
                label.setIcon(renderer.getClosedIcon());
            }
            return panel;
        }
    
        public Object getCellEditorValue() {
            checkStore.text = label.getText();
            checkStore.state = checkBox.isSelected();
            return checkStore;
        }
    
        public boolean isCellEditable(EventObject anEvent) {
            if(anEvent != null && anEvent instanceof MouseEvent &&
                  ((MouseEvent)anEvent).getClickCount() >= clickCountToStart) {
                TreePath path = tree.getPathForLocation(
                                     ((MouseEvent)anEvent).getX(),
                                     ((MouseEvent)anEvent).getY());
                int row = tree.getRowForPath(path);
                Object value = path.getLastPathComponent();
                boolean isSelected = tree.isRowSelected(row);
                boolean expanded = tree.isExpanded(path);
                boolean leaf = tree.getModel().isLeaf(value);
                determineOffset(tree, value, isSelected, expanded, leaf, row);
                Rectangle pb = tree.getPathBounds(path);
                Rectangle target = new Rectangle(offset, pb.y,
                                                 pb.x+pb.width-offset,
                                                 pb.height);
                Point p = ((MouseEvent)anEvent).getPoint();
                if(target.contains(p)) {
    	        tree.startEditingAtPath(path);
                    return true;
                }
            }
            return false;
        }
    
        public void actionPerformed(ActionEvent e) {
            TreePath path = tree.getEditingPath();
            super.stopCellEditing();
            handler.checkForNonLeafSelection(path, checkBox.isSelected());
        }
    
        protected void determineOffset(JTree tree, Object value,
                                 boolean isSelected, boolean expanded,
                                 boolean leaf, int row) {
            int x0 = tree.getPathBounds(tree.getPathForRow(row)).x;
            int hgap = renderer.getHgap();
            offset = x0 + hgap;
            Icon editingIcon = null;
            if(leaf)
                editingIcon = renderer.getLeafIcon();
            else if(expanded)
                editingIcon = renderer.getOpenIcon();
            else
                editingIcon = renderer.getClosedIcon();
            if(editingIcon != null)
                offset += editingIcon.getIconWidth() +
                              renderer.getIconTextGap();
    	String stringValue = tree.convertValueToText(value, isSelected,
    					    expanded, leaf, row, false);
            Font font = tree.getFont();
            FontRenderContext frc = new FontRenderContext(null, false, false);
            int width = (int)font.getStringBounds(stringValue, frc).getWidth();
            offset += width + hgap;
        }
    
        private class EditorPanel extends JPanel {
            Color treeBGColor;
            Color focusBGColor;
    
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Color bColor = renderer.getBackgroundSelectionColor();
    
                int imageOffset = -1;
                if(bColor != null) {
                    Icon currentI = label.getIcon();
    
                    imageOffset = renderer.getLabelStart();
                    g.setColor(bColor);
                    g.fillRect(imageOffset, 0, getWidth() - imageOffset,
                               getHeight());
                }
    
                if(renderer.drawsFocusBorderAroundIcon) {
                    imageOffset = 0;
                } else if(imageOffset == -1) {
                    imageOffset = renderer.getLabelStart();
                }
                paintFocus(g, imageOffset, 0, getWidth() - imageOffset,
                           getHeight(), bColor);
            }
    
            private void paintFocus(Graphics g, int x, int y,
                                    int w, int h, Color notColor) {
                Color bsColor = renderer.getBorderSelectionColor();
    
                if (bsColor != null) {
                    g.setColor(bsColor);
                    g.drawRect(x, y, w - 1, h - 1);
                }
                if (renderer.drawDashedFocusIndicator && notColor != null) {
                    if (treeBGColor != notColor) {
                        treeBGColor = notColor;
                        focusBGColor = new Color(~notColor.getRGB());
                    }
                    g.setColor(focusBGColor);
                    BasicGraphicsUtils.drawDashedRect(g, x, y, w, h);
                }
            }
        }
    }

  9. #9
    TrueBear is offline Member
    Join Date
    Jan 2009
    Posts
    5
    Rep Power
    0

    Default

    Actually, the example I used in my implementation was it #2 above.

    In this example the check boxes are displayed in place of the component normally displayed as the leaf node. The change that was noted was to change the getTreeCellRendererComponent() method in the CheckBoxNodeRenderer class to always return a leaf node rather than the DefaultTreeCellRenderer for the non-leaf nodes and the JCheckBox for the leaf nodes. This caused all nodes to be displayed as JCheckBox components but the non-leaf nodes were not editable. Changing the isCellEditable() method in the CheckBoxNodeEditor class to return true if the user object returned from the DefaultMutableTreeNode was not null instead of only if it was a leaf node and an instance of a CheckBoxNode fixed this. I've attached the code I'm using so you can see what is going on.

    I'll see if I can use the code you posted to get things working the way I need. In the mean time if anyone can come up with a good solution using the current implementation, please let me know. Thank you all for your help.
    Attached Files Attached Files
    Last edited by TrueBear; 01-21-2009 at 12:18 AM.

  10. #10
    hardwired's Avatar
    hardwired is offline Senior Member
    Join Date
    Jul 2007
    Posts
    1,576
    Rep Power
    9

    Default

    Actually, the example I used in my implementation was it #2 above.
    Sorry, I never would have known.

    One of the difficulties with the design you have adopted is the use of the renderer component for editing. Adding a new ItemListener at each edit will cause trouble in time. Add this line in your CheckBoxNodeEditor class and click on a few checkBoxes in the tree to see:
    Java Code:
                if (editor instanceof JCheckBox)
                {
                    ((JCheckBox)editor).addItemListener(itemListener);
                    // There is only one editor so only one listener is
                    // required. Here's a telltale:
                    System.out.println("editor ItemListener count = " +
                           editor.getListeners(ItemListener.class).length);
                }
    You can try this to limit the insanity:
    Java Code:
                if (editor instanceof JCheckBox)
                {
                    JCheckBox cb = (JCheckBox)editor;
                    if(cb.getListeners(ItemListener.class).length == 0)
                    {
                        ((JCheckBox)editor).addItemListener(itemListener);
                    }
                    // There is only one editor so only one listener is
                    // required. Here's a telltale:
                    System.out.println("editor ItemListener count = " +
                           editor.getListeners(ItemListener.class).length);
                }

  11. #11
    TrueBear is offline Member
    Join Date
    Jan 2009
    Posts
    5
    Rep Power
    0

    Default

    OK. What we ended up settling on in our implementation was sort of a compromise between the original design (all nodes as check boxes) vs. all but the top two levels of the tree as check boxes and the top to levels rendered as default JTree nodes. I was able to modify the implementation to display this and everything works except for one thing. Sometimes the text to the right of the check box gets truncated (see attached screen shot). Any ideas from anyone as to why this is happening and how to fix it?
    Attached Thumbnails Attached Thumbnails JcheckBoxes as JTree Nodes-jtree-node-text-problem.jpg  

  12. #12
    TrueBear is offline Member
    Join Date
    Jan 2009
    Posts
    5
    Rep Power
    0

    Default

    I know it's not polite to reply to your own post, but. . .

    I found out what the problem was and was able to implement a solution that I found in another post on another web site. But I'm not sure it is the most optimal. The poster basically said that this is a common problem in rendering custom components as JTree nodes. In his post he set the preffered size of the check box to the preferred size of the JTree in the getTreeCellRendererComponent() method of the class that implemented the JTree's TreeCellRenderer. In the sample code, this class would be the CheckBoxNodeRenderer class.

    The way that I implemented it follows. In the CheckBoxNodeRenderer.getTreeCellRendererComponent( ) method, just before the checkBoxRenderer (i.e., JCheckBox) object is returned as the component to be rendered. I get the font from the check box and get the FontMetrics from the object using the returned font to create it. I then use the SwingUtilities.computeStringWidth() method passing it string to be displayed in the checkbox's text box using to get the computed string width. I then get the preferred size Dimension from the check box, add the text width returned by the computStringWidth() method to the Dimension's width property, and set the check box's preferred size to that. This probably creates a width that is longer than what is actually needed, but it appears to allow for the width of the checkbox and the width of the text properly when the checkbox is rendered as a node in the JTree.

    Attached is the actual code being used.

    Any ideas as to whether or not this is really optimal or is there a more optimal way of doing this?
    Attached Files Attached Files

Similar Threads

  1. nodes in java netowork
    By ahsan in forum Advanced Java
    Replies: 0
    Last Post: 12-26-2007, 04:11 PM
  2. nodes in java
    By ahsan in forum New To Java
    Replies: 0
    Last Post: 12-26-2007, 04:09 PM
  3. linked list nodes all refernce same item.
    By yllawwally in forum New To Java
    Replies: 0
    Last Post: 12-18-2007, 09:45 PM
  4. Replies: 1
    Last Post: 07-26-2007, 08:28 PM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •