Itai
Itai

Reputation: 6911

Context menu on Pane that disappears correctly

I am trying to have a JavaFX Pane (VBox in my case, but I don't think it matters) that has a ContextMenu that behaves correctly.

I have found these two questions: why Panes can't have ContextMenus and How to create ContextMenu within a Pane.

The problem I'm having with these two solutions (which are very similar) is that while the context menu correctly disappears if I click on the pane, it doesn't disappear if I click inside a control within that pane. The simplest way to observe this flaw is to create such a pane with a TextField. Right-click on the pane to show the context menu, then click inside to TextField to focus on it. While a proper context menu would disappear at this point, this "hacked-in" context menu (for lack of a better term) happily stays in it's place, possibly blocking the user's view of the text field they are trying to fill.

Now, I know I can add a change listener to the focused property of each and every control on my pane, but that feels redundant. Is there a better way to make sure the context menu is hidden when a control in my pane is selected (or, more accurately - when the user click the mouse anywhere in the owning window outside the context menu)?

What I tried so far and doesn't work -

  1. Adding a change listener to the pane's focused property - it appears the pane isn't considered focused if one of it's children is
  2. Adding a change listener to the context menu's focused property - it appears the context menu's focus isn't changed when clicking outside of it.

Upvotes: 2

Views: 877

Answers (1)

Itai
Itai

Reputation: 6911

Ok, so after some digging in the source code for JavaFX I have found this workaround (which is what "solves" this problem for normal controls). Simply add this line of code -

contextMenu.setImpl_showRelativeToWindow(true);

Now, I know using internal implementation methods is discouraged as they may disappear, but this is the only solution I have found. If anyone has a better solution I'll be glad to hear it, but I suspect this is simply a bug that should be filed (i.e. - there should be a way to use the showRelativeToWindow mechanism when setting context menus on panes).

I guess a somewhat safer solution would be to have a throwaway control (not in the scene graph) on which to set the context menu, but I don't know if this would have any unwanted side effects:

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.

Edit
After digging some more I have found this, and a solution in the discussion - you should call the show method overload which takes a window, not a node! Not very clear, but it works:

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

Upvotes: 5

Related Questions