This discussion is archived
11 Replies Latest reply: Jan 31, 2013 12:26 PM by James_D RSS

Resizing issues? FXML, Scene Builder, etc

KonradZuse Explorer
Currently Being Moderated
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!
  • 1. Re: Resizing issues? FXML, Scene Builder, etc
    KonradZuse Explorer
    Currently Being Moderated
    Any idea?
  • 2. Re: Resizing issues? FXML, Scene Builder, etc
    EricLePonner Explorer
    Currently Being Moderated
    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 Explorer
    Currently Being Moderated
    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
    EricLePonner Explorer
    Currently Being Moderated
    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 Explorer
    Currently Being Moderated
    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 Explorer
    Currently Being Moderated
    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
    EricLePonner Explorer
    Currently Being Moderated
    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 Explorer
    Currently Being Moderated
    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 Guru
    Currently Being Moderated
    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 Explorer
    Currently Being Moderated
    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 Guru
    Currently Being Moderated
    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.

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points