Question

This is a follow up question based on TreeView in a table cell Java FX 8

I am having a table in which a particular column has to popup a treeview on click.

I am defining the table column's cellfactory as follows

        col4.setCellFactory(new Callback<TableColumn<User,DepartmentTree>, TableCell<User,DepartmentTree>>() {

        @Override
        public TableCell<User, DepartmentTree> call(
                TableColumn<User,DepartmentTree> param)
        {   
            TableCell<User, DepartmentTree> deptCombo = new TableCell<User,DepartmentTree>()
            {
                @Override                   
                public void startEdit()
                {
                    setGraphic(testtree);
                }

                @Override
                public void cancelEdit()
                {
                    setGraphic(null);
                    setText("");
                }

                @Override
                public void updateItem(DepartmentTree item, boolean empty)
                {

                    super.updateItem(item, empty);
                    setText(item.nameProperty().get());

                }


            };
            return deptCombo;
        }
    });

This is resulting in the treeview appearing inside the cell as per the first image. However I would like the treeview to popout of the cell like the second image (the second image is an incorrect implementation using the treeview inside a combobox)

Does the popout appear by mere styling or do I have to modify any code?

Any guidance will be helpful.

Was it helpful?

Solution

enter image description hereI have created my own class of TreeViewPopupTableCell to do this. Basically what you get is, when a table cell is left clicked (first click will choose the row,second will choose the cell) you get a popup with a treeview loaded in it.

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.control.PopupControl;
import javafx.scene.control.Skin;
import javafx.scene.control.Skinnable;
import javafx.scene.control.TableCell;
import javafx.scene.control.TreeItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;

public class TreeViewPopupTableCell<S, T extends HierarchyData<T>> extends
        TableCell<S, T>
{
    private static final String DEFAULT_STYLE_CLASS = "combo-box-popup";
    private PopupControl popup;
    private TreeViewWithSetItems<T> treeviewSetItems;
    private static final Logger log = Logger.getLogger(TreeViewPopup.class);
    private ObservableList<T> treeList;
    private double popupXlocation = 0.0;
    private double popupYlocation = 0.0;

    public TreeViewPopupTableCell(T hierarchyObj)
    {
        treeviewSetItems = new TreeViewWithSetItems<>(new TreeItem<T>());
        treeList = FXCollections.observableArrayList();
        treeList.add(hierarchyObj);
        treeviewSetItems.setShowRoot(false);
        treeviewSetItems.setItems(treeList);
        treeviewSetItems.getStyleClass().add(DEFAULT_STYLE_CLASS);

        this.addEventHandler(MouseEvent.MOUSE_CLICKED,
                new EventHandler<MouseEvent>() {

                    @Override
                    public void handle(MouseEvent event)
                    {
                        popupXlocation = event.getScreenX();
                        popupYlocation = event.getScreenY();
                    }
                });
        treeviewSetItems.addEventHandler(KeyEvent.KEY_PRESSED,
                new EventHandler<KeyEvent>() {

                    @Override
                    public void handle(KeyEvent event)
                    {
                        if (event.getCode().equals(KeyCode.ESCAPE))
                        {

                            popup.hide();
                        }
                    }
                });

        treeviewSetItems.getSelectionModel().selectedItemProperty()
                .addListener(new ChangeListener<TreeItem<T>>() {

                    @Override
                    public void changed(
                            ObservableValue<? extends TreeItem<T>> observable,
                            TreeItem<T> oldValue, TreeItem<T> newValue)
                    {
                        if (oldValue == null)
                            return;
                        log.debug("Value changed");
                        popup.hide();
                        commitEdit(newValue.getValue());
                    }

                });

    }

    @Override
    public void startEdit()
    {

        T ChosenObject = this.getTableColumn().getCellData(
                this.getTableRow().getIndex());
        treeviewSetItems.getSelectionModel().select(
                treeviewSetItems.getindexofItem(ChosenObject));
        popup = new PopupControl();
        popup.getStyleClass().add(DEFAULT_STYLE_CLASS);
        popup.setAutoHide(true);
        popup.setAutoFix(true);

        popup.setHideOnEscape(true);
        popup.setX(popupXlocation);
        popup.setY(popupYlocation);
        popup.setSkin(new Skin<Skinnable>() {
            @Override
            public Skinnable getSkinnable()
            {
                return null;
            }

            @Override
            public Node getNode()
            {
                return treeviewSetItems;
            }

            @Override
            public void dispose()
            {
            }
        });
        popup.show(this.getScene().getWindow());
    }

    @Override
    public void cancelEdit()
    {
        log.debug("Cancel edit is being called");
    }


    @Override
    public void updateItem(T item, boolean empty)
    {
        super.updateItem(item, empty);
        setText(item.nameProperty().get());
    }

}

public interface HierarchyData<T extends HierarchyData> {
    /**
     * The children collection, which represents the recursive nature of the hierarchy.
     * Each child is again a {@link HierarchyData}.
     *
     * @return A list of children.
     */
    ObservableList<T> getChildren();
    StringProperty nameProperty();
}

To use this cell, in your tableview set the cellfactory as follows.

col4.setCellFactory(new Callback<TableColumn<S,T>, TableCell<S,T>>() {

    @Override
    public TableCell<S, T> call(
            TableColumn<S,T> param)
    {   
        return new TreeViewPopupTableCell<S, T>(T obj);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top