11 Replies Latest reply: Jan 31, 2013 2:26 PM by James_D RSS

    Resizing issues? FXML, Scene Builder, etc

    KonradZuse
      So I'm trying to use create an area for objects that move, but when they hit the sides it should collision detect and bounce off. Now I noticed I cannot resize components or containers in Scene Builder, as well as I cannot find how to even SET re-sizing on anything. I know there is isResizable(); and such. I also found the api stating that Class Group has a method called autoResize something that you can set; however I am using
               Parent root = FXMLLoader.load(getClass().getResource("Zonk.fxml")); 
      which is autoset in Netbeans IDE. if I change Parent to it's subclass Group It works; however when I run it I get a funky error.
      Exception in Application start method
      java.lang.reflect.InvocationTargetException
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
           at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
           at java.lang.reflect.Method.invoke(Method.java:601)
           at com.javafx.main.Main.launchApp(Main.java:642)
           at com.javafx.main.Main.main(Main.java:805)
      Caused by: java.lang.RuntimeException: Exception in Application start method
           at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:403)
           at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:47)
           at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:115)
           at java.lang.Thread.run(Thread.java:722)
      Caused by: java.lang.ClassCastException: javafx.scene.layout.AnchorPane cannot be cast to javafx.scene.Group
           at Zonk.start(Zonk.java:25)
           at com.sun.javafx.application.LauncherImpl$5.run(LauncherImpl.java:319)
           at com.sun.javafx.application.PlatformImpl$5.run(PlatformImpl.java:206)
           at com.sun.javafx.application.PlatformImpl$4.run(PlatformImpl.java:173)
           at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
           at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
           at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
           ... 1 more
      Java Result: 1
      Basically it seems like above is saying that I cannot use an AnchorPane in Group; however when looking at the API http://docs.oracle.com/javafx/2/api/javafx/scene/Parent.html you can see the subClass "Base Control" is what deals with the containers, but seems like the "fancier" ones it seems since Parent can apparently work with AnchorPanes... I don't know why Group wouldn't work then... Doesn't make much sense but okay... Is there anything in Scene builder that WOULD work with Group so I could set this off, or again is there any other way to fix the re-sizing issue that i might not have to change to Group?

      Thanks all!
        • 2. Re: Resizing issues? FXML, Scene Builder, etc
          Eric Le Ponner
          This exception probably means that the root object of Zonk.fxml is an AnchorPane.
          Try casting the result of FXMLLoader.load() to AnchorPane.

          If you want the root object to be a Group, then you need to modify Zonk.fxml.
          • 3. Re: Resizing issues? FXML, Scene Builder, etc
            KonradZuse
            Yes, as I said the code is for an anchor pane, a button, and another pane. I don't "NEED" the anchor pane, I just need a container that i can put stuff into that I can resize... I have scene builder, so I can do any changes in there, or the FXML, but I want to know what container can I use for group, and why does the FXML load for Parent, but not it's SUBCLASS Group? How would I cast it, just cast it to a (Group)???
            • 4. Re: Resizing issues? FXML, Scene Builder, etc
              Eric Le Ponner
              If you want to cast to Group, then you need to change the root object of
              your FXML filei from AnchorPane to Group. You need to do it manually
              because Scene Builder does not allow it for the moment.

              However a Group object is not resizable : its size is computed according the
              sizes of its children. So I'm not sure it will help you doing that.

              An AnchorPane can be resized using min, max and pref size properties.
              • 5. Re: Resizing issues? FXML, Scene Builder, etc
                KonradZuse
                Ah I see, so I just need to make it into a group, without using a container though? I can just throw it onto the plan? From Swing it always seemed like you needed a lower level container like a JPanel, because throwing it into the JFrame would normally mess up certain things...


                So I have this as my XML
                <?xml version="1.0" encoding="UTF-8"?>
                
                <?import java.lang.*?>
                <?import java.util.*?>
                <?import javafx.scene.*?>
                <?import javafx.scene.control.*?>
                <?import javafx.scene.layout.*?>
                
                <AnchorPane id="AnchorPane" prefHeight="363.0" prefWidth="320.0" xmlns:fx="http://javafx.com/fxml" fx:controller="ZonkController">
                  <children>
                    <Button fx:id="button" layoutX="126.0" layoutY="90.0" onAction="#handleButtonAction" text="Click Me!" />
                    <Label fx:id="label" layoutX="126.0" layoutY="120.0" minHeight="16.0" minWidth="69.0" />
                    <Pane fx:id="pane" layoutX="60.0" layoutY="136.0" prefHeight="200.0" prefWidth="200.0" />
                  </children>
                </AnchorPane>
                So al I would need to do is chnange <AnchorPane> into <Group>??

                Thanks for your help, I REALLY appreciate it...


                ~KZ
                • 6. Re: Resizing issues? FXML, Scene Builder, etc
                  KonradZuse
                  So one more thing... You say that Group is based on it's children's size, that's all good, but I want to be able to collision detect, so if it is based on the size of the children, wouldn't it just grow in size as it's children are moving around, thus defeating the purpose of a collision?
                  • 7. Re: Resizing issues? FXML, Scene Builder, etc
                    Eric Le Ponner
                    Yes, group size will adjust automatically according the position/size of its children.
                    So it's probably not the right container to simulate the boundaries of a
                    limited 2D space.

                    You could try using a simple Pane ; you have to setup its min/max/pref
                    size to a predefined value and put your moving objects inside.

                    To detect collision of a child with the surrounding Pane, I guess you
                    will have to implement some logic which tests the child layout bounds
                    against the Pane layout bounds...

                    Edited by: Eric Le Ponner on Jan 21, 2013 5:47 PM
                    • 8. Re: Resizing issues? FXML, Scene Builder, etc
                      KonradZuse
                      I have my dice within a pane, which was inside the archorPane/Group and it still resizes :(.
                      • 9. Re: Resizing issues? FXML, Scene Builder, etc
                        James_D
                        This might get you started:

                        BouncingBall.fxml
                        <?xml version="1.0" encoding="UTF-8"?>
                        
                        <?import javafx.scene.layout.Pane?>
                        <?import javafx.scene.layout.BorderPane?>
                        <?import javafx.scene.shape.Circle?>
                        <?import javafx.scene.shape.Rectangle?>
                        <?import javafx.scene.paint.Color?>
                        <BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="BouncingBallController">
                             <center>
                                  <Pane fx:id="container" minWidth="800" maxWidth="800" minHeight="600"
                                       maxHeight="600">
                                       <Rectangle fx:id="leftWall" width="25">
                                            <fill>
                                                 <Color fx:constant="BLUE" />
                                            </fill>
                                       </Rectangle>
                                       <Rectangle fx:id="rightWall" width="25">
                                            <fill>
                                                 <Color fx:constant="BLUE" />
                                            </fill>
                                       </Rectangle>
                                       <Circle fx:id="ball" radius="50" centerY="300" centerX="100" />
                                  </Pane>
                             </center>
                        </BorderPane>
                        BouncingBallController.java
                        import javafx.animation.Animation;
                        import javafx.animation.TranslateTransition;
                        import javafx.beans.InvalidationListener;
                        import javafx.beans.Observable;
                        import javafx.beans.binding.BooleanBinding;
                        import javafx.beans.property.BooleanProperty;
                        import javafx.beans.property.SimpleBooleanProperty;
                        import javafx.beans.value.ChangeListener;
                        import javafx.beans.value.ObservableValue;
                        import javafx.fxml.FXML;
                        import javafx.scene.Node;
                        import javafx.scene.layout.Pane;
                        import javafx.scene.shape.Circle;
                        import javafx.scene.shape.Rectangle;
                        import javafx.util.Duration;
                        
                        
                        public class BouncingBallController {
                        
                          @FXML private Rectangle leftWall ;
                          @FXML private Rectangle rightWall ;
                          @FXML private Circle ball ;
                          @FXML private Pane container ;
                          
                          public void initialize() {
                            
                            final BooleanProperty leftWallCollision = getCollisionProperty(ball, leftWall);
                            final BooleanProperty rightWallCollision = getCollisionProperty(ball, rightWall);
                         
                            leftWall.heightProperty().bind(container.heightProperty());
                            rightWall.heightProperty().bind(container.heightProperty());
                            leftWall.setX(0);
                            rightWall.xProperty().bind(container.widthProperty().subtract(rightWall.widthProperty()));
                                
                            final TranslateTransition animation = new TranslateTransition(Duration.seconds(2), ball);
                            animation.setFromX(0);
                            animation.setToX(800);
                        
                            
                            leftWallCollision.addListener(new ChangeListener<Boolean>() {
                              @Override
                              public void changed(ObservableValue<? extends Boolean> observable,
                                  Boolean oldValue, Boolean newValue) {
                                if (newValue && ! oldValue) {
                                  if (animation.getStatus() == Animation.Status.RUNNING) {
                                    animation.stop();
                                  }
                                  animation.setFromX(ball.getTranslateX());
                                  animation.setToX(container.getWidth());
                                  animation.jumpTo(Duration.ZERO);
                                  animation.play();
                                }
                              }
                            });
                        
                            
                            rightWallCollision.addListener(new ChangeListener<Boolean>() {
                              @Override
                              public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                                if (newValue && ! oldValue) {
                                  if (animation.getStatus() == Animation.Status.RUNNING) {
                                    animation.stop();
                                  }
                                  animation.setFromX(ball.getTranslateX());
                                  animation.setToX(-ball.getRadius());
                                  animation.jumpTo(Duration.ZERO);
                                  animation.play();
                                }
                              }
                            });
                        
                            animation.play();
                            
                          }
                          
                          private BooleanProperty getCollisionProperty(Node node1, Node node2) {
                            BooleanProperty prop = new SimpleBooleanProperty(false);
                            prop.bind(new CollisionBinding(node1, node2));
                            return prop ;
                          }
                          
                          private static class CollisionBinding extends BooleanBinding {
                            private Node node1 ;
                            private Node node2 ;
                            
                            CollisionBinding(Node node1, Node node2) {
                              this.node1 = node1 ;
                              this.node2 = node2 ;
                              this.bind(node1.boundsInParentProperty(), node2.boundsInParentProperty());
                              // Not sure why we need to add listeners explicitly here; surely the binding above should take care of this. Is this a bug?
                              final InvalidationListener il = new InvalidationListener() {
                                @Override public void invalidated(Observable obs) {
                                  invalidate();
                                }
                              };
                              node1.boundsInParentProperty().addListener(il);
                              node2.boundsInParentProperty().addListener(il);
                            }
                            @Override
                            public boolean computeValue() {
                              return node1.getBoundsInParent().intersects(node2.getBoundsInParent());
                            }
                          }
                        
                        }
                        BoncingBall.java
                        import javafx.application.Application;
                        import javafx.fxml.FXMLLoader;
                        import javafx.scene.Parent;
                        import javafx.scene.Scene;
                        import javafx.stage.Stage;
                        
                        public class BouncingBall extends Application {
                        
                             @Override
                             public void start(Stage primaryStage) throws Exception {
                                  Parent root = FXMLLoader.load(getClass().getResource("BouncingBall.fxml"));
                                  primaryStage.setScene(new Scene(root, 800, 600));
                                  primaryStage.setMinWidth(800);
                                  primaryStage.setMinHeight(600);
                                  primaryStage.show();
                             }
                        
                             public static void main(String[] args) { launch(args); }
                        }
                        • 10. Re: Resizing issues? FXML, Scene Builder, etc
                          KonradZuse
                          Hmm, interesting. I'm curious why there is a 2 second timer, I would think the time would be irrelevant if it bounces....


                          It's interesting how you did all of that with the properties and such(seems like a lot of it works on those like translate and rotate), but I see you used rectangles, so couldn't you just intersect them to bounce back?

                          I honestly don't know what's going on... I'm using a borderpane in scenebuilder, it set it's max/min bounds at "infinity" but I think I should change that. It's not really split into "5 different areas." I wanted to split it up and then use the points to intersect the bounces, but that seems to not be working well... I might just use 1 plane and intersect and build rectangles like you did...

                          also when I made my background black it would cut off some of the dice like one went southeast and then went in the Z-coordinate, and normally was shown, but when the black background came it cut it off.... Seems like a lot of bugs still in this. Oh well,s still an amazing lang!
                          • 11. Re: Resizing issues? FXML, Scene Builder, etc
                            James_D
                            KonradZuse wrote:
                            Hmm, interesting. I'm curious why there is a 2 second timer, I would think the time would be irrelevant if it bounces....
                            For a transition, you need to specify the duration. This is effectively going to determine the speed of the "ball" in this example; it will aim to complete the full transition (between the fromX and toX) in the time specified. Of course in this example we sometimes stop the animation prematurely. In real life I'd probably predetermine the speed and compute the duration from it, but I just wanted to show something relatively simple. (You might end up needing to abandon built-in animations completely, and have a thread that updates the positions of your nodes. This will get much more complex though.)

                            >
                            It's interesting how you did all of that with the properties and such(seems like a lot of it works on those like translate and rotate), but I see you used rectangles, so couldn't you just intersect them to bounce back?
                            That's exactly what I do. (Look at the computeValue() method in the CollisionBinding.) I just created the property to nicely encapsulate the collision. The point is you can now do anything you want with that property:
                            Label label = new Label();
                            label.textProperty().bind(Bindings.when(leftWallCollision.or(rightWallCollision)).then("Bang!!!").otherwise(""));
                            >
                            I honestly don't know what's going on... I'm using a borderpane in scenebuilder, it set it's max/min bounds at "infinity" but I think I should change that. It's not really split into "5 different areas." I wanted to split it up and then use the points to intersect the bounces, but that seems to not be working well... I might just use 1 plane and intersect and build rectangles like you did...

                            also when I made my background black it would cut off some of the dice like one went southeast and then went in the Z-coordinate, and normally was shown, but when the black background came it cut it off.... Seems like a lot of bugs still in this. Oh well,s still an amazing lang!
                            BorderPane's probably not what you want for managing this, other than perhaps at the very top level. BorderPane will usually resize its contents to fill the appropriate region (top and bottom get resized horizontally, left and right vertically, and center both). Read through the [url http://docs.oracle.com/javafx/2/layout/jfxpub-layout.htm]tutorial on layouts if you haven't already; it may help.