Details
-
Bug
-
Status: Resolved
-
P2
-
Resolution: Fixed
-
10
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);
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);