2

A JTree uses TreeCellRenderer and TreeCellEditor to display three custom nodes:

  • a single JCheckBox
  • a single JButton
  • a JPanel composed by any action Component (here is a JCheckBox on North and a JButton on South)

screenshot: https://i.stack.imgur.com/ZNMDx.png

There is no problem with such a tree if you use Java Runtime Environment 6.

Besides using Java Runtime Environment 7, my problem occurs when I click on the JButton inside the JPanel node. The 'click' animation for JButton is not rendered the first time you click in JPanel (and after each time the node with JPanel stops being edited). The first node JCheckBox and the second node JButton are working perfectly with jre6 and jre7 either.

I would like to make it work exactly like before in jre6, is there a workaround?

Note: it's not a problem on making a button perform your code.

import java.awt.BorderLayout;
import java.awt.Component;
import javax.swing.AbstractCellEditor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeCellRenderer;

class TreeNodeModel{
    public boolean isJCheckBox = false;
    public boolean isJButton = false;
    public boolean isJPanel = false;
    public Component userObject = null;
    public TreeNodeModel(String name){
        if( name.equals("JCheckBox") ){
            isJCheckBox = true;
        }else if( name.equals("JButton") ){
            isJButton = true;
        }else if( name.equals("JPanel") ){
            isJPanel = true;
        }
    }
}

class CustomTreeCellRenderer implements TreeCellRenderer{
    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) {
        Component returnValue = null;
        if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
            Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
            if (userObject instanceof TreeNodeModel) {
                TreeNodeModel node = (TreeNodeModel) userObject;
                if(node.isJButton){
                    returnValue = new JButton("Ok");
                }else if(node.isJCheckBox){
                    returnValue = new JCheckBox("Ok");
                }else{
                    JPanel panel = new JPanel(new BorderLayout());
                    panel.add(new JButton("Problem"), BorderLayout.SOUTH);
                    panel.add(new JCheckBox("Problem"), BorderLayout.NORTH);
                    returnValue = panel;
                }
            }
        }
        if(returnValue == null)
            returnValue = new DefaultTreeCellRenderer().getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
        return returnValue;
    }
}

class CustomTreeCellEditor extends AbstractCellEditor implements TreeCellEditor {
    public Component getTreeCellEditorComponent(JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row) {
        Component returnValue = null;
        if ((value != null) && (value instanceof DefaultMutableTreeNode)) {
            Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
            if (userObject instanceof TreeNodeModel) {
                TreeNodeModel node = (TreeNodeModel) userObject;
                if(node.isJButton){
                    returnValue = new JButton("Ok");
                }else if(node.isJCheckBox){
                    returnValue = new JCheckBox("Ok");
                }else{
                    JPanel panel = new JPanel(new BorderLayout());
                    panel.add(new JButton("Problem"), BorderLayout.SOUTH);
                    panel.add(new JCheckBox("Problem"), BorderLayout.NORTH);
                    returnValue = panel;
                }
            }
        }
        return returnValue;
    }
    @Override
    public Object getCellEditorValue() { return null; }
}

public class MyTestRendererEditor extends JFrame {
    public MyTestRendererEditor() { 
        DefaultMutableTreeNode node = new DefaultMutableTreeNode("root");
        node.add(new DefaultMutableTreeNode(new TreeNodeModel("JCheckBox")));
        node.add(new DefaultMutableTreeNode(new TreeNodeModel("JButton")));
        node.add(new DefaultMutableTreeNode(new TreeNodeModel("JPanel")));

        final JTree tree = new JTree(new DefaultTreeModel(node));
        tree.setCellRenderer(new CustomTreeCellRenderer());
        tree.setCellEditor(new CustomTreeCellEditor());
        tree.setEditable(true);

        getContentPane().add(new JScrollPane(tree));
        pack();
        setVisible(true);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
    public static void main(String[] args) { 
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new MyTestRendererEditor();
            }
        });     
    }
}
ron190
  • 1,032
  • 1
  • 17
  • 29
  • 1
    Also consider `Outline`, shown [here](http://codereview.stackexchange.com/a/4447/6692). – trashgod Feb 15 '13 at 02:36
  • I didn't know Outline from NetBeans, it's a great custom component. It seems to confirm that a cell with only one Component in it will work perfectly either with jre6 and jre7 (note: a JTree or JTable with only a JButton works well with jre7). But a cell with a JButton inside a JPanel seems broken since jre7. – ron190 Feb 15 '13 at 11:42

0 Answers0