A JavaFX File Editor: Part 2
WebView component, the simple file editor itself, and keyboard processing.
In my previous blog entry, I discussed a simple JavaFX file editor as a way to introduce menu and tab processing. In this entry, I'll finish the story by talking about the JavaFX WebView component, the simple file editor itself, and keyboard processing.
The Content Interface
This simple application is all about opening tabs with some sort of relevant content within them. Therefore, I created a Content interface to manage this. No matter what I put in a tab, it must implement the Content interface so that the application can operate on it in some way.
public interface Content {
public Node getRoot();
}
It's a simple interface: The only method it needs is one that returns the content's root Node object so that it can be placed within a Tab, and cast to one of the known content type classes. Doing so allows the application to prompt the user to save when the application exits, for example.
One example where this interface is used is when the user creates a new tab, either through the File..New or the View..Web Page menu choice. Although the first opens a new editor and the second opens a browser (within a tab), there's a lot of shared processing:
private void createNew(String type) {
Tab tab = new Tab();
Content content = null;
switch ( type ) {
case EDITOR:
content = new SimpleEditor();
editors.add((SimpleEditor)content);
break;
case BROWSER:
content = new WebBrowser();
type += (browserCnt++);
break;
}
tab.setContent(content.getRoot());
tab.setText(type);
tabPane.getTabs().add(tab);
SingleSelectionModel<Tab> selectionModel = tabPane.getSelectionModel();
selectionModel.select(tab);
}
Here, the proper content type is created (editor or browser). It's referenced as a Content interface, and the getRoot method is used to place the Node within the Tab.
The Web Browser
The WebBrowser class encapsulates everything we need to browse the Web from within a JavaFX application. This includes a TextField where the user can type a URL, a "Go" button the user can press to navigate to the URL, and the HTML5-compatible WebView control to display the actual web content.
public class WebBrowser implements Content {
private static final String DEFAULT_URL = "http://www.drdobbs.com";
VBox root = null;
WebView webView = null;
public VBox getRoot() {
return root;
}
public WebBrowser() {
root = new VBox();
webView = new WebView();
final WebEngine webEngine = webView.getEngine();
webEngine.load(DEFAULT_URL);
final TextField locationField = new TextField(DEFAULT_URL);
webEngine.locationProperty().addListener(new ChangeListener<String>() {
@Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
locationField.setText(newValue);
}
});
EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
@Override public void handle(ActionEvent event) {
webEngine.load(locationField.getText().startsWith("http://")
? locationField.getText()
: "http://" + locationField.getText());
}
};
locationField.setOnAction(goAction);
Button goButton = new Button("Go");
goButton.setDefaultButton(true);
goButton.setOnAction(goAction);
// Layout logic
HBox hBox = new HBox(5);
hBox.getChildren().setAll(locationField, goButton);
HBox.setHgrow(locationField, Priority.ALWAYS);
VBox vBox = new VBox(5);
vBox.getChildren().setAll(hBox, webView);
VBox.setVgrow(webView, Priority.ALWAYS);
root.getChildren().add(vBox);
}
}
All of the content is placed within a root VBox Node, including an HBox to contain the TextField and "Go" button side-by-side. A listener is created to track when the WebView's content changes; i.e., via a click on a link, so that the URL can be updated within the TextField. Another listener ensures that the URL is formatted correctly when the Go button is pressed to begin navigation.

