Updates from March, 2011 Toggle Comment Threads | Keyboard Shortcuts

  • mxshrestha 4:59 am on March 30, 2011 Permalink | Reply
    Tags: bounds, bounds in JavaFx, Bounds in local, Bounds In Parent, , , center the node in the screen, , , layout Bounds, , node positioning, position node, reflection effect, rotate effect, translateX, translateY   

    More about bounds and positioning nodes 

    On my last post about bounds titled “Bounds in Java”, I introduced the different types of bounds available in JavaFx and what bounds are. This post is centered towards when to use those bounds and a simple trick to center your node in the screen. Just a quick review, bounds in JavaFx can be accessed in three different ways i.e. accessing  the layoutBounds, boundsInLocal, and boundsInParent of the nodes.  At first I really didn’t like the idea of having three different way to access the bounds and it was more confusing to me coming from a Java Swing background. However, now I think of it, I agree that it is a neat idea and gives the programmer more control and flexibility towards designing the UI. The best and easy way for me to figure out when to use which bounds is to remember this:

    layoutBounds :- node

    boundsInLocal:-node+effect/clip

    boundsInParent:node +effect/clip + transformations(transform/scale/translations)

    So we decide which bound variables we want to use looking at how we want the node to be displayed. Lets suppose I have a ImageView node with reflection effect and rotate(45 degrees) effect applied on it (i will provide the code below). Now, I use the layoutBounds variables if I just want to center the node in the screen. Keep in mind using layout bounds will just center the node (i.e. the image without the reflection part is centered and the reflection is positioned respectively after the node is centered). If I want to center the node along with the reflection of the node (i.e. center the whole image + its reflection) then I use the boundsInLocal variables. The case of boundsInParent is a bit unexplainable because it did not work as I thought it was supposed to be. I applied a rotate transform effect and then tried to center the node along with the reflection and the rotate effect using the boundsinParent variables but the result was not as what i expected. My guess is that boundsInParent comes in handy if we are messing around with groups. Anyways, boundsInParent and boundsInLocal are not recommended to be used.

    QuickTip on how to position nodes at the center of the screen:

    nodes can be positions at the center of the screen using this formula:

    translateX/layoutX/x = (width of screen – width of node)/2;

    translateY/layoutY/y = (height of screen – height of node)/2;

    We can get the width and height of the node using layoutBounds, BoundsInLocal and BoundsinParent variables. Like i said above, if we use laoyoutBounds then only the node without its effect and transform will be centered, and if we use BoundsInLocal then the node along with the effect will be centered. BoundsInParent case was not as expected so I still need to do more research on it (or someone please explain me).

    Here is the example I ran:

    
    var test: ImageView = ImageView
    {
         image: Image
         {
           url: "{__DIR__}Images/a10.jpg" //change this url to point to an image in your folder
         }
    
          effect:Reflection
         {
           fraction: 0.75
           topOffset: 0.0
           topOpacity: 0.5
           bottomOpacity: 0.0
         }
    
         rotate: 45
    
         //centers image only and then reflection is applied.
         translateX: bind (stage.scene.width - test.layoutBounds.width)/2;
         translateY: bind (stage.scene.height - test.layoutBounds.height)/2;
    
        //uncomment this one to see the boundsInLocal in action. this will center the image along with the reflection effect.
        /*
        translateX: bind (stage.scene.width - test.boundsInLocal.width)/2;
        translateY: bind (stage.scene.height - test.boundsInLocal.height)/2;
       */
        //uncomment this one to see the boundsInParent in action. creates unexpected result in my case.
       //Please shine some light on this one to me.
       /*
       translateX: bind (stage.scene.width - test.boundsInParent.width)/2;
       translateY: bind (stage.scene.height - test.boundsInParent.height)/2;
       */
    
    }
    
    

    Below is the result of using layoutBounds, BoundsInLocal and BoundsInParent from left to right respectively on an imageview. We can clearly see that layoutBounds center the image only, BoundsInLocal center the image along with the reflection effect, and BoundsInParent is not even rotating right.(Explain!!!)

    layoutBounds, BoundsInLocal, BoundsInParent

     
  • mxshrestha 4:34 am on March 23, 2011 Permalink | Reply
    Tags: , JavaFX abstract class, JavaFX pages, JavaFX screens, multiple pages in JavaFx, multiple scenes in javaFx, Multiple Screens in javaFx, pages in JavaFx, pages/screens/scenes, scenes, scenes in JavaFx, screens in JavaFx,   

    Managing multiple scenes in JavaFx 

    Although JavaFx scenes are different than Java panels, they both can be used for displaying what needs to be shown in the screen at run time. Suppose that we  have a login screen that is displayed when the application runs, and after the user submits  the user name and password lets say the application directs the user to the respective page according to the user credential. Learning how this works was quite a handful and one of the approach that I found was interesting and useful was by using abstract class. Keep in mind that this can be done other ways as well.  Here, I am introducing a method using abstract class to navigate to different pages that needs to be displayed.

    Lets start with the abstract class. This class will be extended by all other pages or screens that needs to be displayed.

    
    public abstract class View extends CustomNode
    {
      protected var currentView: Node; //holds the value of the current page to be  displayed
      protected var controller:Controller;//business logic to decide what to display
    
      protected abstract function createView():Void;
    
      override function create(): Node
      {
         createView();
         return currentView
      }
    }
    
    

    The abstract class extends CustomNode and overrides the function create()
    to return the current node of interest. the currentView holds the node
    that needs to be displayed and the controller is of type Controller class
    which I will introduce now. Basically what the controller class does is
    decide on what page needs to be displayed and then forwards the page to the
    scene to be displayed.

    public class Controller
    {
        public var contents: Node;
        public var loginForm: Login; //holds login page
        public var adminScreen: AdminPage; //holds admin page
        public var guestScreen: GuestPage;//holds guest page
    
        public function showLoginScreen()
        {
           if(loginForm == null)
           {
             loginForm = Login
             {
               controller: this;
             }
           }
    
           contents = loginForm;
        }
    
        public function showAdminPage()
        {
            if(adminScreen == null)
            {
                adminScreen = AdminPage
                {
                    controller: this;
                }
            }
            contents= adminScreen;
        }
    
        public function showGuestPage()
        {
            if(guestScreen == null)
            {
                guestScreen = GuestPage
                {
                   controller: this;
                }
            }
            contents = guestScreen;
        }
    }
    
    

    Now that the hard part is over, lets introduce the Main.fx.

    
    var controller = new Controller;
    
    var stage: Stage = Stage
    {
       title: "Demo"
       scene: Scene
       {
          width: 800
          height: 800
    
          content: bind
          [
             controller.contents
          ]
       }
    }
    

    The content of the stage is bound to the contents of the controller. So,
    everytime the content of the controller changes the scene is updated with the
    new content.

    Here is a simple code for login.fx

    public class Login extends View
    {
       var userNameLbl = Label
       {
          text:"User Name:"
       }
    
       var passwordLbl = Label
       {
          text:"Password:"
       }
    
       var userNameTxt = TextBox
       {
          columns:10
       }
    
       var passwordTxt = PasswordBox
       {
          columns:10
       }
    
       var submitBtn = Button
       {
          action: function()
          {
             if((userNameTxt.text.compareTo("admin") == 0) and (passwordTxt.text.compareTo("admin") == 0))
             {
                 controller.showAdminPage();
             }
             else
             {
                 controller.showGuestPage();
             }
          }
          text:"Login"
       }
    
       var loginBox:VBox = VBox
       {
          spacing: 5
          nodeHPos: HPos.RIGHT
    
          content:
          [
              HBox
              {
                  nodeVPos: VPos.BOTTOM //bottom aligning the nodes
    
                  spacing: 2 //spacing between the two corresponding nodes
    
                 content:
                 [
                   userNameLbl,
                   userNameTxt
                 ]
              }
    
              HBox
              {
                 hpos: HPos.RIGHT //right align within the containers width
                 nodeVPos: VPos.BOTTOM //bottom align the nodes
                 spacing: 2 //spacing between the two corresponding nodes
                 content:
                 [
                    passwordLbl,
                    passwordTxt,
    
                 ]
              }
    
              submitBtn
           ]
        }
    
        //must override this function
        override function createView():Void
        {
           currentView = loginBox;
        }
    
    }
    

    Here a simple login form is created and the class extends the abstract class
    view. So, when the create() method (called automatically) of the View is called
    the createView() method of this class is called which will assign the loginBox to currentView.

    Similarly we create AdminPage class and the GuestPage class. Both extends the view class

    
    public class AdminPage extends View
    {
       /*
         write the code for what needs to be displayed in admin page
         For example: adminPageView.AdminPageView can be any node i.e.
         Group, Image, label, HBox, etc.
       */
       override function  createView():Void
       {
          currentView = adminPageView;
       }
    }
    
    public class GuestPage extends View
    {
        /*
          write the code for what needs to be displayed in guest page
          For example: guestPageView. GuestPageView can be any node i.e.
           Group, Image, label, HBox, etc.
         */
        override function createView():Void
        {
           currentView = guestPageView
        }
    }
    
     
  • mxshrestha 2:01 am on March 9, 2011 Permalink | Reply
    Tags: connecting to database in JavaFX, connecting to MySQL using JavaFx, JavaFX & MySQL, MySQL and javaFX   

    MySQL & JavaFx 

    Connecting to database in JavaFx is very similar to connecting to database in Java. Good thing about JavaFx is that it can leverage all Java libraries. So, here in this example we are going to use java.sql.* libraries and MySQL connector(must be downloaded). Here is a simple code to connect to MySQL.

    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.lang.Class;
    import java.sql.DriverManager;
    import java.lang.InstantiationException;
    import java.lang.IllegalAccessException;
    import java.sql.SQLException;
    import java.sql.PreparedStatement;
    
    public class DBConnection
    {
     var userName = "user";//username to connect to mysql
     var password = "user";//password to connect to mysql
     var driverClass = "com.mysql.jdbc.Driver";//driver class to connect to mysql
                                               //needs mysql connector jar
     var db_url = "jdbc:mysql://localhost/LOGIN";//LOGIN is the database.
     var connectionString:Connection;
    
     function getConnection():Connection
     {
       var conString: Connection = null;
       try
       {
          Class.forName(driverClass).newInstance();
          conString = DriverManager.getConnection(db_url, userName, password);
    
          if(not conString.isClosed())
          {
             println("Connection Successful");
          }
       }
       catch(ex : InstantiationException)
       {
          ex.printStackTrace();
       }
       catch(ex : IllegalAccessException)
       {
          ex.printStackTrace();
       }
    
       return conString;
     }
    
     public function login(userName:String, password:String): Boolean
     {
        connectionString = getConnection();
    
        var success:Boolean = false;
        var rs:ResultSet = null;
    
        var query:String = "SELECT FIRSTNAME FROM USERS WHERE USER_ID = ? AND PASSWORD = ?";
    
        try
        {
           var statement: PreparedStatement = connectionString.prepareStatement(query);
    
           statement.setString(1, userName);
           statement.setString(2, password);
    
           rs = statement.executeQuery();
    
           if(rs.first())
              success = true;
    
        }
        catch(ex : SQLException)
        {
           ex.printStackTrace();
        }
    
        return success;
      }
    }
    
    

    One thing we need to make sure is that the mysql connector jar
    is downloaded and is in the class path of the project. Also the database
    and the tables should exist.

     
  • mxshrestha 10:55 pm on March 1, 2011 Permalink | Reply
    Tags: , , , JavaFX layoutBounds, javaFx layouts, layout bounds in javaFx, , maxX, maxY, minX, minY   

    Bounds in JavaFX 

    Bounds in JavaFX:
    Bounds refers to the node’s size and position in JavaFx. A nodes rectangular bounds are represented by the Bounds class which provides init-only minX (minimum x value), minY (minimum y value), maxX (maximum x value), maxY (maximum y value) , width , height variables. The X/Y values can also be negative. When a node is created there are three different ways we can access the size and position of the nodes. i.e., boundsInLocal, boundsInParents, and layoutBounds.

    boundsInLocal – physical bounds in the node’s local coordinate grid (not the parent’s coordinate grid.), untransformed coordinate space, including shape geometry, space required for a non-zero strokeWidth that may fall outside the shape’s position/size geometry, the effect and the clip.

    boundsinParent – physical bounds of the node after ALL transform have been applied to the node’s coordinate space, including transforms[], scaleX/scaleY, rotate, translateX/translateY, and layoutX/layoutY. The rectangle will be defined in terms of the parent node’s coordinate system.

    layoutBounds – logical bounds used as basis for layout calculations; by default only includes a node’s shape geometry, however its definition may be overridden in subclasses. It does not necessarily correspond to the node’s physical bounds.

    It is important to understand that each node when created have its own coordinate grid systems that is different from its parents coordinate grid. For example, if we create a rectangle node and put it in the scene. The boundsInLocal references to the bounds of the rectangle within the coordinate grid of the rectangle node (includes the bound differences applied by the effect on the node), boundsInParent refers to the bounds of the rectangle within the coordinate grid of the scene (includes the bound differences applied by the effect on the node ), and the layoutBounds refers to the bounds within the coordinate grid of the rectangle node (doesn’t include bound differences applied by the effect and gives the actual shape geometry of the node).

    For example: for the following rectangle:

    var rect:Rectangle = Rectangle
    {
      translateX:10,
      translateY:10,
      x:130,
      y: 0;
      width: 120,
      height: 120
      fill: Color.BLACK
    }
    

    Rectangle Bounds In Local bounds:
    width: 120.0
    height: 120.0
    minX: 130.0 (x value specified)
    minY: 0.0 (y value specified)
    maxX: 250.0 (minX + width)
    maxY:120.0 (minY + height)

    Rectangle Bounds in Parent bounds:
    width: 120.0
    height: 120.0
    minX: 140.0 (x value + translateX. remember this refrences to the scene coordinate grid)
    minY: 10.0 (y value + translateY)
    maxX: 260.0 (minX + width)
    maxY: 130.0 (minY + height)

    Rectangle layout bounds:
    width: 120.0
    height: 120.0
    minX: 130.0
    minY: 0.0
    maxX: 250.0
    maxY: 120.0

    The layoutBounds bounds in this case is the same as the boundsInLocal bounds because no effect is applied to the rectangle. Now lets apply a drop shadow effect to the rectangle and see how the bounds change.

    var rect:Rectangle = Rectangle
    {
      translateX:10,
      translateY:10,
      x:130,
      y: 0;
    
      width: 120,
      height: 120
      fill: Color.BLACK
    
      effect: DropShadow
      {
        offsetX: 10
        offsetY:10
    
        color:Color.GREEN
        radius:20
    
      }
    }
    

    Rectangle Bounds In Local bounds:
    width: 160.0 (considers the difference due to the drop shadow effect)
    height: 160.0 (considers the difference due to the drop shadow effect)
    minX: 120.0 (considers the difference due to the drop shadow effect)
    minY: -10.0 (considers the difference due to the drop shadow effect. remember that bound values can be negative)
    maxX: 280.0 (minX + width)
    maxY: 150.0 (minY + height)

    Rectangle Bounds in Parent bounds:
    width: 160.0 (considers the difference due to the drop shadow effect)
    height: 160.0 (considers the difference due to the drop shadow effect)
    minX: 130.0 (considers the difference due to the drop shadow effect and is 130 here instead of 120 as in above because it adds the translateX value. This is because, it is in scene coordinate grid)
    minY:  0.0 (considers the difference due to the drop shadow effect and is 0 here instead of -10 as in above because it adds the translateY value. This is because, it is in scene coordinate grid)
    maxX:  290.0 (minX + width)
    maxY: 160.0 (minY + height)

    Rectangle layout bounds:
    width: 120.0  (actual width specified )
    height: 120.0 (actual height specified)
    minX: 130.0 (actual x specified)
    minY: 0.0 (actual y specified)
    maxX: 250.0 (minX + width)
    maxY: 120.0 (minY + height)

    Imortant points:
    Bounds minX/minY and maxX/maxY can be negative. ex: circle is centered on (0,0).
    layout bounds is a logical concept. ex: spin an icon without disturbing the layout of its neighbors
    Always use layoutBounds when measuring the current size and position of nodes for the purpose of the layout.
    All containers in javafx.scene.layout reference the node’s layoutBounds.
    if you want layoutBounds to match a node’s physical bounds(including effects, clip, and transform) then wrap it in a Group. ex: if you want a node to scale up on mouse-over and you want its neighbor to scoot over to make room for the magnified node.

    References made from:

    http://weblogs.java.net/blog/2009/07/09/javafx12-understanding-bounds#chase

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
Reply
e
Edit
o
Show/Hide comments
t
Go to top
l
Go to login
h
Show/Hide help
shift + esc
Cancel