I am learning javafx.scene.control.ContextMenu, and right now I am facing a problem:
how do I get the clicked Object from EventHandler? both event.source() and event.target() return the MenuItem.
let me explain with an example: what should I write inside the function handle?
TextField text = new TextField();
Label label1 = new Label("hello");
Label label2 = new Label("world");
Label label3 = new Label("java");
ContextMenu menu = new ContextMenu();
MenuItem item = new MenuItem("copy to text field");
menu.getItems().add(item);
item.setOnAction(new EventHandler(){
public void handle(Event event) {
//I want to copy the text of the Label I clicked to TextField
event.consume();
}
});
label1.setContextMenu(menu);
label2.setContextMenu(menu);
label3.setContextMenu(menu);
EDIT: I was hoping there was some simple solution (one liner), but if there isn't then there are lot's of complex way to do it.
You could create your own instance of ContextMenu and add the action parent to it for further reference:
I think the easiest way is to save the Node as UserData of context menu.
and in action:
To sum up the basic requirement: get hold of the node that a contextMenu was opened for. According to the api doc of PopupWindow (the grandparent of ContextMenu), that should be easy to achieve
show(Node node, ...)
Node getOwnerNode()
So the general approach in the action of a MenuItem is to
The example at the end does just that in copyText and verifies, that it is working as expected ... iff we are not using a control's contextMenuProperty. The reason for the not-working in controls is a method contract violation (probably introduced by a bug fix around auto-hide behavior in textInputControls) of ContextMenu: it always uses the
show(Window w, ..)
after it has been set as contextMenu to any control (implementation detail: Control.contextMenuProperty sets a flagsetShowRelativeToWindow(true)
which triggers the mis-behavior)Now what can we do to get hold of the ownerNode? There are several options, none of which is nice:
show(Node owner, ... )
and keep the given owner in a custom propertyshow(Node owner, ...)
go dirty and reflectively set super ownerNode to the givenThe first two introduce additional coupling, the latter (besides the dirty reflective access) might re-introduce problems with auto-hide (the "fixed" behavior is dirty in itself .. violating the "keep-open-if-owner-clicked" guarantee)
At the end, an example to play with:
Just create a different
ContextMenu
instance for each label: