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

Animation artifacts of VBox Border when children extend out of VBox

    XMLWordPrintable

Details

    • x86_64
    • windows_7

    Description

      FULL PRODUCT VERSION :
      java version "1.8.0_92"
      Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
      Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows [Version 6.1.7601]

      A DESCRIPTION OF THE PROBLEM :
      When a VBox is not the last child of another VBox and the child VBox is animated so that its height grows or shrinks, the border is not alwasy poperly rendered. On growth, the Border leaves artifacts in the child VBox. On shrink, the Border disappears. This happens when the following are simultaneously true: 1) The child VBox has its own children sticking out of itself; 2) There is another child VBox after this child VBox in the larger VBox; 3) The larger VBOX is
      not overfull. This may occur with GridPane as the Parent as well. That is the circumstance that I originally saw the problem in, but I simplified to VBox.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Follow the steps in the comments of the attached Demo.java file.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The interior of the inner VBox should be white except for the Buttons during VBox grow and the lower border should not disappear during VBox shrink.
      ACTUAL -
      The interior of the iner VBox was filled with an artifact of the red Border except for the Buttons during VBox grow and the border disappeared during VBox shrink.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      /*
       * Demo -- a program to demonstrate the occurrence
       * of rendering artifacts when a VBox is animated
       * to grow from zero height to its full height or
       * is shrunk back down to zero. The VBox has a
       * Border (on just three sides for easy viewing
       * of the problem). Call this VBox a demoBox.
       * (A demoBox is not a subclass of VBox, just an
       * instance.) The demoBox is a child of a
       * a larger VBox and the artifacts appear when it
       * is not the last demoBox child of the larger VBox.
       *
       * Note that an advertised JavaFX feature is that
       * a VBox does not clip its content. Thus, the
       * two buttons in the demoBox stick out of the
       * demoBox during animation and (as noted in the
       * JavaFX documentation) are drawn after the
       * border and so cover part of the border. This
       * is all expected. However, this seems to cause
       * errors in the way the border is drawn.
       *
       * 1. Compile and start the program from a command
       * prompt on Windows 7 Ultimate, Service Pack 1
       * and Java 8u92:
       * javac Demo.java
       * java Demo
       * A window with a single Button labeled "Add"
       * appears.
       *
       * 2. Click the Add button and wait 2 seconds while
       * the first demoBox is created, added to the
       * larger VBox, and animated to its full size.
       * All appears okay. The two new buttons sticking
       * out of the demoBox during animation are expected
       * and the lack of a top border is by design.
       *
       * 3. Click the newly appearing Delete button, and
       * the demoBox animates down to nothing and is
       * deleted. This appears okay. Note that during
       * steps 2 and 3, the demoBox is the last (and only)
       * demoBox in the larger VBox.
       *
       * 4. Click Add to get a demoBox back (as in step 2),
       * wait 2 seconds, and then click Add again to get
       * two demoBoxes showing at the same time. The
       * second demoBox is animated to full size above
       * the first one, but the demoBox is filled with
       * red during the animation. This shouldn't happen.
       * Since the demoBoxes lack top borders, it seems
       * that it is the demoBox's own bottom border that
       * is leaving artifacts. When the animation is
       * complete, the red disappears except for the
       * border and an artifact line at the top where
       * the top border would be if a demoBox had a top
       * border.
       *
       * 5. Click delete on the _top_ demoBox and it shrinks
       * to nothing, but the bottom border disappears
       * when the animation begins. It should not.
       * This happens as long as it is not the bottom
       * demoBox that you delete.
       *
       * 6. Make enough demoBoxes to overfill the window.
       * As long as the demoBoxes use too much space
       * to fit, the animations of Add and Delete
       * work properly. Thus, I suspect that some
       * layout code that is executed for the larger
       * VBox when trying to shrink demoBox _below_ their
       * prefHeight is okay, but the code for _at_
       * prefHeight has a problem.
       * 7. If you tweak the code (see "Override if you
       * wish") to make the demoBoxes grow to a height
       * greater than needed to hold the Buttons, the
       * artifacts do not appear during that portion
       * of the animation in which the Buttons do not
       * stick out of the demoBox.
       */

      import javafx.animation.KeyFrame;
      import javafx.animation.KeyValue;
      import javafx.animation.Timeline;
      import javafx.application.Application;
      import javafx.geometry.Insets;
      import javafx.scene.CacheHint;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.layout.Border;
      import javafx.scene.layout.BorderStroke;
      import javafx.scene.layout.Region;
      import javafx.scene.layout.VBox;
      import javafx.scene.paint.Color;
      import javafx.stage.Stage;

      import static javafx.scene.layout.BorderStrokeStyle.SOLID;
      import static javafx.scene.layout.BorderStrokeStyle.NONE;

      public class Demo extends Application {

          /*
           * Make a MEDIUM width, RED, SOLID border on the left, right
           * and bottom, but no visible border on the top.
           */
          final Border border = new Border(new BorderStroke(Color.RED, null,
                                                            null, null,
                                                            NONE, SOLID,
                                                            SOLID, SOLID,
                                                            null, // radii
                                                            BorderStroke.MEDIUM,
                                                            null)); // insets

          /*
           * A VBox to display the demoBoxes.
           */
          final VBox allDemoBoxes = new VBox();

          @Override
          public void start(Stage stage) {
              Button addButton = new Button("Add Box");
              addButton.setOnAction(e -> makeDemoBox());
              VBox sceneBox = new VBox(addButton, allDemoBoxes);
              sceneBox.setPrefWidth(300);
              sceneBox.setPrefHeight(300);
              stage.setScene(new Scene(sceneBox));
              stage.show();
          }

          /*
           * Make a demoBOX and set up an animation to
           * grow it to its full height.
           */
          private void makeDemoBox() {
              Button deleteButton = new Button("Delete");
              VBox demoBox = new VBox(deleteButton, new Button("Space Holder"));
              deleteButton.setOnAction(e -> deleteDemoBox(demoBox));
              demoBox.setBorder(border);

              /*
               * A trick to find the demoBox's prefHeight before it is added
               * to the real scene:
               */
              Scene tmpScene = new Scene(demoBox);
              demoBox.applyCss();
              demoBox.layout();
              if (demoBox.getContentBias() != null) {
                  System.err.println("Oops!");
                  System.exit(1);
              }
              double height = demoBox.prefHeight(-1.0);
      // double height = 110; // Override if you wish.

              allDemoBoxes.getChildren().add(0, demoBox); // Insert.
              demoBox.setMinHeight(Region.USE_PREF_SIZE);
              demoBox.setPrefHeight(0.0); // Start value.
              /*
               * The following CacheHint did not help.
               */
      // demoBox.setCacheHint(CacheHint.QUALITY);

              KeyFrame keyframe = new KeyFrame(
                             new javafx.util.Duration(2000.0),
                             new KeyValue(demoBox.prefHeightProperty(), height));
              Timeline timeline = new Timeline(keyframe);
              timeline.play();

          }

          /*
           * Animate the deletion of a demoBox.
           * The actual deletion occurs in the deleteDemoBoxFinish method
           * at the end of the animation.
           */
          private void deleteDemoBox(VBox demoBox) {
              KeyFrame keyframe = new KeyFrame(
                             new javafx.util.Duration(2000.0),
                             new KeyValue(demoBox.prefHeightProperty(), 0.0));
              Timeline timeline = new Timeline(keyframe);
              timeline.setOnFinished(e -> deleteDemoBoxFinish(demoBox));
              timeline.play();
          }

          private void deleteDemoBoxFinish(VBox demoBox) {
              allDemoBoxes.getChildren().remove(demoBox);
          }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      None known if you want all of the conditions mentioned including child Nodes of the VBox that are drawn beyond the Border of the VBox. However, if you don't need the child nodes to draw beyond the Border, I have found that clipping the VBox to its height and width eliminates the artifacts.

      Attachments

        Activity

          People

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            5 Start watching this issue

            Dates

              Created:
              Updated: