TableView JavaFX中的上下文菜单可见性

TableView JavaFX中的上下文菜单可见性,java,contextmenu,tableview,javafx-2,javafx,Java,Contextmenu,Tableview,Javafx 2,Javafx,我正在用JavaFX创建TableView。在其中,我想在tableView中用鼠标右键单击来显示上下文菜单。因此,我在表中添加了一个EventHandler,如下所示: TableView tableView=new TableView(); EventHandler event = new EventHandler<MouseEvent>() { @Override public void handle(MouseEvent me

我正在用JavaFX创建
TableView
。在其中,我想在tableView中用鼠标右键单击来显示
上下文菜单
。因此,我在表中添加了一个EventHandler,如下所示:

    TableView tableView=new TableView();

    EventHandler event = new EventHandler<MouseEvent>() {
        @Override
        public void handle(MouseEvent me) {
            if (me.getButton() == MouseButton.SECONDARY) {
                tableView.getContextMenu().show(tableView, me.getSceneX(), me.getSceneY());
            }
        }
    };
    tableView.addEventHandler(MouseEvent.MOUSE_CLICKED, event);
TableView TableView=newtableview();
EventHandler事件=新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent me){
if(me.getButton()==MouseButton.SECONDARY){
tableView.getContextMenu().show(tableView,me.getSceneX(),me.getSceneY());
}
}
};
tableView.addEventHandler(MouseEvent.MOUSE_单击,事件);
但我的问题是,
上下文菜单
在我右键单击表的任何部分时都可见

我想这样做,
上下文菜单
应该只有在我点击了
TableView
中的任何行时才可见


i、 e.如何在特定点获取TableView中的行号,以便我的
上下文菜单
仅在单击
TableView
的任何行时才可见,而不是在整个表格中使用
CellFactory
将上下文菜单添加到特定单元格中

例如,使用以下表格:

TableColumn firstNameCol=newtableColumn();
firstNameCol.setText(“第一”);
firstNameCol.setCellValueFactory(新属性ValueFactory(“firstName”));
firstNameCol.setCellFactory(新回调(){
@凌驾
公共TableCell调用(最终TableColumn参数){
最终TableCell单元格=新TableCell(){
@凌驾
public void updateItem(对象项,布尔值为空){
super.updateItem(项,空);
if(空){
setText(空);
}否则{
if(isEditing()){
setText(空);
}否则{
setText(getItem().toString());
设置图形(空);
}
}
}
};
//这样,我将只有特定列的上下文菜单
cell.setContextMenu(ContextMenuBuilder.create().items(MenuItemBuilder.create().text(“菜单”).build()).build());
返回单元;
}
});

可能是较老的问题。有一个解决方案,比如获取表的鼠标事件的目标,检查例如类TableCellSkin,并将上下文菜单显示为

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

                    @Override
                    public void handle(MouseEvent e) {
                        if (e.getButton() == MouseButton.SECONDARY
                                && !isRowEmpty) {
                            EventTarget target = e.getTarget();
                            if (target instanceof TableCellSkin
                                    || ((Node) target).getParent() instanceof TableCellSkin) {
                                    // do your stuff. Context menu will be displayed by default
                            } else {
                                // hide the context menu when click event is outside table row
                                table.getContextMenu().hide();
                            }
                        }
                    }
                });
table.addEventHandler(MouseEvent.MOUSE_单击,
新的EventHandler(){
@凌驾
公共无效句柄(MouseEvent e){
如果(例如getButton()==MouseButton.SECONDARY
&&!IsRowepty){
EventTarget=e.getTarget();
if(TableCellSkin的目标实例)
||((节点)target.getParent()TableCellSkin实例){
//完成你的任务。默认情况下将显示上下文菜单
}否则{
//当单击事件位于表行之外时隐藏关联菜单
table.getContextMenu().hide();
}
}
}
});

我找到的最佳解决方案是检查y坐标是否超出列标题的边界,然后显式显示菜单

ContextMenu visibleMenu = null;
tableView.setOnMouseClicked((MouseEvent e) -> {
    if (visibleMenu !=null) {
        visibleMenu.hide();
        visibleMenu = null;
    }
    if (e.getButton()==MouseButton.SECONDARY) {
        double columnHeaderHeight = tableView.lookup(".column-header-background").getBoundsInLocal().getHeight();
        if (e.getY()>columnHeaderHeight) {
            visibleMenu = getContextMenu(); // build on the fly or use a prebuild menu
            visibleMenu.show(tableView, e.getScreenX(), e.getScreenY());
        } else {
            // you could show a header specific context menu here
        }
    }
});
附加的好处是,您可以使用上下文敏感项动态构建上下文菜单(例如,仅当选择了特定类型的单元格时才会显示),或者只需像setContextMenu那样重用预构建上下文菜单,具体取决于您

配音。我看到tableView.getContextMenu()所以在其他地方您正在设置contextmenu。如果您设置它,即使您没有显式添加事件处理程序,它也将始终显示。我的意思是如果你想控制contextmenu的显示,不要通过tableView.setContextMenu(),IMHO设置它。
ContextMenu visibleMenu = null;
tableView.setOnMouseClicked((MouseEvent e) -> {
    if (visibleMenu !=null) {
        visibleMenu.hide();
        visibleMenu = null;
    }
    if (e.getButton()==MouseButton.SECONDARY) {
        double columnHeaderHeight = tableView.lookup(".column-header-background").getBoundsInLocal().getHeight();
        if (e.getY()>columnHeaderHeight) {
            visibleMenu = getContextMenu(); // build on the fly or use a prebuild menu
            visibleMenu.show(tableView, e.getScreenX(), e.getScreenY());
        } else {
            // you could show a header specific context menu here
        }
    }
});