Search code examples
javaswingjtree

Refresh JTree without collapsing


I have a tree with a JButton as a node.

I want to be able to toggle the buttons name and the method called by it between two sets of values.

I think this would work fine if the tree would refresh after each button click.

This method seems to work, but it collapses the tree on refreshing, I need the tree to stay open.

I'm not adding/deleting a node so many of the other methods I've seen online do not apply.

public void valueChanged(TreeSelectionEvent e) 
{
    DefaultMutableTreeNode node = (DefaultMutableTreeNode)
            tree.getLastSelectedPathComponent();

    /* if nothing is selected */ 
    if (node == null) return;

    /* retrieve the node that was selected */ 
    Object obj = node.getUserObject();
    if (obj instanceof EmployeeButton)

        EmployeeButton eb = (EmployeeButton) obj;
        if (eb.getText().contains("Add Employee"));
        {
            eb.setText("Remove Employee");
            addEmp(eb.point);
        }
        if (eb.getText().contains("Remove Employee"));
        {
            eb.setText("Add Employee");
            delEmployee(eb.point);
        }
}; 

Solution

  • Using the excellent answer from Jakub Zaverka to a somewhat similar question (Compound JTree Node allowing events to pass through to objects underneath), you could do something like this:

    // Class RefreshTree.java:
    
    import javax.swing.*;
    import javax.swing.tree.*;
    
    public class RefreshTree {
        public static final String ADD_EMPLOYEE = "Add Employee";
        public static final String REMOVE_EMPLOYEE = "Remove Employee";
    
        public static void main(final String[] arguments) {
            new RefreshTree().launchGui();
        }
    
        private void launchGui() {
            final DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode("root");
            rootNode.add(new DefaultMutableTreeNode(ADD_EMPLOYEE));
            rootNode.add(new DefaultMutableTreeNode(ADD_EMPLOYEE));
            rootNode.add(new DefaultMutableTreeNode(ADD_EMPLOYEE));
    
            final JTree tree = new JTree(rootNode);
            tree.setEditable(true);
            tree.setCellRenderer(new ButtonCellRenderer());
            tree.setCellEditor(new ButtonCellEditor());
    
            final JFrame frame = new JFrame("Refresh JTree with JButton");
            frame.getContentPane().add(new JScrollPane(tree));
            frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            frame.setBounds(400, 200, 600, 600);
            frame.setVisible(true);
        }
    }
    
    
    // Class ButtonCellEditor.java:
    
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.tree.*;
    
    public class ButtonCellEditor extends AbstractCellEditor implements TreeCellEditor {
        private JButton button;
    
        public ButtonCellEditor() {
            button = new JButton(RefreshTree.ADD_EMPLOYEE);
            button.addActionListener(actionEvent -> {
                final boolean add = RefreshTree.ADD_EMPLOYEE.equals(button.getText());
                if (add)
                    System.out.println("Call addEmp(eb.point)");
                else
                    System.out.println("Call delEmployee(eb.point)");
                button.setText(add ? RefreshTree.REMOVE_EMPLOYEE : RefreshTree.ADD_EMPLOYEE);
                stopCellEditing();
            });
        }
    
        @Override
        public Object getCellEditorValue() {
            return button.getText();
        }
    
        @Override
        public Component getTreeCellEditorComponent(final JTree tree,
                                                    final Object value,
                                                    final boolean isSelected,
                                                    final boolean expanded,
                                                    final boolean leaf,
                                                    final int row) {
            button.setText(value.toString());
            return button;
        }
    }
    
    
    // Class ButtonCellRenderer.java:
    
    import java.awt.*;
    import javax.swing.*;
    import javax.swing.tree.*;
    
    public class ButtonCellRenderer extends JButton implements TreeCellRenderer {
        @Override
        public Component getTreeCellRendererComponent(final JTree tree,
                                                      final Object value,
                                                      final boolean selected,
                                                      final boolean expanded,
                                                      final boolean leaf,
                                                      final int row,
                                                      final boolean hasFocus) {
            setText(value.toString());
            return this;
        }
    }