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.