JavaFX 8-锚定TableView列ContextMenu紧靠列的标题下方?

时间:2014-12-29 21:51:31

标签: javafx tableview javafx-8

我试图在表格列的上下文菜单中放置一些节点控件。但是,当我右键单击表头以触发ContextMenu时,它会将左上角放在光标位置上。有没有一种简单的方法可以将ContextMenu的左上角锚定到TableHeader的左下角?我无法在TableView的属性中的任何位置找到表头。

ContextMenu contextMenu = new ContextMenu();
contextMenu.setAnchorLocation(... what do I anchor to?);

contextMenu.getItems().add(FilterPanel.getInMenuItem(this));
tableColumn.setContextMenu(contextMenu);

此外,有没有办法允许用户通过拖动来调整ContextMenu的大小?

1 个答案:

答案 0 :(得分:2)

不幸的是,对于我的解决方案,我不得不深入研究TableView皮肤。

首先我们必须注册TableView皮肤,因此我们会在设置后立即收到通知:

tableView.skinProperty().addListener((w, o, n) -> {
    if (n instanceof TableViewSkin) {
        TableViewSkin<?> skin = (TableViewSkin<?>) n;
            checkChangeContextMenu(skin, column);
    }
});

其次我们有魔法代码:

private static void checkChangeContextMenu(TableViewSkin<?> skin, TableColumn<?, ?> column) {
    NestedTableColumnHeader header = skin.getTableHeaderRow()
            .getRootHeader();
    header.getColumnHeaders().addListener((Observable obs) -> changeContextMenu(header,column));
    changeContextMenu(header, column);
}

private static void changeContextMenu(NestedTableColumnHeader header, TableColumn<?, ?> column) {
    TableColumnHeader headerSkin = scan(column, header);
    if (headerSkin != null) {
        headerSkin.setOnContextMenuRequested(ev -> {
            ContextMenu cMenu = column.getContextMenu();
            if (cMenu != null) {
                cMenu.show(headerSkin, Side.BOTTOM, 5, 5);
            }
            ev.consume();
        });
    }
}

private static TableColumnHeader scan(TableColumn<?, ?> search,
        TableColumnHeader header) {
    // firstly test that the parent isn't what we are looking for
    if (search.equals(header.getTableColumn())) {
        return header;
    }

    if (header instanceof NestedTableColumnHeader) {
        NestedTableColumnHeader parent = (NestedTableColumnHeader) header;
        for (int i = 0; i < parent.getColumnHeaders().size(); i++) {
            TableColumnHeader result = scan(search, parent
                    .getColumnHeaders().get(i));
            if (result != null) {
                return result;
            }
        }
    }

    return null;
}

基本上我们在这里做的是:

  1. 注册TableHeader皮肤更新
  2. 搜索TableColumn
  3. 的皮肤
  4. 更改ContextMenu从鼠标坐标绝对定位到TableColumnHeader皮肤下方相对位置的行为。