Geo Koodi
Geo Koodi

Reputation: 15

How to solve JavaFX ContextMenu source node?

I have multiple CheckBoxes in the user interface I created in the FXML file.

<CheckBox..>
  <contextMenu>
    <ContextMenu>
      <items>
        <MenuItem text="%uncheckall" onAction="#uncheckAll" />
        <MenuItem text="%checkall" onAction="#checkAll" />
      </items>
    </ContextMenu>
  </contextMenu>
</CheckBox>
...

All CheckBoxes use the same methods, i.e. uncheckAll and checkAll. How can I return ContextMenu's source Node i.e. CheckBox in the handling methods from Event?

@FXML private void uncheckAll(Event event) {
  MenuItem mni = (MenuItem)event.getSource();
  ContextMenu cm = mni.getParentPopup();
  ...???
}

Upvotes: 1

Views: 251

Answers (2)

Abra
Abra

Reputation: 20914

There doesn't appear to be anything in the API for obtaining the owner of a Node's context menu, however the ancestor class of ContextMenu has method setUserData. You can set the CheckBox as the user data of the ContextMenu. Here is an example using code only, i.e. not FXML.

CheckBox cb = new CheckBox("check");
MenuItem mi = new MenuItem("menu item");
mi.setOnAction(this::uncheckAll);
ContextMenu cm = new ContextMenu(mi);
cm.setUserData(cb);
cb.setContextMenu(cm);

Then, in your uncheckAll method, you can retrieve the CheckBox via method getUserData.

@FXML private void uncheckAll(Event event) {
    MenuItem mi = (MenuItem) event.getSource();
    ContextMenu cm = mi.getParentPopup();
    CheckBox cb = (CheckBox) cm.getUserData();
}

Edit

In FXML simply add a userData attribute to the ContextMenu tag.

<ContextMenu userData="cbxGroup1">

Upvotes: 1

jewelsea
jewelsea

Reputation: 159416

You probably don’t actually need to work out which checkbox the context menu is attached to.

Your task can probably be accomplished through standard fxml injection into a controller.

Assign the checkbox an fx:id in your fxml:

fx:id="cb"

Inject it in your controller:

@FXML private CheckBox cb;

After the fxml is loaded, you can refer to the check box by name cb anywhere in the controller, including in an event handler implementation.

@FXML private void uncheckAll(Event e) {
    // you can refer to cb directly here.
}

As you have multiple checkboxes in your interface, do all of the above multiple times, including the event handler definition.

If you want to share common processing for the event handlers, you can call a separate method, passing in the reference to the checkbox associated with the event handler.

@FXML private CheckBox cb1;
@FXML private CheckBox cb2;

@FXML private void uncheckAllForCb1(Event e) {
    uncheckAll(cb1);
}

@FXML private void uncheckAllForCb2(Event e) {
    uncheckAll(cb2);
}

private void uncheckAll(CheckBox sourceBox) {
    // take action for box.
}

Upvotes: 0

Related Questions