Monday Feb 03, 2014

Some samples using GPIO and I2C with Pi4J

This is the code for:  GPIO pin using Java SE Embedded with Pi4J (get it here)

This is the code for: Pressure/Temperature sensor BMP180, using Java SE Embedded with Pi4J  (get it here)

This is the code for: Accelerometer/Temperature/Gyroscope sensor, using Java SE Embedded with Pi4J (get it here)(This is just a piece of the code only, it won't work on it's own)

Friday May 03, 2013

Beyond Beauty: JavaFX, I2C, Parallax, Touch, Raspberry Pi, Gyroscopes and Much More. (Part I)

I2C and the Rpi

When I think about realism on user interfaces, the first thing that comes to my mind is 3D.   Unfortunately, 3D and embedded are two worlds that don't go along very well.  When we think about embedded, we think about constrained devices, but it doesn't have to mean ugly interfaces.  Now we have Java SE Embedded (which includes JavaFX), it provides us with a great tool to create astonishing UI for embedded applications.

This was my inspiration for my next demo, what can I build, that could be cool, applied to embedded, and of course, how can I play with new hardware that I haven't played with it yet!  :-)  That was my new and exciting challenge.

The inspiration

The hardware:

  • Raspberry Pi was definitely the device, I could easily have Java and JavaFX on it.
  • I want to build an interface that reacts to the device orientation.  For the purpose of tracking positioning I used a combination of accelerometer + gyroscope, and the MPU-9150 Breakout from sparkfun electronics, was just perfect for this.  The MPU-9150 is a System in Package (SiP) that combines two chips: the MPU-6050, which contains a 3-axis gyroscope, 3-axis accelerometer, and an onboard Digital Motion Processor (DMP) capable of processing complex 9-axis MotionFusion algorithms; and the AK8975, a 3-axis digital compass. The supply voltage range was from 2.4V to 3.46V, just perfect for our RPi, and it uses I2C as a communication protocol also supported by RPi. 


The software

  • I'm using Oracle Java SE Embedded and JavaFX apis for the user interface. 
  • I'm using I2C for the communication protocol. Fortunately,  I found Pi4J apis that just do the job for me.  It has a great set of APIs to hide all I2C low level details, by exposing a really clean set of APIs, very easy to use.
  • The parallax effect.  Some time ago I saw a very cool applications using the Parallax effect, it provides a lot of realism to the scene without adding the extra processing cost of the 3D rendering.  Parallax effect is a scrolling technique in computer graphics, wherein background images move by the camera slower than foreground images, creating an illusion of depth in a 2D interface and adding realism to the immersion.  We see it everyday, just pay attention on how things move when you drive around.  



Getting I2C working on the Raspberry Pi

If you pay attention to the Raspberry Pi pins you will see that it has two pins for I2C, one for data's bus (SDA) and one for the clock (SCL).


Great!, I was ready to start connecting things...  But to my surprise, I2C is not enabled by default on the RPi, and there are few steps you need to follow.

Enabling I2C in the RPi

  • First go to:  /etc/modules and add the following lines:
    • i2c-bcm2708
    • i2c-dev
  • Install i2c-tools.  This is not required, but it's very handy for detecting devices and making sure everything works properly.
    • sudo apt-get install python-smbus
    • sudo apt-get install i2c-tools
  • There is a file called raspi-blacklist.conf, and by default SPI and I2C are part of this black list!
    • Edit /etc/modprobe.d/raspi-blacklist.conf  and comment out the lines
      • blacklist spi-bcm2708
      • blacklist i2c-bcm2708


Connecting the Gyroscope/Accelerometer to the Pi.

Connecting the board and the RPi is pretty straight forward.  I2C requires pullup resistors,  but the RPi provide them, so we just need to connect the MPU-9150 directly to the Pi, following the next diagram:

The MPU-9150 has a AD0 pin,  this allows you to set the last bit of the board's address, to either 0 (ground) or  1 (Vcc).  This allows us to connect two boards to the same bus.  In my case I just grounded this pin, then my board address is 0x68


Verifying the communication:

Once we connect the board to the RPi, we can continue to check if we can actually see it as a I2C device. 

  • Try running on your pi:  sudo i2cdetect -y 1  or sudo i2cdetect -y 0(0 for the 256 Pi model B).
  • You should be able to see your device on the table.  The following snapshot shows two I2C devices, one at address 40 and the second on address 70.


  • You should also see a couple of new entries under /dev:
    • spidev0.0
    • spidev0.1
    • I2c-0
    • I2c-1
  • If don't see any of these entries, try running:
    • sudo modprobe i2c-dev

The Hardware setup

This is the big picture of the demo setup.  I just mounted everything on a piece of wood, then, changes on the board position and direction will be reflected on the UI rendered on the screen.



The software


WiringPi Native library.

WiringPi is an Arduino wiring-like library written in C and released under the GNU_LGPLv3 license, which is usable from C and C++ and many other languages with suitable wrappers.  This library provides access to GPIOs pin, I2C and SPI interface, and UART lines.

WiringPi includes a command-line utility gpio which can be used to program and setup the GPIO pins. You can use this to read and write the pins and even use it to control them from shell scripts.



Pi4J

Provides a bridge between the native libraries (WiringPi) and Java for full access to the Raspberry Pi.

Features:
  • Wrapper classes for direct access to WiringPi Library from Java
  • Export & unexport GPIO pins
  • Configure GPIO pin direction
  • Configure GPIO pin edge detection
  • Control/write GPIO pin states
  • Pulse GPIO pin state
  • Read GPIO pin states
  • Listen for GPIO pin state changes (interrupt-based; not polling)
  • Automatically set GPIO states on program termination (GPIO shutdown)
  • Triggers for automation based on pin state changes
  • Send & receive data via RS232 serial communication
  • I2C Communication
  • SPI Communication
  • Extensible GPIO Provider interface to add GPIO capacity via expansion boards
  • Access system information and network information from the Raspberry Pi
  • Wrapper classes for direct access to WiringPi Library from Java


Installing and using Pi4J

  • First, get the APIs. From the Pi command line type:
    • wget http://pi4j.googlecode.com/files/pi4j-0.0.5.deb
  • Install the packages
    •   sudo dpkg -i pi4j-0.0.5.deb
  • Check the source files at:                
    • /opt/pi4j/lib                
    • /opt/pi4j/examples
  • Make sure you include the Pi4J lib folder in the classpath:        
    • javac -classpath .:classes:/opt/pi4j/lib/'*' ...
    • sudo java -classpath .:classes:/opt/pi4j/lib/'*' ...
  • Pi4J comes with a set of demos, you can build them and start from there. 
    • Build all demos:            
      • cd /opt/pi4j/examples            
      • ./build
  • At any time you can uninstall Pi4J
    • sudo dpkg -r pi4j


The Code:


First, we need to get the I2CBusI2CFactory class has a method called getInstance that allows us to do that.  Once we get the bus, we get the device itself (our board), just make sure you provide the correct address (did you ground or not the AD0 pin on your board?),  in our case we grounded AD0 and our address is x68)
.


public class Sensors {
   
     I2CBus bus;
     I2CDevice device;

  
    public Sensors() {
        System.out.println("Starting sensors reading:");

        // get I2C bus instance
        try {
           //get i2c bus
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");
           
           //get device itself
           device = bus.getDevice(0x68);
           System.out.println("Connected to device OK!");
   ...
   }
...
}


After getting the device, I thought I was going to get the readings right away, but it wasn't the case.  For the MPU-9150 few registries need to be set before the reading start:  (Find full description at the MPU_9150 Register Map and Description Revision)

  • Register 107 – Power Management 1 PWR_MGMT_1
This register allows the user to configure the power mode and clock source. It also provides a bit for resetting the entire device, and a bit for disabling the temperature sensor.



Parameters
:
DEVICE_RESET When set to 1, this bit resets all internal registers to their default values.
SLEEP When set to 1, this bit puts the MPU-9150 into sleep mode.
CYCLE When this bit is set to 1 and SLEEP is disabled, the MPU-9150 will cycle between sleep mode and waking up to take a single sample of data from active sensors at a rate determined by LP_WAKE_CTRL (register 108).
TEMP_DIS When set to 1,  this bit disables the temperature sensor.
CLKSEL 3-bit unsigned value. Specifies the clock source of the device.


  • Register 108 – Power Management 2  PWR_MGMT_2



    This register allows the user to configure the frequency of wake-ups in Accelerometer Only Low Power Mode.  This register also allows the user to put individual axes of the accelerometer and gyroscope into standby mode. 

    Parameters
    LP_WAKE_CTRL 2-bit unsigned value.  Specifies the frequency of wake-ups during Accelerometer Only Low Power Mode.
    STBY_XA When set to 1, this bit puts the X axis accelerometer into standby mode.
    STBY_YA When set to 1, this bit puts the Y axis accelerometer into standby mode.
    STBY_ZA When set to 1, this bit puts the Z axis accelerometer into standby mode.
    STBY_XG When set to 1, this bit puts the X axis gyroscope into standby mode.
    STBY_YG When set to 1, this bit puts the Y axis gyroscope into standby mode.
    STBY_ZG When set to 1, this bit puts the Z axis gyroscope into standby mode.

  • Register 27: Gyroscope Configuration  GYRO_CONFIG

    This register is used to trigger gyroscope self-test and configure the gyroscopes’ full scale range.



    The self-test for each gyroscope axis can be activated by controlling the XG_ST, YG_ST, and ZG_ST bits of this register.
    FS_SEL is a 2-bit unsigned value and it allows us to select the full scale range of gyroscopes.
  • Register 28: Accelerometer Configuration ACCEL_CONFIG

    This register is used to trigger accelerometer self test and configure the accelerometer full scale range.



    The self-test for each accelerometer axis can be activated by controlling the XA_ST, YA_ST, and ZA_ST bits of this register.

    Parameters:
    XA_ST When set to 1, the X - Axis accelerometer performs self - test
    YA_ST When set to 1, the Y - Axis accelerometer performs self - test
    ZA_ST When set to 1, the Z - Axis accelerometer performs self - test
    ACCEL _FS_SE 2-bit unsigned value . Selects the full scale range of accelerometers.
    ACCEL_HPF 3-bit unsigned value. Selects the Digital High Pass Filter configuration.

Now setting these registries looks like this:


public class Sensors {
   
    I2CBus bus;
    I2CDevice device;
  
    public Sensors() {
        System.out.println("Starting sensors reading:");

        // get I2C bus instance
        try {
           //get i2c bus
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");

           
           //get device itself
          
device = bus.getDevice(0x68);
           System.out.println("Connected to device OK!");
  

           //start sensing, using config registries 6B  and 6C   
          
device.write(0x6B, (byte) 0b00000000);
           device.write(0x6C, (byte) 0b00000000);

           System.out.println("Configuring Device OK!");
           
           //config gyro
          
device.write(0x1B, (byte) 0b11100000);
           //config accel   
          
device.write(0x1C, (byte) 0b00011001);
           System.out.println("Configuring sensors OK!");
        
           startReading();

        } catch (IOException e) {
           System.out.println(e.getMessage());
        }
   }

...
}




Now how to read the gyroscope and accelerometers values?  The values for the accelerometer measurements are stored in registers 59 to 64.  Each measurement is a 16-bit value, stored in two consecutive registers, as shown in the following table.



Similarly, the gyroscope measurements are stored in registers 67-72.


Now the code will look like this:




public class Sensors {
   
    I2CBus bus;
    I2CDevice device;

    byte[] accelData, gyroData;
  
    public Sensors() {
        System.out.println("Starting sensors reading:");

        // get I2C bus instance
        try {
           //get i2c bus
           bus = I2CFactory.getInstance(I2CBus.BUS_1);
           System.out.println("Connected to bus OK!");
           

           //get device itself
          
device = bus.getDevice(0x68);
           System.out.println("Connected to device OK!");
  

           //start sensing, using config registries 6B  and 6C   
          
device.write(0x6B, (byte) 0b00000000);
           device.write(0x6C, (byte) 0b00000000);

           System.out.println("Configuring Device OK!");
           
           //config gyro
          
device.write(0x1B, (byte) 0b11100000);
           //config accel   
          
device.write(0x1C, (byte) 0b00011001);
           System.out.println("Configuring sensors OK!");
        
           startReading();

        } catch (IOException e) {
           System.out.println(e.getMessage());
        }
   }

 
    //Create a separate thread for reading the sensors
   
public void startReading() {

        Task task = new Task<Void>() {
            @Override
            public void call() {
                try {

                    readingSensors();
                } catch (IOException e) {
                }
                return null;
            }
        };

        new Thread(task).start();
    }



    private void readingSensors() throws IOException {
        while (true) {
           accelData = new byte[6];
           gyroData = new byte[6];


           //You can read one registry at a time,
           //or you can read multiple consecutive ones,
           //in our case we are reading 6 consecutive registries
           //from 0x3B, meaning we are reading all the
           //accelerometer measurements

           int r = device.read(0x3B, accelData, 0, 6);
           if (r != 6) {
             System.out.println("Error reading accel data, < 6 bytes");
           }

           //Convert the values to integers, using the
           //helper method asInt

           int accelX = asInt(accelData[0]) * 256 + asInt(accelData[1]);
           int accelY = asInt(accelData[2]) * 256 + asInt(accelData[3]);
           int accelZ = asInt(accelData[4]) * 256 + asInt(accelData[5]);

        
           System.out.println("accelX: " + accelX + ", accelY: " + accelY + ", accelZ: " + accelZ);

         //Reading gyroscope measurements.
         r = device.read(0x43, gyroData, 0, 6);
         if (r != 6) {
           System.out.println("Error reading gyro data, < 6 bytes");
         }
        

         //Convert the values to integers, using the
         //helper method asInt

         gyroX = (asInt(gyroData[0]) * 256 + asInt(gyroData[1]));
         gyroY = (asInt(gyroData[2]) * 256 + asInt(gyroData[3]));
         gyroZ = (asInt(gyroData[4]) * 256 + asInt(gyroData[5]);

         System.out.println("gyroX: " + gyroX + ", gyroY: " + gyroY + ", gyroZ: " + gyroZ);   
        

         //Use the values as you want
         ...
       }
    }


  //Helper method
  private static int asInt(byte b) {
        int i = b;
        if (i < 0) {
            i = i + 256;
        }
        return i;
    }

}



After you get the values from the accelerometer and gyroscope, you can use them as you wish.  In my next blog entry we see how this values are going to be used to update the UI to provide realism to our interface.

Hope you enjoyed!
  See video of the demo here

Monday Apr 15, 2013

Getting Started with Java ME Embedded 3.3 on Keil Board


Today we have a great news in the embedded site: we announced the availability of Java ME Embedded 3.3 for ARM Cortex M3!

In this post I want you to show you how to create an application that turns on and off some of the LEDs available on the Keil board.  We will be using the Device Access API that provides interfaces and classes for communicating with and controlling peripheral devices attached to the board. 

Join me in this exciting trip, even if you don't have a board yourself, you can still use the emulator to run this program.

What do you need:
  1. Software:
  2. Hardware
    • Desktop computer:
      • Windows XP or later with two USB ports
    • Keil MCBSTM32F200 Cortex Board
    • Hardware debugger
    • ULINK ME or ULINK 2
    • MicroSD card SD adapter, for connecting to the desktop computer
    • Networking LAN cable with RJ-45 interface

For full instructions on how to configure your system, please check out the two videos I've created at our Java Channel in YouTube  (videos Part I, Part II).


Locating the LEDs

If you pay attention to the board, you can locate at the left hand side of the screen (bottom of the screen from the image bellow), a line of 8 small leds, 4 buttons and a small joystick.  These present a great opportunity for us to test the capabilities of the Java ME Embedded software before we connect any external device.
Keil Board

Some of these peripherals are preconfigured and ready to use. The LEDs and Buttons are part of the GPIO preconfigured pins and the joystick is part of the I2C preconfigured devices.  (Full details available at the Device Access API guide.)

For this particular demo, I'm going to use the first 4 LEDs:


Peripheral ID
Peripheral
Name
Mapped To
Configuration
1
LED1
LED PH3
portNumber = 7
pinNumber = 3
direction = GPIOPinConfig.DIR_OUTPUT_ONLY
mode = GPIOPinConfig.MODE_OUTPUT_PUSH_PULL
trigger = GPIOPinConfig.TRIGGER_NONE
initValue = false
2
LED2
LED PH6
portNumber = 7
pinNumber = 6
direction = GPIOPinConfig.DIR_OUTPUT_ONLY
mode = GPIOPinConfig.MODE_OUTPUT_PUSH_PULL
trigger = GPIOPinConfig.TRIGGER_NONE
initValue = false
3
LED3
LED PH7
portNumber = 7
pinNumber = 7
direction = GPIOPinConfig.DIR_OUTPUT_ONLY
mode = GPIOPinConfig.MODE_OUTPUT_PUSH_PULL
trigger = GPIOPinConfig.TRIGGER_NONE
initValue = false
4
LED4
LED PH10
portNumber = 8
pinNumber = 10
direction = GPIOPinConfig.DIR_OUTPUT_ONLY
mode = GPIOPinConfig.MODE_OUTPUT_PUSH_PULL
trigger = GPIOPinConfig.TRIGGER_NONE
initValue = false

The code

One important class in the Device Access API is the PeripheralManager.   This class provides methods for opening and registering peripheral devices that can be handled as Peripheral instances.  In our sample, we want open the GPIO pin associated with each LED.

The simplest way to open the GPIOPin is by calling the static method open from PeripheralManager, and provide the platform-specific numerical ID of this pin.  For example:

        GPIOPin pin1 = (GPIOPin) PeripheralManager.open(1);

If you need to specify more detailed  information about the GPIOPin you are trying to open, you can use a GPIOPinConfig object.  The GPIOPinConfig class encapsulates the hardware addressing information, and static and dynamic configuration parameters of a GPIO pin.

        GPIOPinConfig led3 = new GPIOPinConfig(
               7,            // Port Number
               7,            // Pin Number
               GPIOPinConfig.DIR_OUTPUT_ONLY,               //  Direction
               GPIOPinConfig.MODE_OUTPUT_PUSH_PULL,        
//  Mode
               GPIOPinConfig.TRIGGER_NONE,                 
//  Trigger
               true);     
// Init value

        GPIOPin pin3 = (GPIOPin) PeripheralManager.open(led3);


A PeripheralConfigInvalidException is thrown when attempting to open a peripheral device with an invalid or unsupported configuration.

Now, the following code will simply get the GPIO pin associated with the first 4 LEDs, and switch their status to on and off every second.

package keilleds;

import com.oracle.deviceaccess.PeripheralManager;
import com.oracle.deviceaccess.gpio.GPIOPin;
import com.oracle.deviceaccess.gpio.GPIOPinConfig;
import javax.microedition.midlet.*;

/**
 * @author acaicedo
 */
public class IMlet extends MIDlet {

       public void startApp() {
        System.out.println("GPIO test");

        //Configure pin 7
        GPIOPinConfig led1 = new GPIOPinConfig(
                7,
                3,
                GPIOPinConfig.DIR_OUTPUT_ONLY, 
                GPIOPinConfig.MODE_OUTPUT_PUSH_PULL,
                GPIOPinConfig.TRIGGER_NONE,
                true);


        GPIOPinConfig led2 = new GPIOPinConfig(
                7,
                6,
                GPIOPinConfig.DIR_OUTPUT_ONLY,
                GPIOPinConfig.MODE_OUTPUT_PUSH_PULL,
                GPIOPinConfig.TRIGGER_NONE,
                false);
        GPIOPinConfig led3 = new GPIOPinConfig(
                7,
                7,
                GPIOPinConfig.DIR_OUTPUT_ONLY,
                GPIOPinConfig.MODE_OUTPUT_PUSH_PULL,
                GPIOPinConfig.TRIGGER_NONE,
                true);

        GPIOPinConfig led4 = new GPIOPinConfig(
                8,
                10,
                GPIOPinConfig.DIR_OUTPUT_ONLY,
                GPIOPinConfig.MODE_OUTPUT_PUSH_PULL,
                GPIOPinConfig.TRIGGER_NONE,
                false);
       
        GPIOPin pin1 = null;
        GPIOPin pin2 = null;
        GPIOPin pin3 = null;
        GPIOPin pin4 = null;
       
        try {
            pin1 = (GPIOPin) PeripheralManager.open(led1);
            pin2 = (GPIOPin) PeripheralManager.open(led2);
            pin3 = (GPIOPin) PeripheralManager.open(led3);
            pin4 = (GPIOPin) PeripheralManager.open(led4);
           
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        if (pin1 == null || pin2 == null |
| pin3 == null || pin4 == null) {
            System.out.println("Error connecting to Pins");
        } else {
            try {
                for(int i=0; i<10; i++){
                    pin1.setValue(!pin1.getValue());// If the LED was off,
                                       //
turn it on, otherwise turn it on.
                    pin2.setValue(!pin2.getValue());
                    pin3.setValue(!pin3.getValue());
                    pin4.setValue(!pin4.getValue());
                    Thread.sleep(1000);                 
                }
                // turn all LEDs off at the end
                pin1.setValue(false);
                pin2.setValue(false);
                pin3.setValue(false);
                pin4.setValue(false);
            } catch (Exception e) {
                System.out.println("Noo");
            }

        }
    }
   
   
    public void pauseApp() {
    }
   
    public void destroyApp(boolean unconditional) {
    }
}


You can find the NebBeans project in here.

Running the code

Now lets run the code.  If you are lucky and have a Keil board lets have it connected to your computer and added to NetBeans.

  • Start NetBeans and verify that you have the Java ME SDK 3.3 plugin installed. 
  • Open KeilLEDs project.
  • Click on the phone icon, under IMlet.java Navigator to add your Keil board.  If you don't see this navigator, you probably forgot to install the plugin.  Go back to the top of this blog and make sure you install it before you continue.
    • Enter the ip address for your device, in my case I'm using static ip address 10.0.0.11
    • Click Next, make sure it's detected, and finally click on Finish.
Adding your
device
  • Select the execution model for the project:
    • Right click to your project, and go to Properties.
    • Select Platform from Category
    • Select IMPNGExternalDevice1 from the device list.
    • Click Ok.
Selecting your
device 
  • Run your project.
    • You should see the LEDs going on and off.  See sample here.

Congratulations, you just run your first Java ME Embedded application on your Keil board.

Now, if you are not so lucky to have a board with you, this is the way you can test your application using the Java ME SDK emulators.

  • Go to Tools -> Java ME -> Custom Device Editor

Adding an
emulator
  • Now you can create your own Devices, with the configuration you want.
    • First,  select IMP-NG and select New...
Adding device emulator
    • In the new screen you can:
      • Provide a name to your new device
      • Add the Pin and Ports you want to simulate.
      • The following image is an example that maps the code we previously described.  I've created two ports, 7 and 8 that maps the description of the Keil board.  Then I've created 4 Pins, again that maps to the LED description provided by Keil.
      • You could use any pin you want, as we are only running the code on an emulator, I just wanted to map this emulator as much as possible to the real device, in our case the Keil board.
Configuring your
device
  • Now, select the emulator as your new platform
    • Right-click on your project and select Properties.
    • Select Platform from Category
    • Select your new device, from the device list.  In our case MyVirtualKeilBoard.
Selecting your emulator
  • Run your project
    • Now that we are running on an emulator, you will see the emulator screen been displayed.
    • Click on the GPIO Pins tab, and see the LEDs change your value from High <-> Low.
Running on my
device

Now that we have a basic idea of the Device Access API you can start creating more interesting demos, connecting real devices to your board. Lets have FUN!






Tuesday Feb 26, 2013

Managing Multiple Screens in JavaFX. (Part II)

After finishing with my first application (previous blog), I moved to my second talk I was delivering at JavaOne 2012. Now I was looking to build another UI application, for a small screen and constrained devices. I was looking into having multiple screens, but with very few UI components; I just needed to collect data from the web and displayed it. Looking at my previous framework it wasn't a good fit for this new scenario, and of course there isn't a unique solution for all applications. This is what I was trying to achieve:

  • Build an application for a city information app.

  • An application where you can explore the city's places.

  • Or you can check the map for places of interests.

  • Check the weather

  • Or even change the city

I wanted to build a more dynamic application, where screens just slide in and out... from top, bottom, right and left, like the red arrows implies. I decided to use a technique commonly used in game development, where there is a big background image, and we have a view port, like a small window, and it's by moving this window around that we get the illusion of screen changes. Notice that having a wide background picture create a great navigation effect!

    

  

Points to consider:

  • For this application I used NetBeans and JavaFX SceneBuilder, which are my favorite tools.

  • A very important consideration, from my point of view, is to have a good long background image. This will give you a nice navigation effect without any extra programming cost. It just looks good.

  • Only one big screen is designed in Scene Builder, one fxml file and one controller class. Very simple!

  • Think out of the box, your application doesn't always have to have conventional buttons, labels and other components. Navigation doesn't need to be in one direction!. If you design your UI interface correctly, the user will intuitively navigate through it without any problem! Nice looking and modern interfaces doesn't mean it will be difficult to use.

  • Customize your application using CSS. This application uses CSS heavily, giving a nice and unique touch.


    An example of the semi-transparent gray Panel areas styling looks like this:


       .my-gradientpane {
         -fx-background-radius: 10;
         -fx-background-color:
                radial-gradient(radius 100%,
                                 derive(-fx-base,-60%),
                                 derive(-fx-base,-80%)),
                derive(-fx-base,-40%),
                radial-gradient(radius 100%,
                                 derive(-fx-base,-60%),
                                 derive(-fx-base,-80%));
         -fx-background-insets: 0,1,2;
       }


    Or customizing your ChoiceBox could be something like this:



       .choice-box {
           -fx-background-color:
                  radial-gradient(radius 100%,
                                  derive(-fx-base,-60%),
                                  derive(-fx-base,-80%)),
                  derive(-fx-base,-40%),
                  radial-gradient(radius 100%,
                                  derive(-fx-base,-60%),
                                  derive(-fx-base,-80%));
           -fx-background-insets: 0 0 -1 0, 0, 1, 2;
           -fx-background-radius: 25, 25, 24;
           -fx-padding: 0.0em 0.5em 0.0em 0.0em;
           -fx-alignment: CENTER;
           -fx-content-display: LEFT;
       }


    You can find more detailed information about CSS here.

  • The viewport in my application was simply a container; in this case a Panel. This panel was smaller than the image in the background, it was just the screen's size. The rest of the screens were just not visible.

  • Moving around screens is easy. All the screens have the same width and height, so only a simple TranslateTransition was required here. A sample of this:



      ...
         @FXML
         private void showPlaces(MouseEvent event) {
            moveScreen(0, -MyEmbeddedApp.DEVICE_HEIGHT);
         }
     
         @FXML
         private void showWeather(MouseEvent event) {
            moveScreen(MyEmbeddedApp.DEVICE_WIDTH, 0);
         }
     
         private void moveScreen(int toX, int toY) {
            TranslateTransition moveMe = TranslateTransitionBuilder.
                     create().
                     toX(toX).
                     toY(toY).
                     duration(Duration.seconds(0.5)).
                     node(pane).
                     build();
                     moveMe.play();
         }
      ...


    The annotation @FXML in front of the showPlaces and showWeather methods is to be able to bind these methods to the UI components in your fxml code. More information about this can be found here.

This concludes this second part of how to manage applications with multiple screens using JavaFX. As you can see, there isn't a one-size-fits-all solution, but it's definitely a lot of fun when you need to design your UI interfaces. Have fun, design, think out of the box, and make the life of the user a bit easier and more enjoyable.

You can also see a related video I've created on our YouTube Java Channel, so you can see these applications live.

Thursday Feb 14, 2013

Manejando Multiples Pantallas en JavaFX (Parte I)

(English version)

Una de las mejores cosas de mi trabajo es que tengo la oportunidad de escribir código y jugar con las últimas technologias. He sido desarrolladora de JavaFX ya por varios años y he creado todo tipo de demostraciones. El año pasado me encontré con un problema que algunos de ustedes pueden de estar teniendo hoy en dia: Como navigar entre pantallas y como manejar fácilmente el stack the pantallas en nuestro scene graph? Esta es la razón por al cual me he decidido a escribir este blog y compartir con ustedes este pequeno framework que escribi para mi aplicacion.

Para JavaOne 2012 decidí crear una aplicacion para un casino, y necesitaría una pantalla diferente para cada juego:

Crear las pantallas fue la parte mas fácil: Utilizé NetBeans y JavaFX Scene Builder.


Para NetBeans hay varias opciones:

  • Puedes crear New Project, y seleccionar JavaFX FXML Application. Esta opción genera un projecto que contiene 3 archivos: un archivo fxml, una clase controlladora, y una clase main. El archivo fxml es donde todos los componentes the la interfaz gráfica con definidos. El controlador, tiene la injeccion de los elementos fxml junto con algunos métodos utilizados por dicha interfaz gráfica. Finalmente, la clase main carga el archivo fxml, y comienza la ejecucion de la applicación.

  • La segunda opición es a partir de un projecto existente. Puedes hacer click derecho en el projecto y seleccionar Add Empty fxml file. Una pantalla te preguntara si deseas la creación del controllador asociado con el nuevo archivo fxml, en mi opinion, si se debe de crear esta clase controladora y mas tarde en este blog miraremos por que. A diferencia de la opción anterior, en este caso no se crea una clase main, y en algún lugar de nuestro código estamos a cargo de cargar y desplegar los componentes gráficos creados en el archivo fxml.


A partir del fxml inicial, podemos editar fácilmente este archivo usando JavaFX Scene Builder. Es verdaderamente fácil de usar, y puedes encontrar tutoriales hacerca de esto aqui.

Ahora, todo parece muy simple, verdad? Bueno, no tanto. A medida de que vamos creando las pantallas, nos encontraremos que tenemos un montón de archivos fxml y un montón de clases controladoras, una por cada pantalla creada. Esto parece rasonable, ya que no queremos por ningún motivo tener la definición de todas las pantallas en un solo archivo fxml. Pero como manejarlas?


Miremos que debemos de tener en cuenta:

  • Lo primero que se nos viene a la cabeza es utilizar un StackPane, correcto? Ponemos todas las pantallas en este Stack, una encima de la otra, y la que este en el tope del Stack es la que sería desplegada. Para cambiar de pantalla, sería tan fácil como cambiar de posición las pantallas en dicho Stack. Esto, aunque parece simple, no sería buena idea, ya que el rendimiento de la aplicación se veria seriamente afectado. El scene graph sería inmenso, y cargado de componentes gráficos que no son nisiquiera visibles. Uno de las primeras reglas en JavaFX para tener buen rendimiento es mantener el scene graph pequeño.

  • Definitivamente deseamos mantener archivos fxml separados, uno por cada pantalla. El diseño y el mantenimiento de estos serán muchisimo mas fácil de esta manera.

  • También tiene sentido tener un controlador por cada pantalla. De nuevo, queremos mantener separados no sólo los componentes gráficos sino tambien los comportamientos asociados a estos.

  • Necesitamos definir una navegacion limpia y fácil entre las pantallas.

  • Una vez más, MANTIENE el scene graph pequeño!

Entonces, que podríamos hacer?

  • StackPane sigue siendo una opción excelente como contenedor, simplemente se debe manejar de forma apropiada. En el framework que you cree, el stack pane sólo posee una pantalla en el stack al tiempo. Para mi aplicación yo opté por una imagen común como fondo de la aplicación, asi las transiciones entre pantallas serían mas fáciles. Para pasar a una nueva pantalla, una serie de animaciones tienen lugar. Por simplicidad de este framework utilicé "fade transitions", pero puedes cambiar y utilizar la transición que desees.
    La imagen de fondo de la applicación siempre permanece en el scene graph, y es visible todo el tiempo. Para movernos a una nueva pantalla, la primera transicion 'fade' tiene lugar, haciendo desaparecer los componentes graficos de la pantalla actual. El framework utiliza un EventHandler, el cual será notificado cuando esta transición 'fade' termine. Cuando esto sucede, pasamos a retirar los components de la pantalla que estaba siendo desplegada y que en este momento ya son invisibles. Luego adicionamos los componentes gráphicos de la nueva pantalla (pantalla a ser desplegada) que por defecto son invisibles, pasando luego a ejecutar una nueva transicion en la que hacemos visibles todos sus componentes. De esta manera, solo una pantalla esta cargada en el scene graph y no se vera afectada el buen rendimiento de la aplicación. Aqui estan los pasos a seguir:



    • Mostrar la pantalla principal

    • El usuario selecciona un juego

    • La pantalla actual empieza a desaparecer (transición). Al terminar, esta es retirada el scene graph y la nueva pantalla comienza a hacerce visible.

    • Hasta que finalmente la nueva pantalla es completamente visible.

    • El StackPane termina tan sólo con una pantalla en su scene graph.
    • Con este método, se puede especificar cualquier transicion deseada entre pantallas. Estas pueden entrar de arriba hacia abajo, or entrar horizontalmente por uno de los lados: puedes implementar la animación que desees.


Ahora miremos el código:

  1. Primero, todas las pantallas necesitan saber sobre su padre, en nuestro caso fue la pantalla main, ya que necesitamos poder regresar al menu principal una vez el usuario termine de jugar, o simplemente porque el usuario desee seleccionar un nuevo juego. Para esto necesitaremos una interfaz común (ControlledScreen), con un método para la injección del padre(setScreenParent).


      public interface ControlledScreen {

         //This method will allow the injection of the Parent ScreenPane
         public void setScreenParent(ScreensController screenPage);
      }

  2. Por cada pantalla mantenemos un archivo fxml separado, al igual que una clase controladora, como lo mensionamos al principio de este blog. Cada controlador debe implementar ControlledScreen, para que todos ellos compartan el mismo tipo, y podamos mas tarde asociara el padre a cada pantalla.


      public class Screen1Controller implements Initializable,
                                                ControlledScreen {

         ScreensController myController;

         @Override
         public void initialize(URL url, ResourceBundle rb) {
             // TODO
         }

         public void setScreenParent(ScreensController screenParent){
            myController = screenParent;
         }


         //any required method here
      }


    • Ahora que cada controlador tiene la referencia de su padre, podemos pasar a definir los métodos que realizarán la navegación. Por ejemplo, si deseamos regresar a la pantalla principal de uno de los juegos, debemos ejecutar el siguiente método:


         @FXML
         private void goToMain(ActionEvent event){
           myController.setScreen(ScreensFramework.MAIN_SCREEN);
         }

  3. Necesitamos una nueva clase (ScreensController) para majenar las pantallas:

    • Esta clase de heredar StackPane, ya que parece ser la opción mas adecuada para nuestro escenario.


         public class ScreensController extends StackPane {


    • ScreensController contiene un HashMap llamado screens. Esta collección contiene parejas construídas por el identificador de la pantalla junto al nodo que representa la raiz de su scene graph.


         private HashMap<String, Node> screens = new HashMap<>();


    • Esta clase debe definir métodos para addicionar, cargar y mostrar la pantalla adecuada:

      • addScreen(String id, Node screen) adiciona una pareja (id, screen) al HashMap screens.


           public void addScreen(String name, Node screen) {
               screens.put(name, screen);
           }

      • loadScreen(String id, String resource) Este método carga el archivo fxml especificado por resource, y obtiene el nodo raiz para you pantalla. También podemos obtener el controlador asociado con la pantalla, esto nos permitirá configurar el padre. Esto es posible ya que todos los controladores comparten el mismo tipo ControlledScreen.
        Finalmente, la pantalla es adicionada al hash map llamado screens. Como se puede observar en el código, el archivo fxml que se ha cargado, aun no se ha adicionado al scene graph, osea que aun no es desplegado por JavaFX.


           public boolean loadScreen(String name, String resource) {
             try {
               FXMLLoader myLoader = new
                       FXMLLoader(getClass().getResource(resource));
               Parent loadScreen = (Parent) myLoader.load();
               ControlledScreen myScreenControler =
                      ((ControlledScreen) myLoader.getController());
               myScreenControler.setScreenParent(this);
               addScreen(name, loadScreen);

               return true;
             }catch(Exception e) {
               System.out.println(e.getMessage());
               return false;
             }
           }

      • setScreen(String screenName). Este método muestra la pantalla especificada con el identificador dado.

        • Primero verificamos si la panatalla reconocida por ese identificador ha sido cargada previamente.

        • También tenemos que chequear si hay ya una pantalla desplegada (necesitamos entonces hacer transiciones entre pantallas), o si esta es la primera pantalla a ser mostrada (simplemente se muestra la pantalla).

        • Si ya existe una pantalla, ejecutamos la transicion y definimos el eventHandler para que se haga cargo de la ejecución, una vez termine esta transición.

        • Una vez la antigua pantalla se hace invisible, se remueve del scene graph, y se adiciona la nueva. De nuevo, una animación es realizada para mostrar la nueva pantalla.


           public boolean setScreen(final String name) {

             if(screens.get(name) != null) { //screen loaded
               final DoubleProperty opacity = opacityProperty();

               //Is there is more than one screen
               if(!getChildren().isEmpty()){
                 Timeline fade = new Timeline(
                   new KeyFrame(Duration.ZERO,
                                new KeyValue(opacity,1.0)),
                   new KeyFrame(new Duration(1000),

                       new EventHandler() {

                         @Override
                         public void handle(ActionEvent t) {
                           //remove displayed screen
                           getChildren().remove(0);
                           //add new screen
                           getChildren().add(0, screens.get(name));
                           Timeline fadeIn = new Timeline(
                               new KeyFrame(Duration.ZERO,
                                      new KeyValue(opacity, 0.0)),
                               new KeyFrame(new Duration(800),
                                      new KeyValue(opacity, 1.0)));
                           fadeIn.play();

                         }
                       }, new KeyValue(opacity, 0.0)));
                 fade.play();
               } else {
                 //no one else been displayed, then just show
                 setOpacity(0.0);
                 getChildren().add(screens.get(name));
                 Timeline fadeIn = new Timeline(
                     new KeyFrame(Duration.ZERO,
                                  new KeyValue(opacity, 0.0)),
                     new KeyFrame(new Duration(2500),
                                  new KeyValue(opacity, 1.0)));
                 fadeIn.play();
               }
               return true;
             } else {
                 System.out.println("screen hasn't been loaded!\n");
                 return false;
           }
          

    • Tambien necesitamos un método unloadScreen(String name). Este simplemente remueve la pantalla de nuestra hash map, reportando el status de esta operación.


         public boolean unloadScreen(String name) {
           if(screens.remove(name) == null) {
             System.out.println("Screen didn't exist");
             return false;
           } else {
             return true;
           }
         }


  4. Ahora lo único que necesitamos es comenzar a utilizar el framework. Aqui esta una pequeña parte de código que muestra como hacerlo.


       public class ScreensFramework extends Application {

         public static final String MAIN_SCREEN = "main";
         public static final String MAIN_SCREEN_FXML = "main.fxml";
         public static final String POKER_SCREEN = "poker";
         public static final String POKER_SCREEN_FXML =
                                              "poker.fxml";
         public static final String ROULETTE_SCREEN = "roulette";
         public static final String ROULETTE_SCREEN_FXML =
                                              "roulette.fxml";

         @Override
         public void start(Stage primaryStage) {

           ScreensController mainContainer = new ScreensController();
           mainContainer.loadScreen(ScreensFramework.MAIN_SCREEN,
                                ScreensFramework.MAIN_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.POKER_SCREEN,
                                ScreensFramework.POKER_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.ROULETTE_SCREEN,
                                ScreensFramework.ROULETTE_SCREEN_FXML);


           mainContainer.setScreen(ScreensFramework.MAIN_SCREEN);

           Group root = new Group();
           root.getChildren().addAll(mainContainer);
           Scene scene = new Scene(root);
           primaryStage.setScene(scene);
           primaryStage.show();
         }
       ...


Este framework fue de bastante ayuda para la creación de mi aplicación y espero que también sea de utilidad para usteded. Pueden encontrar la implementación de este framework, junto con tres clases para verificar que todo funcione en este link.

Tambien hay un video asociado a este blog que pueden encontrar aqui.

Friday Feb 08, 2013

Managing Multiple Screens in JavaFX. (Part I)

(Versión en Español)

One of the best things about my job is that it give me the opportunity to write code and play with the latest technologies. As a JavaFX developer I've created all sort of demos, and last year I faced an issue many developer might be facing today: How to transition between screens and how to manage the screen's stack? That is the reason why I've decided to write about my experiences with it, and to share with you a small framework I wrote for that.

For JavaOne 2012 I decided to create a Casino demo, and I needed to have multiple screens, one for each game:

Creating the screens was the easiest part: I used NetBeans in conjunction with JavaFX Scene Builder.


From NetBeans you have multiple options:

  • You can create a New Project, and select JavaFX FXML Application. This option will generate a project containing three files: a fxml file, a java controller and a main class. The fxml file is where all your UI components will be define. The java controller class has the fxml elements injections along with some methods used by the UI. Finally, the main class loads the fxml file, and start the execution of your application.

  • Second option is from an existent project. You can right click your project and select Add Empty fxml file. You will be prompted to acknowledge the creation of a controller associated with this new fxml file, which I recommend to do!. Different from the previous option, in this case no main class will be created, and somewhere in your code you are in charge of loading and displaying your fxml elements.


Once you have the initial fxml file, you can edit it using the JavaFX Scene Builder. It's really easy to use, and you can find some tutorials about it here.

Now, things seem to be really easy, right? Well, not quite. As you start creating your screens, you find yourself with a bunch of fxml files and controllers, one per each screen. This seems reasonable, as we don't want to place all the screens in a single fxml file, but how to manage them?


Here are a few things to keep in mind:

  • StackPane seems to be the first option you can thing of, right? Just have all the screens stacked one on top of each other, and the one on top gets displayed. Changing screens will be just switching places in the stack. This is not a very good idea, as we might be encountering some performance issues. The scene graph will be huge, and loaded with a lot of UI components that are not even visible. Keeping your scene graph small is the first trick for a good performance in your JavaFX application.

  • We definitely want to keep separate fxml for each screen, designing and maintaining the screens will be a much easier job.

  • One controller per screen also makes sense. One more time, we want to maintain separate screens elements and behaviors.

  • We need to define clean and easy navigation among the screens.

  • Once again, we need to keep our scene graph small.

Then, what should we do?

  • StackPane still is a great option for the container, we just need to manage it properly. In the proposed framework, we only have one screen stacked at a time. In our design, I opted for a common background, so the transition between screens was really smooth. When we are transitioning to a new screen, I play a couple of animations. As I've mentioned before I just used fade transitions, but you can customize your framework and have any transition you want. The background always stays there, and the first fade transition takes place, fading out the current screen. The framework implements an EventHandler, so we can listen when this fading process ends, as we need to remove the already invisible screen, and show the new one by adding it to the scene graph and playing a fade-in animation. Only one screen is uploaded in the scene graph. This allows us to keep it as light as possible, and we don't have a negative impact in performance. Here are the steps:



    • Display main screen

    • User select a game

    • The current screen starts to fade out. Once it finishes, the old screen gets remove from the scene graph and the new screen start to fade in.

    • Now the new screen is totally visible (opacity 1), and our graph stays light.

    • The StackPane finishes with only one screen in its tree.
    • With this approach, you can define any transition between the screens. You can drop the new screen from the top, or you can slide in the new screen from any side; you can use any animation you can think of.


Now, lets have a look at the code:

  1. First, all the screens need to know about their parent, in our case the main screen, as we need to be able to return to the main menu once we finish playing, perhaps to choose a different game. A common interface will do the trick (ControlledScreen), with a method for parent injection (setScreenParent), so we can initialize each screen's parent.


      public interface ControlledScreen {

         //This method will allow the injection of the Parent ScreenPane
         public void setScreenParent(ScreensController screenPage);
      }

  2. For each screen, we keep a separate fxml file, and a controller java file, as we mentioned at the beginning of the blog. Each controller class should implement the ControlledScreen, so all of them shared the type, and we can set the screen's parent later on.


      public class Screen1Controller implements Initializable,
                                                ControlledScreen {

         ScreensController myController;

         @Override
         public void initialize(URL url, ResourceBundle rb) {
             // TODO
         }

         public void setScreenParent(ScreensController screenParent){
            myController = screenParent;
         }


         //any required method here
      }


    • Now as each controller class has a reference to the parent screen, you can define methods to perform the correct navigation. For example if you want to go back to main screen from one of the games, you just need to call somewhere the following method.


         @FXML
         private void goToMain(ActionEvent event){
           myController.setScreen(ScreensFramework.MAIN_SCREEN);
         }

  3. We need a new class (ScreensController) for managing the screens:

    • This class will extend StackPane, as it seems to be a perfect choice for our scenario.


         public class ScreensController extends StackPane {


    • ScreensController will have a HashMap called screens. This collection contains pairs formed by the screen's ID and the node representing the top of the screen's scene graph.


         private HashMap<String, Node> screens = new HashMap<>();


    • This class has methods for adding, loading and setting the screens:

      • addScreen(String id, Node screen) add the pair (id, screen) to the HashMap screens.


           public void addScreen(String name, Node screen) {
               screens.put(name, screen);
           }

      • loadScreen(String id, String resource) This method loads the fxml file specified by resource, and it gets the top Node for the screen. We can also get the controller associated to this screen, which allows us to set the parent for the screen, as all the controllers shared the common type ControlledScreen. Finally the screen is added to the screens hash map. As you can see from the code, the loaded fxml file, doesn't get added to the scene graph, so the loaded screen doesn't get displayed or loaded to the screen.


           public boolean loadScreen(String name, String resource) {
             try {
               FXMLLoader myLoader = new
                       FXMLLoader(getClass().getResource(resource));
               Parent loadScreen = (Parent) myLoader.load();
               ControlledScreen myScreenControler =
                      ((ControlledScreen) myLoader.getController());
               myScreenControler.setScreenParent(this);
               addScreen(name, loadScreen);

               return true;
             }catch(Exception e) {
               System.out.println(e.getMessage());
               return false;
             }
           }

      • setScreen(String screenName). This method displays a screen with a given screen name.

        • First the method verifies that the screen has been previously loaded.

        • We check if there is already a screen been displayed, so we need to play the screen transition sequence. If there isn't any screen, we just add it to the graph and perform a nice fade-in animation.

        • If there is a screen already been displayed, we play an animation to fade out the current screen, and we defined an eventHandler to handle execution after this.

        • Once the screen is invisible, we remove it from the graph, and we add the new screen. Again, a nice animation is played to show the new screen.


           public boolean setScreen(final String name) {

             if(screens.get(name) != null) { //screen loaded
               final DoubleProperty opacity = opacityProperty();

               //Is there is more than one screen
               if(!getChildren().isEmpty()){
                 Timeline fade = new Timeline(
                   new KeyFrame(Duration.ZERO,
                                new KeyValue(opacity,1.0)),
                   new KeyFrame(new Duration(1000),

                       new EventHandler() {

                         @Override
                         public void handle(ActionEvent t) {
                           //remove displayed screen
                           getChildren().remove(0);
                           //add new screen
                           getChildren().add(0, screens.get(name));
                           Timeline fadeIn = new Timeline(
                               new KeyFrame(Duration.ZERO,
                                      new KeyValue(opacity, 0.0)),
                               new KeyFrame(new Duration(800),
                                      new KeyValue(opacity, 1.0)));
                           fadeIn.play();

                         }
                       }, new KeyValue(opacity, 0.0)));
                 fade.play();
               } else {
                 //no one else been displayed, then just show
                 setOpacity(0.0);
                 getChildren().add(screens.get(name));
                 Timeline fadeIn = new Timeline(
                     new KeyFrame(Duration.ZERO,
                                  new KeyValue(opacity, 0.0)),
                     new KeyFrame(new Duration(2500),
                                  new KeyValue(opacity, 1.0)));
                 fadeIn.play();
               }
               return true;
             } else {
                 System.out.println("screen hasn't been loaded!\n");
                 return false;
           }
          

    • We also have an unloadScreen(String name) method, that simple removes the screen from our hashmap, and report the status of this operation.


         public boolean unloadScreen(String name) {
           if(screens.remove(name) == null) {
             System.out.println("Screen didn't exist");
             return false;
           } else {
             return true;
           }
         }


  4. Now all we have to do is start using the framework. Here I show a small piece of code where you load the screens, and show the main one.


       public class ScreensFramework extends Application {

         public static final String MAIN_SCREEN = "main";
         public static final String MAIN_SCREEN_FXML = "main.fxml";
         public static final String POKER_SCREEN = "poker";
         public static final String POKER_SCREEN_FXML =
                                              "poker.fxml";
         public static final String ROULETTE_SCREEN = "roulette";
         public static final String ROULETTE_SCREEN_FXML =
                                              "roulette.fxml";

         @Override
         public void start(Stage primaryStage) {

           ScreensController mainContainer = new ScreensController();
           mainContainer.loadScreen(ScreensFramework.MAIN_SCREEN,
                                ScreensFramework.MAIN_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.POKER_SCREEN,
                                ScreensFramework.POKER_SCREEN_FXML);

           mainContainer.loadScreen(ScreensFramework.ROULETTE_SCREEN,
                                ScreensFramework.ROULETTE_SCREEN_FXML);


           mainContainer.setScreen(ScreensFramework.MAIN_SCREEN);

           Group root = new Group();
           root.getChildren().addAll(mainContainer);
           Scene scene = new Scene(root);
           primaryStage.setScene(scene);
           primaryStage.show();
         }
       ...


I found this framework very useful for my application, and I hope this will be valuable for you too. You can find a full implementation with three testing screens available following this link.

You can also see a related video I've created on our YouTube Java Channel, so you can see this application live.

Friday Oct 19, 2012

Unleash the Power of JavaFX

It seems that it was just yesterday that we were getting ready for JavaOne 2012.  Now it's over, but it's definitely a great time to go back and watch the sessions you missed, and learn some of the latest news about Java.  

For this JavaOne, I presented two sessions and one HOL, all of them related to JavaFX:

If you couldn't join us for these sessions, just follow the links and you can watch the videos on demand.

For the HOL I've created a repository at GitHub, as many of the attendees wanted to keep the material.   In this repository you can find the lab document, the NetBeans projects for each exercise and it's appropriate solution.

 Hope you enjoy!




I created and presented a HOL called:  Unleash the power of JavaFX.  In this blog entry I would like to provide you 

Tuesday Sep 11, 2012

JavaOne Countdown, Are you ready?


This is a great time of the year!  Not only does the weather start cooling down a bit, but it's time to get ready for JavaOne 2012.  It feels so long since my last JavaOne (last year I missed it because I was on a mom duty), so this year I couldn't be happier to be this close to the action again. 

Have you ever been at JavaOne?  There are a million great reasons to love JavaOne, and the most important for me is the atmosphere of the conference: The Java community is there, and Java is in the air!

This year we have more than 450 sessions, and there are HOLs (Hands on labs) to get your hands dirty with code.  In addition, there will be very cool demos, an exhibition hall. and a DEMOground.  During the whole time, you will have the opportunity to interact with the speakers, discuss topics and concerns, and even have a drink!

Oh yes, I almost forgot, there will be lots of fun even apart from the technology!  For example there will be a Geek Bike Ride, a Thirsty Bear party, and the Appreciation Party with Pearl Jam and Kings of Leon.  How can this get any better!

So, are you ready yet?  Have you registered?  If not, just follow this "Register for JavaOne" link and we'll see you there!

P.S.  Little known fact: If you are a student you can get your pass for free!!!

Friday Jul 20, 2012

JavaFX Deployment News!

One of the issues developers face almost everyday is the proliferation of Java platforms. Questions like: What version of Java should I use? Should I use the latest features? What about companies that are still running old versions of Java? These are common questions among developers, and just determining the Java release to be used could require much thought.

The majority of developers want to go for the latest build, but most of the time their companies are using older releases of the platform, and upgrading is out of question as it might break some of the older applications. Sometimes, developers don’t even have the rights to update the software, preventing them from writing powerful applications using the latest technologies that they desire.

Well, not anymore. With the JavaFX packager your deployment nightmares are gone! The newest packaging tool for JavaFX applications allows you to bundle your application along with its resources into a package that include a private copy of the Java and JavaFX runtimes, together with a native application launcher. This means you won’t have to worry about what is installed on the machine on which your application is going to run; your application’s package includes everything it needs for execution! Because it has its own private copy of Java and JavaFX runtimes, you don’t have to be concerned about breaking other applications, or asking your client to update the system to be able to run your application. Your application is self contained and ready to be used.

The javafxpackager will generate zip files or native packages depending on the operating system on which your application will be running. For example, if you are running on Windows it could generate EXE or MSI files. On MacOS it would generate a DMG file, and on Linux it would generate an RPM file.



JavaFX Packaging Tool


JavaFX 2.2 provides two options to create your bundles: The command line utility tool javafxpackager, and a set of ant tasks ant-javafx.jar

Before we go any further let’s review the build process for JavaFX applications.

JavaFX applications and preloaders consist of source code, stylesheets, and may or may not contain additional resources. Source code must be compiled, and stylesheets can optionally be converted to binary format. The source code, stylesheets, and other resources are combined to create a JAR archive, which can optionally be signed and have a certificate attached. JavaFX applications and preloaders are packaged into separate JAR archives. For web applications, a deployment descriptor (JNLP file) is prepared to produce the final package, consisting of one or more executable JAR files, the deployment descriptor, and a web page with the embedded application or a link to launch a Web Start application.

You have full control of this process through the JavaFX packager tool or the ant task as shown in the following table.

Now that you know how to package your JavaFX application, there is a small option you need to include in order to produce the application native bundles:

This is an example of the ant task including the generation of native bundles:


nativeBundles can have the following values:

  • image: Bundle of the application in an unpacked form. You can zip it or package it for redistribution.
  • installer: prepackaged image
  • all: generate images and installers

Now that you have generated your native packages, you can install and test your application. For example for Mac OS we have the following default installer:


In addition, you can customize the bundles and have something like this:


For the bundle customization you will need to place resources such as icons in the package/<platform>/ folder:

  • package/macosx/Ensemble2.icns
  • package/windows/Ensemble2.icns


You might also include customs scripts to be used to build the packages:

  • package/macosx/Ensemble2-dmg-setup.scpt
  • package/windows/Ensemble2.wsx
 

The native packaging capabilities described in this article are available in JDK 7u6 and subsequent releases. I hope you’ll try out these capabilities, leveraging them to make it easy for users to deploy your JavaFX applications!


I'm BACK!!!!

Hello everyone, let me start this blog by saying: “I’m back!!!”. It’s been an amazing decade as Java Evangelist, and now it’s time to really start writing my blog!! From now on, you will find in this space all about my trips, experiences with developers, and lots and lots of information about Java Technology.

So stay tuned!!!

About

Angela Caicedo

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today