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

TextField: misbehaviour on opening (or not) its default contextMenu

XMLWordPrintable

      The misbehaviour:

      1. the default contextMenu doesn't open on keyboard trigger which is shift-f10 on windows
      2. showing the default contextMenu by mouse doesn't honor the OS custom trigger: hard-coded on released is fine in windows, and wrong in linux (the latter is hear-say only, don't have a box handy ;-)
      3. opening the default context menu by mouse allows multiple context menus to be open (related issue, probably with the same underlying reason: https://javafx-jira.kenai.com/browse/RT-26028

      To reproduce the misbehaviour, run the example

      for 1: (windows only): press shift-f10 and see nothing happening
      for 2: (linux or any OS that opens on press): right-click in textField and see the default context menu open on released
      for 3: right-click in the textfield and see both parent's and the textField's default context menu

      To see the expected behaviour, uncomment the lines setting a custom context menu and do the same as above

      for 1: menu showing on shift-f10
      for 2: menu showing on pressed (hope so ;-)
      for 3: only the textField's context menu is open
       
      The technical reason is that TextFieldBehaviour handles the opening on receiving a mouseEvent, it should use a contextMenuEvent instead.

      It's a bit of a showstopper in complex contextMenu hierarchies: a typical use-case is a parent menu that's shown if the child doesn't have its own. All is fine, if the child uses (and consumes!) the contextMenuEvent so the parent knows it has already been handled. Side-stepping that mechanism, leaves no option (except maybe hacking) for the parent to not show its own (because it simply can't know that a child handled it)

      runnable example:

      /*
       * Created on 12.06.2014
       *
       */
      package chapter4layoutandcontrols;


      import java.util.logging.Logger;

      import javafx.application.Application;
      import javafx.event.EventHandler;
      import javafx.geometry.Insets;
      import javafx.scene.Parent;
      import javafx.scene.Scene;
      import javafx.scene.control.ContextMenu;
      import javafx.scene.control.Label;
      import javafx.scene.control.MenuItem;
      import javafx.scene.control.TextField;
      import javafx.scene.input.ContextMenuEvent;
      import javafx.scene.layout.HBox;
      import javafx.scene.layout.Pane;
      import javafx.stage.Stage;


      /**
       * Issues with default context menu:
      * - does not open on keystroke (shift-f10 on windows)
      * - doesn't consume contextMenuEvents, leading to multiple open contextMenus
      *
       * @author Jeanette Winzenburg, Berlin
       */
      public class ContextMenuExample extends Application {

          private Parent getContent() {
              Label label = new Label("me and ancient queens");
              // BUG: TextField doesn't open default contextMenu on shift-f10
              // implemented in TextFieldBehaviour: uses MouseEvent
              TextField textField = new TextField("some text");
              // a menu installed by client code is handled correctly
              //ContextMenu customMenu = new ContextMenu(new MenuItem("some local action"));
              //textField.setContextMenu(customMenu);
              Pane parent = new HBox(100);
              ContextMenu parentMenu = new ContextMenu(new MenuItem("some parent action"));
              // a handler on the parent that's invoked if none of the children
              // has handled the event
              // reacts to shift-f10, opens on right pressed as expected
              // REMINDER to self: need a handler on the parent because setContextMenu is defined only for
              // Controls
              EventHandler<ContextMenuEvent> paneHandler = e -> {
                  parentMenu.show(parent, e.getScreenX(), e.getScreenY()-100);
                  LOG.info("parentHandler " + e);
              };
              // BUT: if right-pressed in textField with default context, we have two context menus
              parent.addEventHandler(ContextMenuEvent.ANY, paneHandler);
              parent.getChildren().addAll(label, textField);
              parent.setPadding(new Insets(20));
              return parent;
          }

          @Override
          public void start(Stage primaryStage) throws Exception {
              Scene scene = new Scene(getContent());
              primaryStage.setScene(scene);
              primaryStage.show();
          }

          public static void main(String[] args) {
              launch();
          }
          
          @SuppressWarnings("unused")
          private static final Logger LOG = Logger.getLogger(ContextMenuExample.class
                  .getName());
      }

            dgrieve David Grieve
            fastegal Jeanette Winzenburg
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: