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

Clicking a JFXPanel having setFocusable(false) causes its processMouseEvent method to loop forever

    XMLWordPrintable

Details

    • b21
    • 10
    • x86_64
    • generic

    Description

      FULL PRODUCT VERSION :
      java version "10" 2018-03-20
      Java(TM) SE Runtime Environment 18.3 (build 10+46)
      Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10+46, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Any OS running Java 10, for example latest Windows 10

      A DESCRIPTION OF THE PROBLEM :
      Clicking a JFXPanel having setFocusable(false) causes its processMouseEvent method to loop forever.

      Depending on the contents of the JFXPanel, the results may be catastrophic. With a JavaFX media player contained in a JFXPanel, the Swing app hangs immediately and after a few seconds I get out of memory errors.

      Please compare:

      Java 10's javafx.swing/javafx/embed/swing/JFXPanel.java
      -----------------------------------------------------------
          @Override
          protected void processMouseEvent(MouseEvent e) {
              if ((e.getID() == MouseEvent.MOUSE_PRESSED) &&
                  (e.getButton() == MouseEvent.BUTTON1)) {
                  if (!hasFocus()) {
                      requestFocus();
                      // this focus request event goes to eventqueue and will be
                      // asynchronously handled so MOUSE_PRESSED event will not be
                      // honoured by FX immediately due to lack of focus in fx
                      // component. Fire the same MOUSE_PRESSED event after
                      // requestFocus() so that 2nd mouse press will be honoured
                      // since now fx have focus
                      AppContext context = SunToolkit.targetToAppContext(this);
                      if (context != null) {
                          SunToolkit.postEvent(context, e);
                      }
                  }
              }

              sendMouseEventToFX(e);
              super.processMouseEvent(e);
          }
      -----------------------------------------------------------

      to:

      Java 9's javafx.swing/javafx/embed/swing/JFXPanel.java
      -----------------------------------------------------------
          @Override
          protected void processMouseEvent(MouseEvent e) {
              if ((e.getID() == MouseEvent.MOUSE_PRESSED) &&
                  (e.getButton() == MouseEvent.BUTTON1)) {
                  if (!hasFocus()) {
                      requestFocus();
                  }
              }

              sendMouseEventToFX(e);
              super.processMouseEvent(e);
          }
      -----------------------------------------------------------


      Obviously with Java 10, if, for any reason (for example because JFXPanel.setFocusable(false)), JFXPanel never gets the focus then processMouseEvent() loops for ever.

      A simple fix is to replace:

      ---
      if (!hasFocus()) {
      ---

      by:

      ---
      if (isFocusable() && !hasFocus()) {
      ---

      Or better, do not bother invoking "requestFocus();" at all because it's the responsiblity of the client code of the JFXPanel to ensure that JavaFX gets the focus (if needed).



      REGRESSION. Last worked in version 9.0.4

      ADDITIONAL REGRESSION INFORMATION:
      It last worked with:

      java version "9.0.4"
      Java(TM) SE Runtime Environment (build 9.0.4+11)
      Java HotSpot(TM) 64-Bit Server VM (build 9.0.4+11, mixed mode)


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1) Compile attached code saved as NonFocusableJFXPanel.java

      javac NonFocusableJFXPanel.java

      2) Run it using Java 10 from a command prompt to see the messages printed by the Swing app

      java -cp . NonFocusableJFXPanel

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      After clicking the button just once, should print :

      1
      ACTUAL -
      After clicking the button just once, prints :

      1
      2
      3
      ...
      4464
      4465
      4466
      ...
      INCREMENTS FOR EVER

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.awt.BorderLayout;
      import javax.swing.SwingUtilities;
      import javax.swing.JPanel;
      import javax.swing.JFrame;
      import javafx.application.Platform;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.embed.swing.JFXPanel;

      /*
       * Compile attached code saved as NonFocusableJFXPanel.java:
       *
       * javac NonFocusableJFXPanel.java
       *
       * Run it from a command prompt to see the messages printed by the Swing app:
       *
       * java -cp . NonFocusableJFXPanel
       *
       * Works fine with Java 1.8.0_162, Java 9.0.4 but not with Java 10.
       */
      public class NonFocusableJFXPanel {
          public static void main(String[] args) {
              SwingUtilities.invokeLater(new Runnable() {
                  public void run() {
                      initAndShowGUI();
                  }
              });
          }

          public static void initAndShowGUI() {
              JFrame frame = new JFrame("NonFocusableJFXPanel");
              frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

              JPanel workArea = (JPanel) frame.getContentPane();

              final JFXPanel fxPanel = new JFXPanel();

              // With Java 10, works fine with .setFocusable(true).
              fxPanel.setFocusable(false);

              workArea.add(fxPanel, BorderLayout.CENTER);

              Platform.runLater(new Runnable() {
                  public void run() {
                      initFX(fxPanel);
                  }
              });

              frame.setSize(600, 200);
              frame.setVisible(true);
          }

          private static int clickCount = 0;

          private static void initFX(JFXPanel fxPanel) {
              Button button = new Button("Click me ONCE and look at your console.");
              button.setOnMousePressed(e -> System.err.println(++clickCount));

              Scene scene = new Scene(button);
              fxPanel.setScene(scene);
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Comment out:

      fxPanel.setFocusable(false);

      or replace it by:

      fxPanel.setFocusable(true);

      Attachments

        Activity

          People

            psadhukhan Prasanta Sadhukhan
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: