Pane 上的上下文菜单正确消失

Context menu on Pane that disappears correctly

我正在尝试让 JavaFX Pane(在我的例子中是 VBox,但我认为这不重要),它的 ContextMenu 行为正确。

我找到了这两个问题:why Panes can't have ContextMenus and How to create ContextMenu within a Pane

我在这两个解决方案(非常相似)中遇到的问题是,如果我单击窗格,上下文菜单会正确消失,但如果我在该窗格中的控件内单击,它不会消失.观察此缺陷的最简单方法是创建一个带有 TextField 的窗格。右键单击窗格以显示上下文菜单,然后在内部单击 TextField 以聚焦它。虽然此时适当的上下文菜单会消失,但此 "hacked-in" 上下文菜单(由于缺少更好的术语)很乐意留在原处,可能会阻止用户查看他们试图填写的文本字段。

现在,我知道我可以向窗格中每个控件的 focused 属性 添加一个更改侦听器,但这感觉是多余的。是否有更好的方法来确保在选择我的窗格中的控件时隐藏上下文菜单(或者更准确地说 - 当用户在上下文菜单之外的拥有 window 中的任意位置单击鼠标时)?

到目前为止我尝试过但没有用的 -

  1. 向窗格的 focused 添加更改侦听器 属性 - 如果其中一个子项是
  2. ,则该窗格似乎未被视为焦点
  3. 向上下文菜单的 focused 添加更改侦听器 属性 - 在上下文菜单外部单击时,上下文菜单的焦点似乎没有改变。

好的,所以在对 JavaFX 的源代码进行一些挖掘之后,我找到了这个解决方法(这就是 "solves" 普通控件的这个问题)。只需添加这行代码 -

contextMenu.setImpl_showRelativeToWindow(true);

现在,我知道不鼓励使用内部实现方法,因为它们可能会消失,但这是我找到的唯一解决方案。如果有人有更好的解决方案,我会很高兴听到它,但我怀疑这只是一个应该提交的错误(即 - 在窗格上设置上下文菜单时应该有一种使用 showRelativeToWindow 机制的方法).

我想一个更安全的解决方案是使用一次性控件(不在场景图中)来设置上下文菜单,但我不知道这是否会产生任何不需要的副作用:

Label throwaway = new Label(); // No special reason for using Label, could be any Control. 
throwaway.setContextMenu(contextMenu); // note that this is the only place `throwaway` is used, it is never added to the scene graph 
                                       // or referenced again, but just setting the context menu on a control solves the problem.

编辑
在进一步挖掘之后,我发现了 this,以及讨论中的一个解决方案 - 您应该调用 show 方法重载,它采用 window,而不是节点!不是很清楚,但它有效:

myPane.setOnContextMenuRequested(event -> 
    contextMenu.show(myPane.getScene().getWindow(), event.getScreenX(), event.getScreenY())
);