Assignment 2 The goal of this lab is to create a web browser in JavaFX. I am giv
ID: 3681498 • Letter: A
Question
Assignment 2
The goal of this lab is to create a web browser in JavaFX. I am giving you some code to start the assignment but you must add the extra functionality. You don’t need to write a full HTML renderer, just use the JavaFX WebView object: https://docs.oracle.com/javafx/2/api/javafx/scene/web/WebView.html
It has a getEngine() function that returns the WebEngine object that loads and displays HTML pages. This WebEngine object has a load( String url) function that loads a properly formed URL and renders it. The WebEngine also has a getHistory() function which returns a WebHistory object. You will need these objects for this assignment.
There are several parts to this assignment: Menu Bar, Browser bar, and sliding history window.
Menu Bar
The browser should have a File menu with an option Quit, which quits the program when selected.
There should also be a Bookmarks menu, which contains all of the websites that have added by clicking the Bookmark button.
There should be a Help menu, which has 3 menu items:
“Get help for Java class” – selecting this option should present a Dialog box asking for the user to type which Java class they want to search. When the user clicks “Ok”, the browser should navigate to a Google search for that class entered. Lab_4 presented the format for a Google search of “Java String”. All you have to do is replace “String” with the selected java class. This should help you to look up the documentation for many of the classes you will use for this assignment.
There should be a “Show History” CheckedMenuItem which is checked if the History slider is visible, and unchecked if it is hidden.
An “About” option that gives your name, the release date, and version number:
Browser Bar
The Browser bar should have 4 components:
Back button. This should be disabled at the start of the program but enabled only if the browser history is not at the first page. Check the WebEngine’s History to check if the currentIndex is 1. Clicking on the Back button should call the goBack() function that I have provided.
TextField. This should be where the user types in the URL. Add a KeyEvent listener to check when the user has typed the Enter/Return key. When this happens, read the text that was entered. If it’s a valid URL, then tell the WebEngine to load that URL. Also add a mouse click listener to the TextField. Clicking only once should highlight the text so that any further typing will replace what was previously selected. Double-clicking the TextField should erase what was there so that the user can type a new string. This text field should be able to grow so that it fills the rest of the Browser Bar. Read the documentation for HBox to see how to do this.
Bookmark button. Clicking this button should add a MenuItem for the current URL to the Bookmarks menu. Clicking on the newly created Bookmark MenuItem should bring you to the page where the Bookmark button was clicked. If there is already a MenuItem for the current URL, then the Bookmark button should be disabled. The browser should not have two MenuItems for the same URL.
Forward button. This should be disabled at the start of the program but enabled only if the browser history is not at the last page. Check the WebEngine’s History to check if the currentIndex is equal to the WebHistory’s size(). Otherwise, clicking on the Forward button should call the goForward() function that I have provided.
The buttons should all be disabled when the WebEngine is told to load a page. Use the provided engine page load succeeded callback to set the appropriate Disabled states of the buttons using the logic rules above.
You must have only 1 click handler object for all 4 components. When the handle function is called, you must check the getSource() of the click to see if it was the back button, bookmark button, forward button, or text field and then react appropriately. This should be done as a full inner class.
History Side bar
Add a ListView on the right side of your browser window. The contents of the ListView should be the ObservableList<WebHistory.Entry> that is returned by the getEntries() method of the Engine’s WebHistory object. Clicking on the “Show History” menu item should set the maxSize of the listView to some reasonable value. Clicking the ShowHistory menu item a second time should hide the ListView, by setting its maxSize to 0.
Showing and hiding the history bar should use a combination of two animations: Fade, Scale, Translate or Rotate. One combination must be a ParallelTransition and the other must be a SequentialTransition.
When the history ListView is shown, selecting any of the History items should cause the WebEngine to go to that Index in the webHistory. The WebHistory class has a go(int) function to do this, but it takes a relative int as parameter. go(1) moves the history one page forward where go(-2) moves the history two pages back. You will have to compare the WebHistory’s current index to the index of what was selected to compute the relative movement (-2, -1, 0, 1, 2, etc…)
The MouseClick event handler for the ListView must use a Lambda function as a callback handler since it will only ever be used for the ListView object.
Code already given must be used:
package assignment2;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker.State;
import javafx.stage.Stage;
import javafx.scene.web.WebView;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebHistory;
public class MyGUI extends Application {
protected WebEngine engine;
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) throws Exception {
WebView browserView = new WebView();
engine = browserView.getEngine();
//This is a 3-parameter Lambda function for listening for changes
// of state for the web page loader. VVV VVV VVV
engine.getLoadWorker().stateProperty().addListener(( ov, oldState, newState)->
{
// This if statement gets run if the new page load succeeded.
if (newState == State.SUCCEEDED) {
}
});
}
//Tell the engine to go back 1 page in the history
public void goBack()
{
final WebHistory history=engine.getHistory();
ObservableList<WebHistory.Entry> entryList=history.getEntries();
int currentIndex=history.getCurrentIndex();
if(currentIndex > 0)
{ // VVV This is a no-parameter Lambda function run();
Platform.runLater( () -> {
history.go(-1);
final String nextAddress = history.getEntries().get(currentIndex - 1).getUrl();
} );
}
}
//Tell the engine to go forward 1 page in the history
public void goForward()
{
final WebHistory history=engine.getHistory();
ObservableList<WebHistory.Entry> entryList=history.getEntries();
int currentIndex=history.getCurrentIndex();
if(currentIndex + 1 < entryList.size())
{ //This is a no-parameter Lambda function run();
Platform.runLater( () -> {
history.go(1);
final String nextAddress = history.getEntries().get(currentIndex + 1).getUrl();
});
}
}
}
Explanation / Answer
public class MyGUI extends Application{
protected WebEngine engine;
public static void main(String[] args) { launch(args); }
@Override
public void start(Stage primaryStage) throws Exception{
WebView browserView = new WebView();
engine = browserView.getEngine();
//This is a 3-parameter Lambda function for listening for changes
// of state for the web page loader. VVV VVV VVV
engine.getLoadWorker().stateProperty().addListener(( ov, oldState, newState)->
{
// This if statement gets run if the new page load succeeded.
if (newState == State.SUCCEEDED) {
URL url = getClass().getResource("/org/html/main.html");
webEngine.load(url.toString());
StackPane rootPanel = new StackPane();
rootPanel.getChildren().add(browserView);
Scene scene=new Scene(rootPanel,800,600);
primaryStage.setTitle("Web Browser");
primaryStage.setScene(scene);
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getBounds();
primaryStage.setX(bounds.getMinX());
primaryStage.setY(bounds.getMinY());
primaryStage.setWidth(bounds.getWidth());
primaryStage.setHeight(bounds.getHeight());
primaryStage.show();
}
});
}
//Tell the engine to go back 1 page in the history
public void goBack()
{
final WebHistory history=engine.getHistory();
ObservableList<WebHistory.Entry> entryList=history.getEntries();
int currentIndex=history.getCurrentIndex();
if(currentIndex > 0)
{ // VVV This is a no-parameter Lambda function run();
Platform.runLater( () -> {
history.go(-1);
final String nextAddress = history.getEntries().get(currentIndex - 1).getUrl();
} );
}
}
//Tell the engine to go forward 1 page in the history
public void goForward()
{
final WebHistory history=engine.getHistory();
ObservableList<WebHistory.Entry> entryList=history.getEntries();
int currentIndex=history.getCurrentIndex();
if(currentIndex + 1 < entryList.size())
{ //This is a no-parameter Lambda function run();
Platform.runLater( () -> {
history.go(1);
final String nextAddress = history.getEntries().get(currentIndex + 1).getUrl();
});
}
}
}