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

Exception in layout pass locks up Toolkit pulsing.

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 8
    • 8
    • javafx
    • Java 1.80ea b109

      I have recently noticed that any exception that is thrown during a layout pass in my Scene will encounter 2 troubling issues.

      1. The exception is printed to Standard.err instead of bubbling up to my UncaughtExceptionHandler. It appears that inside QuantumToolkit.pulse() there is a try catch that prints the stacktrace instead of allowing the error to be handled by its ThreadGroup. This is related to bug RT-15332 and RT-30579.

      2. The exception also seems to put the QuantumToolkit in an unstable state which means that the JavaFX Application Thread still processes user events but no longer renders any visual updates since the Scene pulsing is frozen. It looks to me like QuantumToolkit.pulse() should be doing more pulse cleanup in its finally block so that exceptions do not break future pulsing altogether...

      To observe this behaviour run the following test case and click on the button. Then resize the stage to trigger a layout pass.

      This is definitely a contrived example to highlight the issue. While it is true that much of the JavaFX's layout code is not really in the application writer's domain it does cause more issues with "virtualized" controls like ListView and TableView. In these views each layout pass encounters much more application code to update the virtualized cells and this incomplete error handling will make applications feel very unstable.

      ********************************** test case ***********************************************
      import javafx.application.Application;
      import javafx.event.ActionEvent;
      import javafx.event.EventHandler;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.layout.StackPane;
      import javafx.stage.Stage;

      public class PulseTest extends Application {

         private boolean throwErrorNextLayout_ = false;
         
         @Override public void start(final Stage primaryStage) throws Exception {

            primaryStage.centerOnScreen();
            primaryStage.setHeight(200);
            primaryStage.setWidth(550);
            
            Button armErrorbutton = new Button("Arm Pulse Error");
            armErrorbutton.setOnAction(new EventHandler<ActionEvent>() {
               @Override public void handle(ActionEvent event) {
                  throwErrorNextLayout_ = true;
               }
            });
            
            primaryStage.setScene(new Scene(new StackPane(armErrorbutton) {
               @Override
               protected void layoutChildren() {
                  super.layoutChildren();
                  if ( throwErrorNextLayout_ ) {
                     throw new RuntimeException("layout error thrown!");
                  }
               }
            }));
            
            primaryStage.show();

         }

         public static void main(String[] args) throws Exception {
            launch(args);
         }

      }

            art Artem Ananiev (Inactive)
            csmithjfx Charles Smith (Inactive)
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported: