Mapping directions in a JavaFX application is easy with the Directions API that was recently introduced in GMapsFX. In this blog post I’ll walk through an example of setting up an application with a map and a couple of text fields, one which will be used for the trip origin and the second which will be used for the trip destination. When the user hits ‘Enter’ in the destination text field, the map will display the directions.
Starting off with the FXML file, we have an AnchorPane which contains the GoogleMapView and 2 TextFields. The AnchorPane has a controller assigned to it named FXMLController, and both components have an FX ID associated with them so they will be accessible from the FXMLController class. Also, the destination TextField has an action, “toTextFieldAction” associated with it, so this method will be called when the user hits the ‘Enter’ key in the TextField.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<?import com.lynden.gmapsfx.GoogleMapView?> | |
<?import javafx.scene.control.TextField?> | |
<?import javafx.scene.layout.AnchorPane?> | |
<AnchorPane id="AnchorPane" prefHeight="443.0" prefWidth="711.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="com.lynden.gmaps.directions.FXMLController"> | |
<children> | |
<GoogleMapView fx:id="mapView" layoutX="-311.0" layoutY="-244.0" prefWidth="490.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | |
<TextField fx:id="fromTextField" prefHeight="27.0" prefWidth="222.0" promptText="From:" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="10.0" /> | |
<TextField fx:id="toTextField" layoutX="10.0" layoutY="10.0" onAction="#toTextFieldAction" prefHeight="27.0" prefWidth="222.0" promptText="To:" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="50.0" /> | |
</children> | |
</AnchorPane> |
The result should look as follows:
Next, I’ve cut up the relevant parts of the FXMLController class. The MapComponentInitializedListener interface needs to be implemented by the controller since the underlying GoogleMap doesn’t get initialized immediately. The DirectionsServiceCallback interface also needs to be implemented, although in this example I won’t be doing anything with it.
The GoogleMapView and the TextFields components from the FXML file are defined below and annotated with @FXML.
There is also a reference to the Directions Service as well as StringProperties to represent the ‘to’ and ‘from’ endpoints that the user will enter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class FXMLController implements Initializable, MapComponentInitializedListener, DirectionsServiceCallback { | |
protected StringProperty from = new SimpleStringProperty(); | |
protected StringProperty to = new SimpleStringProperty(); | |
@FXML | |
protected GoogleMapView mapView; | |
@FXML | |
protected TextField fromTextField; | |
@FXML | |
protected TextField toTextField; |
After the controller is created, its initialize method is called which will set the MapView’s initialization listener to the FXMLController as well as bind the ‘to’ and ‘from’ String properties to the TextProperties of their respective TextFields.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void initialize(URL url, ResourceBundle rb) { | |
mapView.addMapInializedListener(this); | |
to.bindBidirectional(toTextField.textProperty()); | |
from.bindBidirectional(fromTextField.textProperty()); | |
} |
Once the map has been initialized, the DirectionService can be instantiated as well as a MapOptions object to set various attributes about the map. The options are then configured and a GoogleMap object can be instantiated from the map view. The directionsPane is a component which can be used to render the step by step direction text, in this example however, it won’t be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Override | |
public void mapInitialized() { | |
MapOptions options = new MapOptions(); | |
options.center(new LatLong(47.606189, –122.335842)) | |
.zoomControl(true) | |
.zoom(12) | |
.overviewMapControl(false) | |
.mapType(MapTypeIdEnum.ROADMAP); | |
GoogleMap map = mapView.createMap(options); | |
directionsService = new DirectionsService(); | |
directionsPane = mapView.getDirec(); | |
} |
Finally, the action method defined in the FXML file when the user hits ‘Enter’ in the TextField is below. The method will call the getRoute() method on the DirectionsService class, passing in a boolean value which will define whether the route can be modified by dragging it, the map object, and the DirectionsRequest object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@FXML | |
private void toTextFieldAction(ActionEvent event) { | |
DirectionsRequest request = new DirectionsRequest(from.get(), to.get(), TravelModes.DRIVING); | |
directionsService.getRoute(request, this, new DirectionsRenderer(true, mapView.getMap(), directionsPane)); | |
} |
Below is an example when the user enters directions from Seattle to Redmond
That’s it! For completeness I’ll include the full source code of the example below.
Scene.fxml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<?import com.lynden.gmapsfx.GoogleMapView?> | |
<?import javafx.scene.control.TextField?> | |
<?import javafx.scene.layout.AnchorPane?> | |
<AnchorPane id="AnchorPane" prefHeight="443.0" prefWidth="711.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.65" fx:controller="com.lynden.gmaps.directions.FXMLController"> | |
<children> | |
<GoogleMapView fx:id="mapView" layoutX="-311.0" layoutY="-244.0" prefWidth="490.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" /> | |
<TextField fx:id="fromTextField" prefHeight="27.0" prefWidth="222.0" promptText="From:" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="10.0" /> | |
<TextField fx:id="toTextField" layoutX="10.0" layoutY="10.0" onAction="#toTextFieldAction" prefHeight="27.0" prefWidth="222.0" promptText="To:" AnchorPane.leftAnchor="10.0" AnchorPane.topAnchor="50.0" /> | |
</children> | |
</AnchorPane> |
MainApp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lynden.gmaps.directions; | |
import javafx.application.Application; | |
import static javafx.application.Application.launch; | |
import javafx.fxml.FXMLLoader; | |
import javafx.scene.Parent; | |
import javafx.scene.Scene; | |
import javafx.stage.Stage; | |
public class MainApp extends Application { | |
@Override | |
public void start(Stage stage) throws Exception { | |
Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml")); | |
Scene scene = new Scene(root); | |
scene.getStylesheets().add("/styles/Styles.css"); | |
stage.setTitle("JavaFX and Maven"); | |
stage.setScene(scene); | |
stage.show(); | |
} | |
public static void main(String[] args) { | |
launch(args); | |
} | |
} |
FXMLController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.lynden.gmaps.directions; | |
import com.lynden.gmapsfx.GoogleMapView; | |
import com.lynden.gmapsfx.MapComponentInitializedListener; | |
import com.lynden.gmapsfx.javascript.object.*; | |
import com.lynden.gmapsfx.service.directions.*; | |
import java.net.URL; | |
import java.util.ResourceBundle; | |
import javafx.beans.property.SimpleStringProperty; | |
import javafx.beans.property.StringProperty; | |
import javafx.event.ActionEvent; | |
import javafx.fxml.FXML; | |
import javafx.fxml.Initializable; | |
import javafx.scene.control.TextField; | |
public class FXMLController implements Initializable, MapComponentInitializedListener, DirectionsServiceCallback { | |
protected DirectionsService directionsService; | |
protected DirectionsPane directionsPane; | |
protected StringProperty from = new SimpleStringProperty(); | |
protected StringProperty to = new SimpleStringProperty(); | |
@FXML | |
protected GoogleMapView mapView; | |
@FXML | |
protected TextField fromTextField; | |
@FXML | |
protected TextField toTextField; | |
@FXML | |
private void toTextFieldAction(ActionEvent event) { | |
DirectionsRequest request = new DirectionsRequest(from.get(), to.get(), TravelModes.DRIVING); | |
directionsService.getRoute(request, this, new DirectionsRenderer(true, mapView.getMap(), directionsPane)); | |
} | |
@Override | |
public void directionsReceived(DirectionsResult results, DirectionStatus status) { | |
} | |
@Override | |
public void initialize(URL url, ResourceBundle rb) { | |
mapView.addMapInializedListener(this); | |
to.bindBidirectional(toTextField.textProperty()); | |
from.bindBidirectional(fromTextField.textProperty()); | |
} | |
@Override | |
public void mapInitialized() { | |
MapOptions options = new MapOptions(); | |
options.center(new LatLong(47.606189, –122.335842)) | |
.zoomControl(true) | |
.zoom(12) | |
.overviewMapControl(false) | |
.mapType(MapTypeIdEnum.ROADMAP); | |
GoogleMap map = mapView.createMap(options); | |
directionsService = new DirectionsService(); | |
directionsPane = mapView.getDirec(); | |
} | |
} |
Pingback: Java desktop links of the week, August 29 « Jonathan Giles
Pingback: JavaFX links of the week, August 29 | JavaFX News, Demos and Insight // FX Experience