Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8219620

Menu: must update items on modifying the list while showing

    Details

      Description

       Issue: modifying the items of a Menu (aka: submenu) while it is showing
       does not update the items shown. For comparison: modifying the list of
       direct items of the contextMenu is working as expected.

       To reproduce, compile the example below, run:
       A: see tab "subMenu"
       - right click in button the show contextmenu
       - move mouse over menu to open submenu and make sure it remains open during the steps below
       - press f1
       - expected: first item of open submenu visibly removed
       - actual: no visual change
       - to verify that items are removed from the items list, press f1 until message "empty" is printed

       for comparison, see tab "direct" and do the same:
       - as expected, items are visibly removed from the showing popup
       
      The issue turned up in a question at SO: https://stackoverflow.com/q/54834206/203657

      The culprit seems to be ContextMenuContent that is responsible for opening/hiding submenus - it does so by calling:

          private void showSubmenu(Menu menu) {
              openSubmenu = menu;
              createSubmenu();
              submenu.getItems().setAll(menu.getItems());
              submenu.show(selectedBackground, Side.RIGHT, 0, 0);
          }

      note that the items of the subMenu (== ContextMenu that's showing the items of the menu) is set once to the items of the menu, without registering any listeners: so removing the items from Menu's items doesn't keep the items of the subMenu in sync.

      A dirty (! and beware: not tested for side-effects) hack around is to

      - grab the ContextMenuContent for the menu (that is the content that contains menu)
      - reflectively access its private field subMenu
      - when changing the items in menu, reset the items in subMenu to the same

      public class MenuModifyItemsWhileShowing extends Application {

          protected Node createTabContent(boolean asSubMenu) {
              final List<String> options = Arrays.asList(
                      "AbC",
                      "dfjksdljf",
                      "skdlfj",
                      "stackoverflow");

              ContextMenu cmenu = new ContextMenu();
              List<MenuItem> items;;
              if (asSubMenu) {
                  //---------- submenu: bug
                  final Menu menu = new Menu("MENU");
                  cmenu.getItems().setAll(menu);
                  items = menu.getItems();
              } else {
                  // for comparison: directly added - behaves as expected
                  items = cmenu.getItems();
              }
              options.stream().map(MenuItem::new).forEach(items::add);

              Button button = new Button("for contextMenu");
              button.setContextMenu(cmenu);
              // on pressing f1, remove first menuItem until list empty
              cmenu.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
                  if (e.getCode() == KeyCode.F1) {
                      if (!items.isEmpty()) {
                          items.remove(0);
                      } else {
                          System.out.println("no more items");
                      }
                  }
              });
              return button;
          }

          private Parent createContent() {
              TabPane pane = new TabPane();
              pane.getTabs().addAll(
                      new Tab("subMenu", createTabContent(true)),
                      new Tab("direct", createTabContent(false)));
              return pane;
          }

          @Override
          public void start(Stage stage) throws Exception {
              stage.setScene(new Scene(createContent()));
              stage.setTitle(FXUtils.version());
              stage.show();
          }

          public static void main(String[] args) {
              launch(args);
          }
          
      }


        Attachments

          Activity

            People

            • Assignee:
              aghaisas Ajit Ghaisas
              Reporter:
              fastegal Jeanette Winzenburg
            • Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated: