Search code examples
javafxtreeviewtreecell

JavaFX TreeView adding item to the treeview results the same behavior of the two cells


I am willing to parse an XML Schema Definition and get the TreeView from the parsed file , then adding and removing items from the TreeView before generating an XML .

My issue is when i want to add a TreeItem from a selected one -duplicating it- results in a misbehavior of the two TreeItems : the selected one and the new one.

For example expanding one TreeItem results in expanding the other also .

SchemaTreeCell.java

public class SchemaTreeCell extends TreeCell<SchemaElement> {
GridPane grid = new GridPane();

private JFXButton bt ;
private ContextMenu detailsMenu ;
private TreeItem<SchemaElement> newItem;
private MenuItem showItem ;
private MenuItem addMenuItem;
private MenuItem deleteItem;
public SchemaTreeCell() {
    showItem = new MenuItem("Show Details");
    addMenuItem = new MenuItem("Add Element");
    deleteItem = new MenuItem("Remove Element");
    detailsMenu = new ContextMenu();
    detailsMenu.getItems().add(showItem);
    detailsMenu.getItems().add(addMenuItem);
    detailsMenu.getItems().add(deleteItem);
    bt = new JFXButton("Commit");
    showAction();
    addAction();
    deleteAction();
}


protected void addAction() {
    addMenuItem.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent t) {
            String max = getItem().getMaxOccurs().equals("unbounded")? "100" : getItem().getMaxOccurs();
            if (numberOccurence(getTreeItem())>=Integer.parseInt(max)) {
                Alert alert = new Alert(AlertType.WARNING);
                alert.setHeaderText("Be Careful");
                alert.setContentText("Verify the Max Occurence of this item");
                alert.show();
            }
            else {
                newItem = new TreeItem<>();
                newItem =  getTreeView().getSelectionModel().getSelectedItem();
                getTreeItem().getParent().getChildren().add(newItem);
                addMenuItem.setOnAction(null);      
                t.consume();

            }

        }

    });
}
@Override
protected void updateItem(SchemaElement item, boolean empty) {

    super.updateItem(item, empty);
    if (isEmpty()) {
        setGraphic(null);
        setText(null);
    }else {
    setText(item == null ? ""
            : item.getValue() == null ? "<" + item.getName() + "/>"
                    : "<" + item.getName() + ">" + item.getValue() + "<" + item.
    setContextMenu(detailsMenu);
    }
}

This is how i called the CellFactory

getSchemaView().setCellFactory(new Callback<TreeView<SchemaElement>, TreeCell<SchemaElement>>() {
        @Override
        public TreeCell<SchemaElement> call(TreeView<SchemaElement> list) {
            return new SchemaTreeCell();
        }
    });

Solution

  • You're adding the exact same TreeItem that is already selected to the tree. The TreeItem has the expanded state (and other state that you almost certainly do not want replicated), so if you expand this tree item, both representations will expand.

    Instead, create a new tree item with the same value, and add it to the tree:

    addMenuItem.setOnAction(new EventHandler<ActionEvent>() {
        public void handle(ActionEvent t) {
            String max = getItem().getMaxOccurs().equals("unbounded")? "100" : getItem().getMaxOccurs();
            if (numberOccurence(getTreeItem())>=Integer.parseInt(max)) {
                Alert alert = new Alert(AlertType.WARNING);
                alert.setHeaderText("Be Careful");
                alert.setContentText("Verify the Max Occurence of this item");
                alert.show();
            }
            else {
                newItem = createDeepCopy(getTreeView().getSelectionModel().getSelectedItem());
                getTreeItem().getParent().getChildren().add(newItem);
                addMenuItem.setOnAction(null);      
                t.consume();
    
            }
    
        }
    
    });
    
    // ...
    
    private TreeItem<SchemaElement> createDeepCopy(TreeItem<SchemaElement> original) {
        TreeItem<SchemaElement> copy = new TreeItem<SchemaElement>(original.getValue());
        for (TreeItem<SchemaElement> child : original.getChildren()) {
            copy.getChildren().add(createDeepCopy(child));
        }
        return copy ;
    }