Summary
Adds a check for FX application thread to show()
, hide()
(and related methods like showAndWait()
, setShowing()
, close()
, etc.) of Window, Control, and Skin.
These methods will throw an IllegalStageException
if called on a thread other than the FX app thread.
Problem
Most JavaFX objects, such as Node and Scene, can be constructed and modified on any thread unless and until that object is attached to a visible Window. Showing or hiding a Window is an operation that must always be done on the JavaFX application thread as documented in the Window and Stage classes.
Currently, calling these methods in a background thread will lead to exceptions in some cases (but not all) and intermittent failures in others. See JDK-8349004 and JDK-8349096 for an example.
Solution
The solution is to check for the FX application thread and throw an IllegalStageException
if called from any other thread.
Basically, what we are doing is to propagate the already-documented restriction on showing and hiding windows, extending it to popup windows and controls that can show popup windows.
Specification
javafx.controls/src/main/java/javafx/scene/control/ChoiceBox.java
/**
* Opens the list of choices.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show() {
/**
* Closes the list of choices.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void hide() {
javafx.controls/src/main/java/javafx/scene/control/ComboBoxBase.java
/**
- * Requests that the ComboBox display the popup aspect of the user interface.
+ * Requests that the ComboBox display the popup associated with this control.
* As mentioned in the {@link ComboBoxBase} class javadoc, what is actually
* shown when this method is called is undefined, but commonly it is some
* form of popup or dialog window.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show() {
/**
* Closes the popup / dialog that was shown when {@link #show()} was called.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void hide() {
javafx.controls/src/main/java/javafx/scene/control/ContextMenu.java
* <p>
* This function is useful for finely tuning the position of a menu,
* relative to the parent node to ensure close alignment.
+ *
* @param anchor the anchor node
* @param side the side
* @param dx the dx value for the x-axis
* @param dy the dy value for the y-axis
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show(Node anchor, Side side, double dx, double dy) {
* given its size requirements, the necessary adjustments are made to bring
* the {@code ContextMenu} back on screen. This also means that the
* {@code ContextMenu} will not span multiple monitors.
+ *
* @param anchor the anchor node
* @param screenX the x position of the anchor in screen coordinates
* @param screenY the y position of the anchor in screen coordinates
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
@Override
public void show(Node anchor, double screenX, double screenY) {
* <p>
* If this {@code ContextMenu} is not showing, then nothing happens.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
- @Override public void hide() {
javafx.controls/src/main/java/javafx/scene/control/Dialog.java
/**
* Closes this {@code Dialog}.
* This call is equivalent to {@link #hide}.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public final void close() {
/**
* Hides this {@code Dialog}.
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public final void hide() {
javafx.controls/src/main/java/javafx/scene/control/Menu.java
/**
* If the Menu is not disabled and the {@link ContextMenu} is not already showing,
* then this will cause the {@link ContextMenu} to be shown.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show() {
* Hides the {@link ContextMenu} if it was previously showing, and any showing
* submenus. If this menu is not showing, then invoking this function
* has no effect.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void hide() {
javafx.controls/src/main/java/javafx/scene/control/MenuButton.java
/**
* Shows the {@link ContextMenu}, assuming this MenuButton is not disabled.
*
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
* @see #isDisabled()
* @see #isShowing()
*/
public void show() {
/**
* Hides the {@link ContextMenu}.
*
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
* @see #isShowing()
*/
public void hide() {
javafx.controls/src/main/java/javafx/scene/control/skin/ComboBoxBaseSkin.java
/**
* This method will be called when the ComboBox popup should be displayed.
* It is up to specific skin implementations to determine how this is handled.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public abstract void show();
/**
* This method will be called when the ComboBox popup should be hidden.
* It is up to specific skin implementations to determine how this is handled.
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public abstract void hide();
javafx.graphics/src/main/java/javafx/stage/PopupWindow.java
* @throws NullPointerException if owner is null
* @throws IllegalArgumentException if the specified owner window would
* create cycle in the window hierarchy
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show(Window owner) {
* @throws IllegalArgumentException if the specified owner node is not
* associated with a Window or when the window would create cycle
* in the window hierarchy
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show(Node ownerNode, double anchorX, double anchorY) {
* @throws NullPointerException if ownerWindow is null
* @throws IllegalArgumentException if the specified owner window would
* create cycle in the window hierarchy
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void show(Window ownerWindow, double anchorX, double anchorY) {
/**
* Hide this Popup and all its children
+ *
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
@Override
public void hide() {
javafx.graphics/src/main/java/javafx/stage/Stage.java
/**
* Closes this {@code Stage}.
* This call is equivalent to {@code hide()}.
+ * @throws IllegalStateException if this method is called on a thread
+ * other than the JavaFX Application Thread.
*/
public void close() {
- csr of
-
JDK-8350048 Enforce threading restrictions for show and hide methods in Window, Control, and Skin
-
- Resolved
-