OOP Lab08 JavaFX - ExeptionHandling
OOP Lab08 JavaFX - ExeptionHandling
0 Assignment Submission
For this lab class, you will have to turn in your work twice, specifically:
§ Right after the class: for this deadline, you should include any work you have done
within the lab class.
§ 10 PM 7 days after the class: for this deadline, you should include your work on all
sections of this lab, and push it to a branch called “release/lab08” of the valid
repository.
After completing all the exercises in the lab, you have to update the use case diagram and the class
diagram of the AIMS project.
Each student is expected to turn in his or her work and not give or receive unpermitted aid.
Otherwise, we would apply extreme methods for measurement to prevent cheating. Please write
down answers for all questions into a text file named “answers.txt” and submit it within your
repository.
1
- Check after installation: After successful installation and restarting Eclipse, you can
check the result of the installation. In Eclipse select: File/New/Others... There are
Wizards which allow you to carry out JavaFX programming
2
- Click “Add External JARs” then navigate to the folder where you extracted JavaFX in the
previous step, choose the “lib” folder and add all .jar files. Click “Apply and Close”.
- Right-click on the project → Build Path → Configure Build Path → Classpath → Add
Library → User Library → JavaFX
3
Figure 2. Configure Eclipse to use Scene Builder (1)
4
Figure 4. Configure Eclipse to use Scene Builder (3)
5
3 JavaFX API
Note: For the exercises in this lab (excluding the AIMS exercises), you will continue to use the
GUIProject, and put all your source code in a package called “hust.soict.globalict.javafx” (for
ICT) or “hust.soict.dsai.javafx” (for DS & AI). You might need to add the JavaFX library to this
project if you are using the JDK version after 1.8.
In this exercise, we revisit the components of a JavaFX application by implementing a simple
Painter app that allows the user to draw on a white canvas with their mouse.
Recall the basic structure of a JavaFX application: It uses the metaphor of a theater to model the
graphics application. A stage (defined by the javafx.stage.Stage class) represents the top-
level container (window). The individual controls (or components) are contained in a scene
(defined by the javafx.scene.Scene class). An application can have more than one scene,
but only one of the scenes can be displayed on the stage at any given time. The contents of a scene
is represented in a hierarchical scene graph of nodes (defined by javafx.scene.Node).
6
Figure 7. Structure of JavaFX application
Like any other JavaFX application, there are 3 steps for creating this Painter app as follows:
- Create the FXML file “Painter.fxml” (we will be using Scene Builder)
- Create the controller class PainterController
- Create the application class Painter
The FXML file lays out the UI components in the scene graph. The controller adds interactivity to
these components by providing even-handling methods. Together, they complete the construction
of the scene graph. Finally, the application class creates a scene with the scene graph and adds it
to the stage.
7
Figure 8. Create a new FXML in Eclipse(1)
Name the file “Painter” and choose BorderPane as the root element as in Figure 9
A new file is created. Right-click on it in Project Explorer and select Open with SceneBuilder
8
Figure 11. Target interface
For the right-side section, we use a regular Pane. On the other hand, for the left-side section, since
we want to arrange subsequent items below the previous ones vertically, we use a VBox layout.
Step 1. Configuring the BorderPane – the root element of the scene
- We set the GridPane’s Pref Width and Pref Height properties to 640 and 480
respectively. Recall that the stage’s size is determined based on the size of the root node
in the FXML document
- Set the BorderPane’s Padding property to 8 to inset it from the stage’s edges
9
Figure 13. Get VBox in the Library menu
10
Figure 14. Configuring the VBox
11
Figure 15. Configuring the Pane
12
Figure 16. Configuring the Button
Now that all the elements are set, you can preview them by selecting Preview > Show Preview in
Window
3.2 Create the controller class
In the same package as the FXML, create a Java class called PainterController. You can
also utilize Scene Builder for coding the controller as follows: Select View > Show Sample
Controller Skeleton. A window like in XXX will appear:
13
Figure 17. Auto-generated skeleton code for the controller
You can choose to copy the skeleton and paste it into your PainterController.java file.
Remember to replace the class name in the skeleton code with your actual class name
(PainterController). The results look roughly like this:
14
a dot) to the Pane at that same position. We do this by getting the Pane’s children list – which is
an ObservableList - and adding the UI object to the list.
For the clearButtonPressed() method, we simply need to clear all the Circle objects on
the Pane. Again, we have to access the Pane’s children list through Pane.getChildren().
The source code for the controller is complete, however, to ensure that an object of the controller
class is created when the app loads the FXML file at runtime, you must specify the controller
class’s name in the FXML file using Scene Builder, in the lower right corner under Document
menu > Controller.
Figure 21. Specify the controller for the FXML file in Scene Builder
15
Figure 22. Painter source code
16
Figure 23. Choose another MouseEvent handling entry
Hint:
• For the interface design: use TitledPane and RadioButton. Using Scene Builder,
set the Toggle Group properties of the RadioButtons as identical, so only one of them can
be selected at a time.
17
• For the implementation of Eraser: One approach is to implement an eraser just like the
pen above, but use white ink color (canvas color) instead.
Figure 25. New packages for ICT class Figure 26. New packages for DSAI
class
18
5 Build View Store Screen for AIMS Customer Application with
JavaFX
5.1 Set up View Store Screen with Scene Builder
Like the previous exercise, we start by creating an FXML file named “Store.fxml” in the package
screen.customer.view with VBox being the root node. The View Store Screen contains
two main parts:
• An Hbox contains a label AIMS and a button View Cart
• A ScrollPane contains GridPane to show all the items in the store
19
Figure 28. Structure of Store.fxml file
In this section, we will create the GUI components (i.e, the FXML file) only. The controller of
ViewStoreScreen will be implemented later.
5.1.1 Set up the VBox
- Properties:
§ Alignment: CENTER
- Layout:
§ Pref Width: 1024
§ Pref Height: 768
§ Padding: 20 Left
5.1.2 Set up the HBox
Step 1. Set up HBox Properties and Layout
- Properties:
§ Alignment: CENTER
- Layout:
§ Pref Height: 100
Step 2. Add a Label to the HBox
- Properties:
§ Text: AIMS
§ Font: 50px
§ Text Fill: #004cff
- Layout:
§ Padding: 10 Left
Step 3. Add a Region to the HBox
- Layout:
§ Hgrow: ALWAYS
Step 3. Add a Button to the HBox
- Properties:
§ Text: View Cart
- Layout:
§ Margin: 20 Right
§ Pref Width: 100
§ Pref Height: 50
20
- Code:
§ On Action: btnViewCartPressed
5.1.3 Set up the ScrollPane:
Step 1. Add a ScrollPane to the VBox, under the HBox
- Layout:
§ Pref Width: 1024
§ Pref Height: 760
Step 2. Add a GridPane to the ScrollPane
- Because the number of items in the store can be changed, therefore we will create a
dynamic GridPane that updates the view along with the change of the Store.
- Firstly, we will create an “empty” GridPane. Drag a GridPane to the ScrollPane. Delete
given rows and columns in the GridPane by right click on the row/column to be deleted,
choose Delete. The final dimension of the GridPane is (0 x 1).
- Set up Layout:
§ Pref Width: 0
§ Pref Height: 0
- Code:
§ fx:id: gridPane
5.2 Set up Item in the Store
In the View Store Screen, we already created an empty GridPane. In this section, we will create
an FXML component to display the information of media and dynamically add it to the GridPane.
5.2.1 Create Item.fxml file
In package screen.customer.view, create the Item.fxml file, choose the root node to be
AnchorPane.
The structure of this file is shown as below:
21
Figure 30. Structure of Item.fxml file
22
§ Pref Width: 305
§ Pref Height: 50
- Code:
§ fx:id: btnAddToCart
§ On Action: btnAddToCartClicked
v Button 2:
- Properties:
§ Text: Play
- Layout:
§ Pref Width: 305
§ Pref Height: 50
- Code:
§ fx:id: btnPlay
§ On Action: btnPlayClicked
5.2.2 Create ItemController class
The fxml file just contains the GUI, not the logic. You need to create a controller to implements
the behaviors of the FXML components.
23
5.3 Create ViewStoreController class
In the package customer.screen.controller, create the ViewStoreController class. Add
all attributes and methods defined in the Store.fxml file to the Controller. You can copy the
Controller Skeleton from Scene Builder by select View > Show Sample Controller Skeleton.
Declare one attribute in the StoreManagerScreen class: Store store (because we need
information of the items in the store to display them) and and pass it to the constructor.
The GridPane we created in the section 5.1 is currently empty, we need to fill it with data of
media items in the store. In the initialize() method, we load the fxml file of each media
item to an FXML component (lines 35-40), set data for the item component (line 41) and add it to
the GridPane (line 48).
Explain initialize() method: The FXML controller can define an initialize() method,
which will be called once on an implementing controller when the contents of its associated
24
document have been completely loaded. In a few words: The constructor is called first, then any
@FXML annotated fields are populated, then initialize() is called.
5.4 Test View Store Screen
To test if our previouse code actually works, we will create a new package under the src pakcage
named: hust.soict.program.test.screen.customer.store, where program is
replaced by globalict or dsai.
In that package, create a class TestViewStoreScreen that extends Application class with
the main method. The sample code is shown below:
25
6 Build Cart for AIMS Customer Application
6.1 Set up Cart Screen with Scene Builder
Similar to the View Store Screen, in package screen.customer.view, we will first create a
Cart.fxml file with BorderPane being the root node. The Cart Screen has three distinct areas
(bounded in red borders) corresponding to TOP, CENTER and BOTTOM areas of BorderPane.
6.1.1 Set up the BorderPane:
- Layout:
§ Pref Width: 1024
§ Pref Height: 768
6.1.2 Set up the TOP area
We use the HBox layout for the TOP area to arrange components horizontally. The structure of
TOP area is shown as below:
26
Step 1. Drag a HBox into the BorderPane’s TOP area.
- Layout:
§ Margin: 20 Left, 20 Right
§ Pref Height: 100
Step 2. Add a Label to the HBox
- Properties:
§ Text: CART
§ Font: 50px
§ Text Fill: #004cff
Step 3. Add a Region to the HBox
- Layout:
§ Hgorw: ALWAYS
Step 4. Add a Button to the HBox
- Properties:
§ Pref Width: 100
§ Pref Height: 50
- Code:
§ On Action: btnViewStorePressed
6.1.3 Setg up the CENTER area
For the CENTER area, we use the VBox layout to arrange components vertically. Inside the Vbox,
we use an HBox to arrange the top row of components horizontally. We also use a TableView to
display data in a tabular form. Below the TableView is another HBox containing two buttons Play
and Remove.
27
§ Text: By ID
§ Selected: ü
§ Toggle Group: filterCategory
Step 2.5. Add the second RadioButtons into the HBox
- Properties:
§ Text: By Title
§ Toggle Group: filterCategory
Step 3. Add a TableView into the VBox
- Set TableView’s fx:id property to tblMedia
- Add for TableColumns
§ The Title column:
o Text: ID
o fx:id: colMediaId
§ The Title column:
o Text: Title
o fx:id: colMediaTitle
§ The Category column:
o Text: Category
o fx:id: colMediaCategory
§ The Cost column:
o Text: Cost
o fx:id: colMediaCost
Step 4. Add another HBox below the TableView into the Vbox
Step 4.1. Set up the HBox
- Properties:
§ Alignment: TOP_RIGHT
- Layout:
§ Padding: 10 Top
§ Spacing: 20
Step 4.2. Add button Play into the HBox
- Properties:
§ Text: Play
- Layout:
§ Pref Width: 60
- Code:
§ fx:id: btnPlay
§ On Action: btnPlayPressed
Step 4.3. Add button Remove into the HBox
- Properties:
§ Text: Remove
- Layout:
§ Pref Width: 60
- Code:
§ fx:id: btnRemove
§ On Action: btnRemovePressed
28
6.1.4 Setting up the BOTTOm area
Declare one attribute in the CartController class: Cart cart (because we need
information of the items in the cart to display them) and and pass it to the constructor.
29
Figure 39. Declaration of CartController class
In line 78, we set the cart’s list of items to the items of the TableView. Note that this will initially
cause an error, because we cannot set a regular List as the items of a TableView. Instead, we
have to use an ObservableList, so that any change in the data can be observed and reflected
by the TableView. Please open the source code of Cart and change the itemsOrdered from
List<Media> to ObservableList<Media>
After setting the items of the TableView, the data still isn’t showing up in the TableView yet,
because we still have to set up the way the columns can retrieve data. This is done by setting the
columns’ cellValueFactory.
In lines 69 – 76, we set the columns’ cellValueFactory using the class
PropertyValueFactory<S, T> (Read the Javadocs for more details). This class is a
callback that will take in a String <property> and look for the method
30
get<property>() in the Source S class. If a method matching this pattern exists, the value
returned from this method is returned to the TableCell.
You can now test the Cart Screen with some media in your cart, the results will look roughly like
this:
31
Figure 43. Modified initialize() method
Put some code at the end of the initialize() method to add a ChangeListener to the
TableView’s selectedItem property (lines 83 – 88 in Figure 43). Here, we create an
anonymous inner class for the ChangeListener. All ChangeListeners must implement
the changed() method. Whenever a selected item in the TableView is changed, the method
changed() is called. Here, we check to make sure the newValue is not null (the user didn’t
just unselect) and call the updateButtonBar() method (Figure 44)
32
6.5 Deleting a media
Next, we will implement the event handling for the “Remove” button. Please add a method name
to the onAction property of the button in Scene Builder. You can refer to the event-handling code
below:
Note that we don’t need to invoke an update for the TableView because it can already observe
the changes through the ObservableList and update its display.
6.6 Filter items in cart – FilteredList
This exercise is optional (full credit can still be given for this lab without doing this exercise), but
you can do it for extra credit.
We will implement a filter that is re-applied every time the user makes a change in the filter text
field. To do this, again, we need references to the text field where the user inputs the filter string,
and the two radio buttons (to determine what criteria are being used to filter).
Similar to the above, please add the fx:id property for the components in SceneBuilder and create
three corresponding attributes in the controller:
- The TextField: tfFilter
- The RadioButton “By ID”: radioBtnFilterId
- The RadioButton “By Title”: radioBtnFilterTitle
At the end of the initialize() method, put some code to add a ChangeListener to the
TextField’s text property (illustrated in Figure 46):
The following code is used to switch from Store Screen to Cart Screen when user click on the
button View Cart in Store Screen:
33
Figure 47. Source code switch from Store Screen to Cart Screen
This code is placed in ViewStoreController class created earlier. Make sure that you add
the On Action property for the View Cart button.
Note: You may need to add the Cart cart attribute to the ViewStoreController class and
modify its constructor to pass both Store store and Cart cart to the constructor.
34
9 Check all the previous source codes to catch/handle/delegate
runtime exceptions
Review all methods, classes in AimsProject, catch/handle or delegate all exceptions if necessary.
The exception delegation mechanism is especially helpful for constructors so that no object is
created if there is any violation of the requirement/constraints.
Hint: In Aims Project, we can apply exception handling to validate data constraints such as non-
negative price, to validate policies like the restriction of the number of orders, and to handle
unexpected interactions, e.g., user try to remove an author while the author is not listed.
For example, the following piece of code illustrates how to control the number of items in the cart
with exception.
35
• At this point, you should output an error message using System.err.println()
method and the PlayerException should be raised.
- The example of codes and results for the play() of DigitalVideoDisc are illustrated in the
following figures.
public void play() throws PlayerException {
if (this.getLength() > 0) {
// TODO Play DVD as you have implemented
} else {
throw new PlayerException("ERROR: DVD length is non-positive!");
}
}
- Save your changes and make the same with the play() method of Track.
36
public void play() throws PlayerException{
if(this.getLength() > 0) {
// TODO Play all tracks in the CD as you have implemented
java.util.Iterator iter = tracks.iterator();
Track nextTrack;
while(iter.hasNext()) {
nextTrack = (Track) iter.next();
try {
nextTrack.play();
}catch(PlayerException e) {
throw e;
}
}
}else {
throw new PlayerException("ERROR: CD length is non-positive!");
}
}
- You should modify the above source code so that if any track in a CD can’t play, it throws a
PlayerException exception.
37
Figure 51. Swing dialog showing error
13 Reading Document
Please read the following links for better understanding.
• Exception-handling basics:
https://developer.ibm.com/tutorials/j-perry-exceptions/
• Basic guidelines: Although the examples are in C++, the ideas are important.
https://docs.microsoft.com/en-us/cpp/cpp/errors-and-exception-handling-modern-
cpp?view=vs-2019#basic-guidelines
38