Search code examples
javatreeviewcelljavafx-2

JavaFX 2.0 TreeView ContextMenu


I´m currently working on a TreeView and want to implement a ContextMenu which pops up on rightClick on a TreeCell. I´ve studied the examples but I´m not sure of how I can set the ContextMenu to popup on every cell, not just the ones that are filled with children.

Here my code (pretty much the sample code):

Constructor
.
.
.

this.setCellFactory(new Callback<TreeView<String>,TreeCell<String>>()
    {
            @Override
            public TreeCell<String> call(TreeView<String> p) 
            {
                return new TextFieldTreeCellImpl();
            }
        });
    }

    private final class TextFieldTreeCellImpl extends TreeCell<String> 
    {

        private TextField textField;
        private ContextMenu addMenu = new ContextMenu();

        @SuppressWarnings({ "rawtypes", "unchecked" })
    public TextFieldTreeCellImpl() 
        {
            MenuItem addMenuItem = new MenuItem("Add Note");
            addMenu.getItems().add(addMenuItem);
            addMenuItem.setOnAction(new EventHandler() 
            {
                public void handle(Event t) 
                {
                    ImageView noteIcon = new ImageView(new Image(getClass().getResourceAsStream("../icons/note.png")));
            noteIcon.setFitHeight(16);
            noteIcon.setFitWidth(16);

                    TreeItem newNote = new TreeItem<String>("New Note");
                    getTreeItem().getChildren().add(newNote);
                }
            });
        }

        @Override
        public void startEdit() 
        {
            super.startEdit();

            if (textField == null) 
            {
                createTextField();
            }
            setText(null);
            setGraphic(textField);
            textField.selectAll();
        }

        @Override
        public void cancelEdit() 
        {
            super.cancelEdit();

            setText((String) getItem());
            setGraphic(getTreeItem().getGraphic());
        }

        @Override
        public void updateItem(String item, boolean empty) 
        {
            super.updateItem(item, empty);

            if (empty) 
            {
                setText(null);
                setGraphic(null);
            } 
            else
            {
                if (isEditing()) 
                {
                    if (textField != null) 
                    {
                        textField.setText(getString());
                    }
                    setText(null);
                    setGraphic(textField);
                } 
                else 
                {
                    setText(getString());
                    setGraphic(getTreeItem().getGraphic());
                    if (!getTreeItem().isLeaf()&&getTreeItem().getParent()!= null)
                    {
                        setContextMenu(addMenu);
                    }
                }
            }
        }

        private void createTextField() 
        {
            textField = new TextField(getString());
            textField.setOnKeyReleased(new EventHandler<KeyEvent>() 
            {
                @Override
                public void handle(KeyEvent t) 
                {
                    if (t.getCode() == KeyCode.ENTER) 
                    {
                        commitEdit(textField.getText());
                    } 
                    else if (t.getCode() == KeyCode.ESCAPE) 
                    {
                        cancelEdit();
                    }
                }
            });     
        }

        private String getString() 
        {
            return getItem() == null ? "" : getItem().toString();
        }
    }
}

Solution

  • Showing contextMenu to "filled with children" cells only is controlled with lines:

    if (!getTreeItem().isLeaf() && getTreeItem().getParent() != null) {
        setContextMenu(addMenu);
    }
    

    remove if control to popup contextMenu to all nodes/cells.