JDK-8170459 : Indeterminate ProgressIndicator degrades performance if stage changed
  • Type: Bug
  • Component: javafx
  • Sub-Component: animation
  • Affected Version: 8u111
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: windows_7
  • CPU: x86_64
  • Submitted: 2016-11-28
  • Updated: 2016-12-07
  • Resolved: 2016-12-07
Related Reports
Duplicate :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
If there is an indeterminate progress indicator showing, any type of stage/scene interaction degrades the application performance.  

For example, while a progress indicator is showing, these types of interactions can produce the issue:
- Creating a new stage/scene
- User resizing the stage
- Programatically resizing the stage (as is done in the included source example)

The problem is not immediately noticeable, a number of interactions typically have to be performed for it to become apparent to the user.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the included source:
- Click the Menu, opens as normal
- Click the Run Resize Task button, a series of stage resize operations are performed
- Click the Menu again, now there is a noticeable lag (~2 seconds) for the menu to open
- The problem becomes progressively worse the more times the resize task is run

As noted in the description, the user manually resizing the window a lot can produce the same behavior.


REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

/**
 * Example demonstrating issue with stage resizing when indeterminate progress indicator is showing.
 */
public class TestApplication extends Application {

    private void init(Stage primaryStage) {
        // Create new scene for stage
        Group root = new Group();
        primaryStage.setScene(new Scene(root));
        primaryStage.setWidth(200);
        primaryStage.setHeight(200);
        
        // Create menu bar with a single menu+item
        MenuBar menuBar = new MenuBar();
        Menu menu = new Menu("Menu");
        MenuItem menuItem = new MenuItem("Menu Item");
        menu.getItems().add(menuItem);
        menuBar.getMenus().addAll(menu);
        
        // Create button that runs the resize task
        Button button = new Button("Run Resize Task");
        button.setOnAction((event) -> {
            button.setDisable(true);
            runResizeTask(primaryStage, () -> {
                button.setDisable(false);
            });
        });
        
        // Create indeterminate progress indicator
        ProgressIndicator progressIndicator = new ProgressIndicator();
        progressIndicator.setMaxSize(75, 75);
        
        // Add all elements to vbox
        VBox vBox = new VBox();
        vBox.spacingProperty().set(10);
        vBox.getChildren().addAll(menuBar, button, progressIndicator);
        root.getChildren().add(vBox);
    }

    private void runResizeTask(Stage stage, Runnable callback) {
        // Expand and contract the stage size in a task 
        Task<Void> task = new Task<Void>() {
            @Override 
            protected Void call() throws Exception {
                for (int i = 200; i < 600; i++) {
                    stage.setWidth(i);
                    stage.setHeight(i);
                    Thread.sleep(5);
                }
                for (int i = 600; i > 200; i--) {
                    stage.setWidth(i);
                    stage.setHeight(i);
                    Thread.sleep(5);
                }
                
                callback.run();
                return null;
            }
        };
        
        // Start the task in a new thread
        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }
    
    @Override 
    public void start(Stage primaryStage) throws Exception {
        init(primaryStage);
        primaryStage.show();
    }
    
    public static void main(String[] args) { 
        launch(args); 
    }
}

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

CUSTOMER SUBMITTED WORKAROUND :
Using a determinate ProgressIndicator and binding it to a service does not have this same issue.

However this does have limitations as the UI elements are different.


Comments
This is similar to JDK-8088857 and the fix solves both problems so I am closing this as a duplicate of the earlier bug.
07-12-2016

Note: to workaround JDK-8170500, so that the ProgressIndicator animates on JDK 9 as well as on 8u, move the "primaryStage.setScene" to the end of the init method.
02-12-2016

Another oddity I noticed is that the test program as written has exposed a regression in JDK 9, where the animation of the progress indicator does not run in some cases. I filed a follow-on bug, JDK-8170500, to track this.
30-11-2016

Given that this is caused by Window resizing it is likely a graphics issue rather than an animation issue. Probably unrelated to the bug....I see that the application is calling Stage.setWidth and .setHeight, as well as Button.setDisabled, from a background thread which is not permitted (it should do so via runLater).
29-11-2016