Advertisement
Guest User

Modified Bounds Example by jewelsea

a guest
Feb 26th, 2014
240
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 20.98 KB | None | 0 0
  1. package application;
  2.  
  3. import javafx.application.Application;
  4. import javafx.beans.property.DoubleProperty;
  5. import javafx.beans.property.ObjectProperty;
  6. import javafx.beans.property.ReadOnlyObjectProperty;
  7. import javafx.beans.property.SimpleObjectProperty;
  8. import javafx.beans.value.ChangeListener;
  9. import javafx.beans.value.ObservableValue;
  10. import javafx.collections.FXCollections;
  11. import javafx.collections.ObservableList;
  12. import javafx.event.EventHandler;
  13. import javafx.geometry.Bounds;
  14. import javafx.scene.Cursor;
  15. import javafx.scene.Group;
  16. import javafx.scene.Node;
  17. import javafx.scene.Scene;
  18. import javafx.scene.control.CheckBox;
  19. import javafx.scene.control.Control;
  20. import javafx.scene.control.Label;
  21. import javafx.scene.control.ListView;
  22. import javafx.scene.control.RadioButton;
  23. import javafx.scene.control.ToggleGroup;
  24. import javafx.scene.effect.DropShadow;
  25. import javafx.scene.input.MouseEvent;
  26. import javafx.scene.layout.StackPane;
  27. import javafx.scene.layout.VBox;
  28. import javafx.scene.paint.Color;
  29. import javafx.scene.shape.Circle;
  30. import javafx.scene.shape.Line;
  31. import javafx.scene.shape.Rectangle;
  32. import javafx.scene.shape.Shape;
  33. import javafx.scene.shape.StrokeLineCap;
  34. import javafx.scene.shape.StrokeType;
  35. import javafx.scene.web.WebView;
  36. import javafx.stage.Stage;
  37. import javafx.stage.StageStyle;
  38. import javafx.stage.WindowEvent;
  39.  
  40. /** Demo for understanding JavaFX Layout Bounds */
  41. public class BoundsPlayground extends Application
  42. {
  43.   final ObservableList<Shape>     shapes             = FXCollections.observableArrayList();
  44.   final ObservableList<ShapePair> intersections      = FXCollections.observableArrayList();
  45.   ObjectProperty<BoundsType>      selectedBoundsType = new SimpleObjectProperty<BoundsType>(
  46.                                                          BoundsType.LAYOUT_BOUNDS );
  47.  
  48.   public static void main( final String[] args )
  49.   {
  50.     launch( args );
  51.   }
  52.   @Override
  53.   public void start( final Stage stage )
  54.   {
  55.     stage.setTitle( "Bounds Playground" );
  56.     // define some objects to manipulate on the scene.
  57.     final Circle greenCircle = new Circle( 100, 100, 50, Color.FORESTGREEN );
  58.     greenCircle.setId( "Green Circle" );
  59.     final Circle redCircle = new Circle( 300, 200, 50, Color.FIREBRICK );
  60.     redCircle.setId( "Red Circle" );
  61.  
  62.     final Line line = new Line( 25, 300, 375, 200 );
  63.     line.setId( "Line" );
  64.     line.setStrokeLineCap( StrokeLineCap.ROUND );
  65.     line.setStroke( Color.MIDNIGHTBLUE );
  66.     line.setStrokeWidth( 5 );
  67.  
  68.     final Anchor anchor1 = new Anchor( "Anchor 1", line.startXProperty(), line.startYProperty() );
  69.     final Anchor anchor2 = new Anchor( "Anchor 2", line.endXProperty(), line.endYProperty() );
  70.  
  71.     final Group group = new Group( greenCircle, redCircle, line, anchor1, anchor2 );
  72.  
  73.     // monitor intersections of shapes in the scene.
  74.     for ( final Node node : group.getChildrenUnmodifiable() )
  75.     {
  76.       if ( node instanceof Shape )
  77.       {
  78.         shapes.add( (Shape) node );
  79.       }
  80.     }
  81.     testIntersections();
  82.  
  83.     // enable dragging for the scene objects.
  84.     final Circle[] circles = { greenCircle, redCircle, anchor1, anchor2 };
  85.     for ( final Circle circle : circles )
  86.     {
  87.       enableDrag( circle );
  88.       circle.centerXProperty().addListener( new ChangeListener<Number>()
  89.       {
  90.         @Override
  91.         public void changed( final ObservableValue<? extends Number> observableValue, final Number oldValue,
  92.                              final Number newValue )
  93.         {
  94.           testIntersections();
  95.         }
  96.       } );
  97.       circle.centerYProperty().addListener( new ChangeListener<Number>()
  98.       {
  99.         @Override
  100.         public void changed( final ObservableValue<? extends Number> observableValue, final Number oldValue,
  101.                              final Number newValue )
  102.         {
  103.           testIntersections();
  104.         }
  105.       } );
  106.     }
  107.  
  108.     // define an overlay to show the layout bounds of the scene's shapes.
  109.     final Group layoutBoundsOverlay = new Group();
  110.     layoutBoundsOverlay.setMouseTransparent( true );
  111.     for ( final Shape shape : shapes )
  112.     {
  113.       if ( !(shape instanceof Anchor) )
  114.       {
  115.         layoutBoundsOverlay.getChildren().add( new BoundsDisplay( shape ) );
  116.       }
  117.     }
  118.     // layout the scene.
  119.     final StackPane background = new StackPane();
  120.     background.setStyle( "-fx-background-color: cornsilk;" );
  121.     final Scene scene = new Scene( new Group( background, group, layoutBoundsOverlay ), 600, 500 );
  122.  
  123.     group.setScaleX( 5 );
  124.     group.setScaleY( 5 );
  125.  
  126.  
  127.     background.prefHeightProperty().bind( scene.heightProperty() );
  128.     background.prefWidthProperty().bind( scene.widthProperty() );
  129.     stage.setScene( scene );
  130.     stage.show();
  131.  
  132.     createUtilityWindow( stage, layoutBoundsOverlay, new Shape[]{ greenCircle, redCircle } );
  133.   }
  134.  
  135.   // update the list of intersections.
  136.   private void testIntersections()
  137.   {
  138.     intersections.clear();
  139.     // for each shape test it's intersection with all other shapes.
  140.     for ( final Shape src : shapes )
  141.     {
  142.       for ( final Shape dest : shapes )
  143.       {
  144.         final ShapePair pair = new ShapePair( src, dest );
  145.         if ( !(pair.a instanceof Anchor) && !(pair.b instanceof Anchor) && !intersections.contains( pair )
  146.             && pair.intersects( selectedBoundsType.get() ) )
  147.         {
  148.           intersections.add( pair );
  149.         }
  150.       }
  151.     }
  152.   }
  153.  
  154.   // make a node movable by dragging it around with the mouse.
  155.   private void enableDrag( final Circle circle )
  156.   {
  157.     final Delta dragDelta = new Delta();
  158.     circle.setOnMousePressed( new EventHandler<MouseEvent>()
  159.     {
  160.       @Override
  161.       public void handle( final MouseEvent mouseEvent )
  162.       {
  163.         // record a delta distance for the drag and drop operation.
  164.         dragDelta.x = circle.getCenterX() - mouseEvent.getX();
  165.         dragDelta.y = circle.getCenterY() - mouseEvent.getY();
  166.         circle.getScene().setCursor( Cursor.MOVE );
  167.       }
  168.     } );
  169.     circle.setOnMouseReleased( new EventHandler<MouseEvent>()
  170.     {
  171.       @Override
  172.       public void handle( final MouseEvent mouseEvent )
  173.       {
  174.         circle.getScene().setCursor( Cursor.HAND );
  175.       }
  176.     } );
  177.     circle.setOnMouseDragged( new EventHandler<MouseEvent>()
  178.     {
  179.       @Override
  180.       public void handle( final MouseEvent mouseEvent )
  181.       {
  182.         circle.setCenterX( mouseEvent.getX() + dragDelta.x );
  183.         circle.setCenterY( mouseEvent.getY() + dragDelta.y );
  184.       }
  185.     } );
  186.     circle.setOnMouseEntered( new EventHandler<MouseEvent>()
  187.     {
  188.       @Override
  189.       public void handle( final MouseEvent mouseEvent )
  190.       {
  191.         if ( !mouseEvent.isPrimaryButtonDown() )
  192.         {
  193.           circle.getScene().setCursor( Cursor.HAND );
  194.         }
  195.       }
  196.     } );
  197.     circle.setOnMouseExited( new EventHandler<MouseEvent>()
  198.     {
  199.       @Override
  200.       public void handle( final MouseEvent mouseEvent )
  201.       {
  202.         if ( !mouseEvent.isPrimaryButtonDown() )
  203.         {
  204.           circle.getScene().setCursor( Cursor.DEFAULT );
  205.         }
  206.       }
  207.     } );
  208.   }
  209.  
  210.   // a helper enumeration of the various types of bounds we can work with.
  211.   enum BoundsType
  212.   {
  213.     LAYOUT_BOUNDS, BOUNDS_IN_LOCAL, BOUNDS_IN_PARENT
  214.   }
  215.  
  216.   // a translucent overlay display rectangle to show the bounds of a Shape.
  217.   class BoundsDisplay extends Rectangle
  218.   {
  219.     // the shape to which the bounds display has been type.
  220.     final Shape                    monitoredShape;
  221.     private ChangeListener<Bounds> boundsChangeListener;
  222.  
  223.     BoundsDisplay( final Shape shape )
  224.     {
  225.       setFill( Color.LIGHTGRAY.deriveColor( 1, 1, 1, 0.35 ) );
  226.       setStroke( Color.LIGHTGRAY.deriveColor( 1, 1, 1, 0.5 ) );
  227.       setStrokeType( StrokeType.INSIDE );
  228.       setStrokeWidth( 3 );
  229.       monitoredShape = shape;
  230.       monitorBounds( BoundsType.LAYOUT_BOUNDS );
  231.     }
  232.  
  233.     // set the type of the shape's bounds to monitor for the bounds display.
  234.     void monitorBounds( final BoundsType boundsType )
  235.     {
  236.       // remove the shape's previous boundsType.
  237.       if ( boundsChangeListener != null )
  238.       {
  239.         final ReadOnlyObjectProperty<Bounds> oldBounds;
  240.         switch ( selectedBoundsType.get() )
  241.         {
  242.           case LAYOUT_BOUNDS:
  243.             oldBounds = monitoredShape.layoutBoundsProperty();
  244.             break;
  245.           case BOUNDS_IN_LOCAL:
  246.             oldBounds = monitoredShape.boundsInLocalProperty();
  247.             break;
  248.           case BOUNDS_IN_PARENT:
  249.             oldBounds = monitoredShape.boundsInParentProperty();
  250.             break;
  251.           default :
  252.             oldBounds = null;
  253.         }
  254.         if ( oldBounds != null )
  255.         {
  256.           oldBounds.removeListener( boundsChangeListener );
  257.         }
  258.       }
  259.  
  260.       // determine the shape's bounds for the given boundsType.
  261.       final ReadOnlyObjectProperty<Bounds> bounds;
  262.       switch ( boundsType )
  263.       {
  264.         case LAYOUT_BOUNDS:
  265.           bounds = monitoredShape.layoutBoundsProperty();
  266.           break;
  267.         case BOUNDS_IN_LOCAL:
  268.           bounds = monitoredShape.boundsInLocalProperty();
  269.           break;
  270.         case BOUNDS_IN_PARENT:
  271.           bounds = monitoredShape.boundsInParentProperty();
  272.           break;
  273.         default :
  274.           bounds = null;
  275.       }
  276.  
  277.       // set the visual bounds display based upon the new bounds and keep it in sync.
  278.       if ( bounds != null )
  279.       {
  280.         updateBoundsDisplay( bounds.get() );
  281.  
  282.         // keep the visual bounds display based upon the new bounds and keep it in sync.
  283.         boundsChangeListener = new ChangeListener<Bounds>()
  284.         {
  285.           @Override
  286.           public void changed( final ObservableValue<? extends Bounds> observableValue,
  287.                                final Bounds oldBounds, final Bounds newBounds )
  288.           {
  289.             updateBoundsDisplay( newBounds );
  290.           }
  291.         };
  292.         bounds.addListener( boundsChangeListener );
  293.       }
  294.     }
  295.  
  296.     // update this bounds display to match a new set of bounds.
  297.     private void updateBoundsDisplay( final Bounds newBounds )
  298.     {
  299.       setX( newBounds.getMinX() );
  300.       setY( newBounds.getMinY() );
  301.       setWidth( newBounds.getWidth() );
  302.       setHeight( newBounds.getHeight() );
  303.     }
  304.   }
  305.   // an anchor displayed around a point.
  306.   class Anchor extends Circle
  307.   {
  308.     Anchor( final String id, final DoubleProperty x, final DoubleProperty y )
  309.     {
  310.       super( x.get(), y.get(), 10 );
  311.       setId( id );
  312.       setFill( Color.GOLD.deriveColor( 1, 1, 1, 0.5 ) );
  313.       setStroke( Color.GOLD );
  314.       setStrokeWidth( 2 );
  315.       setStrokeType( StrokeType.OUTSIDE );
  316.       x.bind( centerXProperty() );
  317.       y.bind( centerYProperty() );
  318.     }
  319.   }
  320.   // records relative x and y co-ordinates.
  321.   class Delta
  322.   {
  323.     double x, y;
  324.   }
  325.   // records a pair of (possibly) intersecting shapes.
  326.   class ShapePair
  327.   {
  328.     private final Shape a, b;
  329.     public ShapePair( final Shape src, final Shape dest )
  330.     {
  331.       a = src;
  332.       b = dest;
  333.     }
  334.  
  335.     public boolean intersects( final BoundsType boundsType )
  336.     {
  337.       if ( a == b )
  338.       {
  339.         return false;
  340.       }
  341.       a.intersects( b.getBoundsInLocal() );
  342.       switch ( boundsType )
  343.       {
  344.         case LAYOUT_BOUNDS:
  345.           return a.getLayoutBounds().intersects( b.getLayoutBounds() );
  346.         case BOUNDS_IN_LOCAL:
  347.           return a.getBoundsInLocal().intersects( b.getBoundsInLocal() );
  348.         case BOUNDS_IN_PARENT:
  349.           return a.getBoundsInParent().intersects( b.getBoundsInParent() );
  350.         default :
  351.           return false;
  352.       }
  353.     }
  354.  
  355.     @Override
  356.     public String toString()
  357.     {
  358.       return a.getId() + " : " + b.getId();
  359.     }
  360.  
  361.     @Override
  362.     public boolean equals( final Object other )
  363.     {
  364.       final ShapePair o = (ShapePair) other;
  365.       return o != null && (a == o.a && b == o.b || a == o.b && b == o.a);
  366.     }
  367.  
  368.     @Override
  369.     public int hashCode()
  370.     {
  371.       int result = a != null ? a.hashCode() : 0;
  372.       result = 31 * result + (b != null ? b.hashCode() : 0);
  373.       return result;
  374.     }
  375.   }
  376.  
  377.   // define a utility stage for reporting intersections.
  378.   private void createUtilityWindow( final Stage stage, final Group boundsOverlay,
  379.                                     final Shape[] transformableShapes )
  380.   {
  381.     final Stage reportingStage = new Stage();
  382.     reportingStage.setTitle( "Control Panel" );
  383.     reportingStage.initStyle( StageStyle.UTILITY );
  384.     reportingStage.setX( stage.getX() + stage.getWidth() );
  385.     reportingStage.setY( stage.getY() );
  386.  
  387.     // define content for the intersections utility panel.
  388.     final ListView<ShapePair> intersectionView = new ListView<ShapePair>( intersections );
  389.     final Label instructions = new Label( "Click on any circle in the scene to the left to drag it around." );
  390.     instructions.setMinSize( Control.USE_PREF_SIZE, Control.USE_PREF_SIZE );
  391.     instructions.setStyle( "-fx-font-weight: bold; -fx-text-fill: darkgreen;" );
  392.  
  393.     final Label intersectionInstructions =
  394.         new Label( "Any intersecting bounds in the scene will be reported below." );
  395.     instructions.setMinSize( Control.USE_PREF_SIZE, Control.USE_PREF_SIZE );
  396.  
  397.     // add the ability to set a translate value for the circles.
  398.     final CheckBox translateNodes = new CheckBox( "Translate circles" );
  399.     translateNodes.selectedProperty().addListener( new ChangeListener<Boolean>()
  400.     {
  401.       @Override
  402.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean oldValue,
  403.                            final Boolean doTranslate )
  404.       {
  405.         if ( doTranslate )
  406.         {
  407.           for ( final Shape shape : transformableShapes )
  408.           {
  409.             shape.setTranslateY( 100 );
  410.             testIntersections();
  411.           }
  412.         }
  413.         else
  414.         {
  415.           for ( final Shape shape : transformableShapes )
  416.           {
  417.             shape.setTranslateY( 0 );
  418.             testIntersections();
  419.           }
  420.         }
  421.       }
  422.     } );
  423.     translateNodes.selectedProperty().set( false );
  424.  
  425.     // add the ability to add an effect to the circles.
  426.     final Label modifyInstructions = new Label( "Modify visual display aspects." );
  427.     modifyInstructions.setStyle( "-fx-font-weight: bold;" );
  428.     modifyInstructions.setMinSize( Control.USE_PREF_SIZE, Control.USE_PREF_SIZE );
  429.     final CheckBox effectNodes = new CheckBox( "Add an effect to circles" );
  430.     effectNodes.selectedProperty().addListener( new ChangeListener<Boolean>()
  431.     {
  432.       @Override
  433.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean oldValue,
  434.                            final Boolean doTranslate )
  435.       {
  436.         if ( doTranslate )
  437.         {
  438.           for ( final Shape shape : transformableShapes )
  439.           {
  440.             shape.setEffect( new DropShadow() );
  441.             testIntersections();
  442.           }
  443.         }
  444.         else
  445.         {
  446.           for ( final Shape shape : transformableShapes )
  447.           {
  448.             shape.setEffect( null );
  449.             testIntersections();
  450.           }
  451.         }
  452.       }
  453.     } );
  454.     effectNodes.selectedProperty().set( true );
  455.  
  456.     // add the ability to add a stroke to the circles.
  457.     final CheckBox strokeNodes = new CheckBox( "Add outside strokes to circles" );
  458.     strokeNodes.selectedProperty().addListener( new ChangeListener<Boolean>()
  459.     {
  460.       @Override
  461.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean oldValue,
  462.                            final Boolean doTranslate )
  463.       {
  464.         if ( doTranslate )
  465.         {
  466.           for ( final Shape shape : transformableShapes )
  467.           {
  468.             shape.setStroke( Color.LIGHTSEAGREEN );
  469.             shape.setStrokeWidth( 10 );
  470.             testIntersections();
  471.           }
  472.         }
  473.         else
  474.         {
  475.           for ( final Shape shape : transformableShapes )
  476.           {
  477.             shape.setStrokeWidth( 0 );
  478.             testIntersections();
  479.           }
  480.         }
  481.       }
  482.     } );
  483.     strokeNodes.selectedProperty().set( true );
  484.     // add the ability to show or hide the layout bounds overlay.
  485.     final Label showBoundsInstructions = new Label( "The gray squares represent layout bounds." );
  486.     showBoundsInstructions.setStyle( "-fx-font-weight: bold;" );
  487.     showBoundsInstructions.setMinSize( Control.USE_PREF_SIZE, Control.USE_PREF_SIZE );
  488.     final CheckBox showBounds = new CheckBox( "Show Bounds" );
  489.     boundsOverlay.visibleProperty().bind( showBounds.selectedProperty() );
  490.     showBounds.selectedProperty().set( true );
  491.  
  492.     // create a container for the display control checkboxes.
  493.     final VBox displayChecks = new VBox( 10 );
  494.     displayChecks.getChildren().addAll( modifyInstructions, translateNodes, effectNodes, strokeNodes,
  495.         showBoundsInstructions, showBounds );
  496.  
  497.     // create a toggle group for the bounds type to use.
  498.     final ToggleGroup boundsToggleGroup = new ToggleGroup();
  499.     final RadioButton useLayoutBounds = new RadioButton( "Use Layout Bounds" );
  500.     final RadioButton useBoundsInLocal = new RadioButton( "Use Bounds in Local" );
  501.     final RadioButton useBoundsInParent = new RadioButton( "Use Bounds in Parent" );
  502.     useLayoutBounds.setToggleGroup( boundsToggleGroup );
  503.     useBoundsInLocal.setToggleGroup( boundsToggleGroup );
  504.     useBoundsInParent.setToggleGroup( boundsToggleGroup );
  505.     final VBox boundsToggles = new VBox( 10 );
  506.     boundsToggles.getChildren().addAll( useLayoutBounds, useBoundsInLocal, useBoundsInParent );
  507.  
  508.     // change the layout bounds display depending on which bounds type has been selected.
  509.     useLayoutBounds.selectedProperty().addListener( new ChangeListener<Boolean>()
  510.     {
  511.       @Override
  512.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean aBoolean,
  513.                            final Boolean isSelected )
  514.       {
  515.         if ( isSelected )
  516.         {
  517.           for ( final Node overlay : boundsOverlay.getChildren() )
  518.           {
  519.             ((BoundsDisplay) overlay).monitorBounds( BoundsType.LAYOUT_BOUNDS );
  520.           }
  521.           selectedBoundsType.set( BoundsType.LAYOUT_BOUNDS );
  522.           testIntersections();
  523.         }
  524.       }
  525.     } );
  526.     useBoundsInLocal.selectedProperty().addListener( new ChangeListener<Boolean>()
  527.     {
  528.       @Override
  529.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean aBoolean,
  530.                            final Boolean isSelected )
  531.       {
  532.         if ( isSelected )
  533.         {
  534.           for ( final Node overlay : boundsOverlay.getChildren() )
  535.           {
  536.             ((BoundsDisplay) overlay).monitorBounds( BoundsType.BOUNDS_IN_LOCAL );
  537.           }
  538.           selectedBoundsType.set( BoundsType.BOUNDS_IN_LOCAL );
  539.           testIntersections();
  540.         }
  541.       }
  542.     } );
  543.     useBoundsInParent.selectedProperty().addListener( new ChangeListener<Boolean>()
  544.     {
  545.       @Override
  546.       public void changed( final ObservableValue<? extends Boolean> observableValue, final Boolean aBoolean,
  547.                            final Boolean isSelected )
  548.       {
  549.         if ( isSelected )
  550.         {
  551.           for ( final Node overlay : boundsOverlay.getChildren() )
  552.           {
  553.             ((BoundsDisplay) overlay).monitorBounds( BoundsType.BOUNDS_IN_PARENT );
  554.           }
  555.           selectedBoundsType.set( BoundsType.BOUNDS_IN_PARENT );
  556.           testIntersections();
  557.         }
  558.       }
  559.     } );
  560.     useLayoutBounds.selectedProperty().set( true );
  561.  
  562.     final WebView boundsExplanation = new WebView();
  563.     boundsExplanation
  564.         .getEngine()
  565.         .loadContent(
  566.             "<html><body bgcolor='darkseagreen' fgcolor='lightgrey' style='font-size:12px'><dl>"
  567.                 + "<dt><b>Layout Bounds</b></dt><dd>The boundary of the shape.</dd><br/>"
  568.                 + "<dt><b>Bounds in Local</b></dt><dd>The boundary of the shape and effect.</dd><br/>"
  569.                 + "<dt><b>Bounds in Parent</b></dt><dd>The boundary of the shape, effect and transforms.<br/>The co-ordinates of what you see.</dd>"
  570.                 + "</dl></body></html>" );
  571.     boundsExplanation.setPrefWidth( 100 );
  572.     boundsExplanation.setMinHeight( 130 );
  573.     boundsExplanation.setMaxHeight( 130 );
  574.     boundsExplanation.setStyle( "-fx-background-color: transparent" );
  575.  
  576.     // layout the utility pane.
  577.     final VBox utilityLayout = new VBox( 10 );
  578.     utilityLayout
  579.         .setStyle( "-fx-padding:10; -fx-background-color: linear-gradient(to bottom, lightblue, derive(lightblue, 20%));" );
  580.     utilityLayout.getChildren().addAll( instructions, intersectionInstructions, intersectionView,
  581.         displayChecks, boundsToggles, boundsExplanation );
  582.     utilityLayout.setPrefHeight( 530 );
  583.     reportingStage.setScene( new Scene( utilityLayout ) );
  584.     reportingStage.show();
  585.  
  586.     // ensure the utility window closes when the main app window closes.
  587.     stage.setOnCloseRequest( new EventHandler<WindowEvent>()
  588.     {
  589.       @Override
  590.       public void handle( final WindowEvent windowEvent )
  591.       {
  592.         reportingStage.close();
  593.       }
  594.     } );
  595.   }
  596. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement