Desktop Java

JavaFX 2.0 beta sample application and after thoughts

I had quite sometime back played around with JavaFX and had good and bad experiences using the language. With the JavaFX 2.0 beta being released I thought of giving it a try.

Here, I developed a simple Geocoding application which will take the address and provides the latitude-longitude values for that location – using Google Geocoding API.

I used Groovy for the JSON parsing, as the latest version-1.8 provides a really neat json parsing support.

import groovy.json.*
 
class GeocodingParser {
  static def GEOCODE_JSON_URL = "http://maps.googleapis.com/maps/api/geocode/json"
  static def GEOCODE_XML_URL = "http://maps.googleapis.com/maps/api/geocode/xml"
 
  static def getGeocodeForAddress(address){
    def queryBuilder = []
    queryBuilder << "address=${URLEncoder.encode(address)}"
    queryBuilder << "sensor=false"
    def queryString = queryBuilder.join("&")
    def requestUrl = GEOCODE_JSON_URL+"?${queryString}"
    def payload = new URL(requestUrl).text
    def jsonSlurper = new JsonSlurper()
    def doc = jsonSlurper.parseText(payload)
    def geocode = new Geocode()
    geocode.latitude = doc.results.geometry.location.lat.join("")
    geocode.longitude = doc.results.geometry.location.lng.join("")
    geocode.locationType = doc.results.geometry.location_type.join("")
    return geocode
  }
}
 
class Geocode {
  def String latitude
  def String longitude
  def String locationType
  def String toString(){
    return "Latitude: ${latitude}, Longitude:${longitude} and Location type: ${locationType}"
  }
}

You can see that the json parsing using JsonSlurper is so succinct. The groovy parser returns the latitude, longitude and location type (these are the values of interest for our application) values in the Geocode wrapper class – which is again a Grooy bean.

Now lets look at the JavaFX code which actually is the crux of this post:

public class NewFXMain extends Application {
 
 /**
 * @param args the command line arguments
 */
 public static void main(String[] args) {
   Application.launch(NewFXMain.class, args);
 }
 
 @Override
 public void start(Stage primaryStage) {
   primaryStage.setTitle("Geocoder");
   TabPane mainTabPane = new TabPane();
   Tab geoTab = new Tab("Geocoding");
   geoTab.setClosable(false);
   mainTabPane.getTabs().add(geoTab);
 
   final GridPane geoGrid = new GridPane();
   geoGrid.setHgap(10);
   geoGrid.setVgap(10);
   geoGrid.setPadding(new Insets(0, 20, 0, 10));
 
   Label mainGeoLabel = new Label("Geocoding");
 
   final TextBox geoAddressTextBox = new TextBox(15);
 
   Button geoCodeButton = new Button("Geocode");
   final TextBox latitudeValTextBox = new TextBox();
   latitudeValTextBox.setEditable(false);
   final TextBox longitudeValTextBox = new TextBox();
   longitudeValTextBox.setEditable(false);
   final TextBox locationTypeValTextBox = new TextBox();
   locationTypeValTextBox.setEditable(false);
 
   final StringProperty latitudeProperty = new StringProperty();
   latitudeProperty.addListener(new ChangeListener<String>() {
 
     @Override
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
       latitudeValTextBox.setText(newValue);
     }
   });
 
   final StringProperty longitudeProperty = new StringProperty();
   longitudeProperty.addListener(new ChangeListener<String>() {
 
     @Override
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
       longitudeValTextBox.setText(newValue);
     }
   });
 
   final StringProperty locationTypeProperty = new StringProperty();
   locationTypeProperty.addListener(new ChangeListener<String>() {
 
     @Override
     public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
       locationTypeValTextBox.setText(newValue);
     }
   });
 
   geoCodeButton.setOnAction(new EventHandler<ActionEvent>(){
 
     @Override
     public void handle(ActionEvent event) {
       String address = geoAddressTextBox.getText();
       if(address == null){
       }else{
         Geocode parsedCode = (Geocode)GeocodingParser.getGeocodeForAddress(address);
         latitudeProperty.set(parsedCode.getLatitude());
         longitudeProperty.set(parsedCode.getLongitude());
         locationTypeProperty.set(parsedCode.getLocationType());
      }
    }
   });
 
   geoGrid.add(mainGeoLabel, 4, 1);
   geoGrid.add(new Label("Address"), 2, 3);
   geoGrid.add(geoAddressTextBox, 3, 3,3,1);
   geoGrid.add(new Label("Latitude"), 2,7);
 
   geoGrid.add(new Label("Longitude"),2,8);
 
   geoGrid.add(new Label("Location Type"),2,9);
   geoGrid.add(latitudeValTextBox,3,7,2,1);
   geoGrid.add(longitudeValTextBox,3,8,2,1);
   geoGrid.add(locationTypeValTextBox,3,9,2,1);
   geoGrid.add(geoCodeButton, 4, 5);
   geoTab.setContent(geoGrid);
   Scene scene = new Scene(mainTabPane);
   primaryStage.setScene(scene);
   primaryStage.setVisible(true);
   primaryStage.setResizable(false);
 }
}

I have used bindings to bind the component displaying the latitude, longitude and location type values with the properties for the same values. For example, the code below shows how the latitude value was bound to the control which will display the value. This control (textbox) holds the latitude value obtained after passing the json response sent by the Geocoding API.

Now we create a StringProperty to hold the value for the latitude and we attach a change listener to this property such that when ever the value gets updated in the property we update the textbox with the new value. So, what exactly is changing the value of this property? We add a button which invokes the groovy parser and gets the latitude, longitude and location type values in a wrapper class. In the above action listener we get the parsed values and then update the properties with the corresponding values. This update in turn triggers the method in the corresponding change listeners.

Now coming to the layout for the controls. I used a GridBox layout and this was really flexible as it allowed me to place the components in a neat order.

Here are a few after thoughts:

  • JavaFX 2.0 has been changed to make more Java programmer friendly
  • JavaFX 2.0 more verbose than the JavaFX script- for example: looking at the way bindings has to be done.
  • Lack of tooling support – Creating a GUI is difficult.
  • Java programmers need not learn a new language all together, they wold feel at home with JavaFX APIs
  • Interoperability with other JVM languages like Groovy, Scala.
  • Lot of new controls, APIs added in the JavaFX 2.0.
  • Lack of multi-platform support.

The source code can be found here.

Reference: Sample application using JavaFX 2.0 beta and the after thoughts from our JCG partner Mohamed Sanaulla at the Experiences Unlimited Blog.

Related Articles :
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button