Permalink
Browse files

Update JavaFX 8 Tutorial for JDK 8u40

* Remove controlsfx dialogs and use the now included JavaFX dialogs instead.
* Reference the updated example downloads (v1.1).
* Add an info box for `setCellValueFactory` when used with `IntegerProperty` and `DoubleProperty` in part 2.
* Correct some minor typos.
  • Loading branch information...
marcojakob committed Mar 12, 2015
1 parent 5fd40a5 commit f6b4a51b41957b753bfbfc8c1f637a6849ceeab5
@@ -2,7 +2,7 @@
layout: article
title: "JavaFX 8 Tutorial"
date: 2014-04-19 00:00
updated: 2014-08-27 00:00
updated: 2015-03-12 00:00
slug: javafx-8-tutorial-intro
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-intro.md
description: "This seven-part tutorial walks through designing, programming and deploying an address application with JavaFX."
@@ -2,7 +2,7 @@
layout: article
title: "JavaFX 8 Tutorial - Part 1: Scene Builder"
date: 2014-04-19 01:00
updated: 2014-08-27 00:00
updated: 2015-03-12 00:00
slug: javafx-8-tutorial-part1
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part1.md
description: "Learn how to set up a JavaFX project. This is part one of a seven-part tutorial about designing, programming and deploying an address application with JavaFX."
@@ -40,8 +40,8 @@ sidebars:
paging: 7
- header: "Download Sources"
body:
- text: Part 1 as Eclipse Project <em>(requires at least JDK 8u20)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-1.zip
- text: Part 1 as Eclipse Project <em>(requires at least JDK 8u40)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-1.zip
icon-css: fa fa-fw fa-download
- header: Languages
languages: true
@@ -86,8 +86,8 @@ sidebars:
### Prerequisites
* Latest [Java JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) (includes **JavaFX 8**).
* Eclipse 4.3 or greater with e(fx)clipse plugin. The easiest way is to download the preconfigured distro from the [e(fx)clipse website](http://efxclipse.bestsolution.at/install.html#all-in-one). As an alternative you can use an [update site](http://www.eclipse.org/efxclipse/install.html) for your Eclipse installation.
* [Scene Builder 2.0](http://www.oracle.com/technetwork/java/javase/downloads/javafxscenebuilder-info-2157684.html) or greater
* Eclipse 4.4 or greater with e(fx)clipse plugin. The easiest way is to download the preconfigured distro from the [e(fx)clipse website](http://efxclipse.bestsolution.at/install.html#all-in-one). As an alternative you can use an [update site](http://www.eclipse.org/efxclipse/install.html) for your Eclipse installation.
* [Scene Builder 8.0](http://gluonhq.com/products/downloads/) (provided by Gluon because [Oracle only ships it in source code form](http://www.oracle.com/technetwork/java/javase/downloads/sb2download-2177776.html)).
### Eclipse Configurations
@@ -168,6 +168,8 @@ Right-click on the view package and create a new *FXML Document* called `PersonO
Right-click on `PersonOverview.fxml` and choose *Open with Scene Builder*. Now you should see the Scene Builder with just an *AncherPane* (visible under Hierarchy on the left).
(If Scene Builder does not open, go to *Window | Preferences | JavaFX* and set the correct path to your Scene Builder installation).
1. Select the *Anchor Pane* in your Hierarchy and adjust the size under Layout (right side):
![Anchor Pane Size](/assets/library/javafx-8-tutorial/part1/anchor-pane-size.png)
@@ -182,7 +184,7 @@ Right-click on `PersonOverview.fxml` and choose *Open with Scene Builder*. Now y
5. Change the column text (under Properties) to "First Name" and "Last Name".
![Column Texts](/assets/library/javafx-8-tutorial/part1/column-texts.png)
6. Select the *TableView* choose *constrained-resize* for the *Column Resize Policy* (under Properties). This ensures that the colums will always take up all available space.
6. Select the *TableView* and choose *constrained-resize* for the *Column Resize Policy* (under Properties). This ensures that the colums will always take up all available space.
![Column Resize Policy](/assets/library/javafx-8-tutorial/part1/column-resize-policy.png)
7. Add a *Label* on the right side with the text "Person Details" (hint: use the search to find the *Label*). Adjust it's layout using anchors.
@@ -195,7 +197,7 @@ Right-click on `PersonOverview.fxml` and choose *Open with Scene Builder*. Now y
*Note: To add a row to the GridPane select an existing row number (will turn yellow), right-click the row number and choose "Add Row".*
![Add labels](/assets/library/javafx-8-tutorial/part1/add-labels.png)
10. Add the three buttons at the bottom. Tip: Select all of them, right-click and call *Wrap In | HBox*. This groups them together. You might need to specify a *spacing* inside the HBox. Then, also set anchors (right and bottom) so they stay in the right place.
10. Add a *ButtonBar* at the bottom. Add three buttons to the bar. Now, set anchors (right and bottom) to the *ButtonBar* so it stays in the right place.
![Button Group](/assets/library/javafx-8-tutorial/part1/button-group.png)
11. Now you should see something like the following. Use the *Preview* menu to test its resizing behaviour.
@@ -333,7 +335,7 @@ If you run the application now, you should see something like the screenshot at
### Frequent Problems
If JavaFX can't find the `fxml` file you speicified, you might get the following error message:
If JavaFX can't find the `fxml` file you specified, you might get the following error message:
`java.lang.IllegalStateException: Location is not set.`
@@ -353,7 +355,7 @@ In [Tutorial Part 2](/java/javafx-8-tutorial-part2/) we will add some data and f
##### Some other articles you might find interesting
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)
@@ -2,7 +2,7 @@
layout: article
title: "JavaFX 8 Tutorial - Part 2: Model and TableView"
date: 2014-04-23 00:00
updated: 2014-08-27 00:00
updated: 2015-03-12 00:00
slug: javafx-8-tutorial-part2
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part2.md
description: "Use a JavaFX TableView to display an ObservableList of Persons."
@@ -40,8 +40,8 @@ sidebars:
paging: 7
- header: "Download Sources"
body:
- text: Part 2 as Eclipse Project <em>(requires at least JDK 8u20)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-2.zip
- text: Part 2 as Eclipse Project <em>(requires at least JDK 8u40)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-2.zip
icon-css: fa fa-fw fa-download
- header: Languages
languages: true
@@ -216,7 +216,7 @@ public class Person {
### Explanations
* With JavaFX it's common to use [`Properties`](http://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/Property.html) for all fields of a model class. A `Property` allow us, for example, to automatically be notified when the `lastName` or any other variable is changed. This helps us keep the view in sync with the data. To learn more about `Properties` read [Using JavaFX Properties and Binding](http://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/binding.htm).
* With JavaFX it's common to use [`Properties`](http://docs.oracle.com/javase/8/javafx/api/javafx/beans/property/Property.html) for all fields of a model class. A `Property` allows us, for example, to automatically be notified when the `lastName` or any other variable is changed. This helps us keep the view in sync with the data. To learn more about `Properties` read [Using JavaFX Properties and Binding](http://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/binding.htm).
* [`LocalDate`](http://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html), the type we're using for `birthday`, is part of the new [Date and Time API for JDK 8](http://docs.oracle.com/javase/tutorial/datetime/iso/).
@@ -279,7 +279,7 @@ From those collections, we need the `ObservableList`. To create a new `Observabl
Now let's finally get some data into our table. We'll need a controller for our `PersonOverview.fxml`.
1. Create a normal class inside the **view** package called `PersonOverviewController.java`. (We must put it in the same package as the `PersonOverview.fxml`, otherwise the SceneBuilder won't find it - at least not in the current version).
1. Create a normal class inside the **view** package called `PersonOverviewController.java`. (We must put it in the same package as the `PersonOverview.fxml`, otherwise the SceneBuilder won't find it.
2. We'll add some instance variables that give us access to the table and the labels inside the view. The fields and some methods have a special `@FXML` annotation. This is necessary for the fxml file to have access to private fields and private methods. After we have everything set up in the fxml file, the application will automatically fill the variables when the fxml file is loaded. So let's add the following code:
<div class="alert alert-info">
@@ -363,6 +363,20 @@ Now this code will probably need some explaining:
* The `setCellValueFactory(...)` that we set on the table colums are used to determine which field inside the `Person` objects should be used for the particular column. The arrow `->` indicates that we're using a Java 8 feature called *Lambdas*. (Another option would be to use a [PropertyValueFactory](http://docs.oracle.com/javase/8/javafx/api/), but this is not type-safe).
<div class="alert alert-info">
<p>
We're only using `StringProperty` values for our table columns in this example. When you want to use `IntegerProperty` or `DoubleProperty`, the `setCellValueFactory(...)` must have an additional `asObject()`:
</p>
<p>
<pre>myIntegerColumn.setCellValueFactory(cellData ->
cellData.getValue().myIntegerProperty().<mark>asObject()</mark>);</pre>
</p>
<p>
This is necessary because of a bad design decision of JavaFX (see <a href="https://community.oracle.com/thread/2575601">this discussion</a>).
</p>
</div>
### Connecting MainApp with the PersonOverviewController
The `setMainApp(...)` method must be called by the `MainApp` class. This gives us a way to access the `MainApp` object and get the list of `Persons` and other things. Replace the `showPersonOverview()` method with the following. It contains two additional lines:
@@ -380,13 +394,13 @@ public void showPersonOverview() {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
AnchorPane personOverview = (AnchorPane) loader.load();
// Set person overview into the center of root layout.
rootLayout.setCenter(personOverview);
// Give the controller access to the main app.
<mark> // Give the controller access to the main app.
PersonOverviewController controller = loader.getController();
controller.setMainApp(this);
controller.setMainApp(this);</mark>
} catch (IOException e) {
e.printStackTrace();
@@ -437,7 +451,7 @@ In [Tutorial Part 3](/java/javafx-8-tutorial-part3/) we will add more functional
##### Some other articles you might find interesting
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)
@@ -2,7 +2,7 @@
layout: article
title: "JavaFX 8 Tutorial - Part 3: Interacting with the User"
date: 2014-04-24 00:00
updated: 2014-08-27 00:00
updated: 2015-03-12 00:00
slug: javafx-8-tutorial-part3
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part3.md
description: "React to selection changes in the JavaFX TableView. Add, edit and remove items from the table and validate user input."
@@ -40,8 +40,8 @@ sidebars:
paging: 7
- header: "Download Sources"
body:
- text: Part 3 as Eclipse Project <em>(requires at least JDK 8u20)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-3.zip
- text: Part 3 as Eclipse Project <em>(requires at least JDK 8u40)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-3.zip
icon-css: fa fa-fw fa-download
- header: Languages
languages: true
@@ -291,14 +291,7 @@ There will be an `ArrayIndexOutOfBoundsException` because it could not remove a
To ignore such an error is not very nice, of course. We should let the user know that he/she must select a person before deleting. (Even better would be if we disabled the button so that the user doesn't even have the chance to do something wrong.)
We'll add a popup dialog to inform the user. You'll need to **add a library** for the [Dialogs](/blog/javafx-8-dialogs/):
1. Download this [controlsfx-8.0.6_20.jar](https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/controlsfx-8.0.6_20.jar) (you could also get it from the [ControlsFX Website](http://fxexperience.com/controlsfx/)).
**Important: The ControlsFX must be version `8.0.6_20` or greater to work with `JDK 8u20` and above as there was a breaking change introduced in that version.**
2. Create a **lib** subfolder in the project and add the controlsfx-jar file to this folder.
3. Add the library to your project's **classpath**: In Eclipse *right-click on the jar file* | *Build Path* | *Add to Build Path*. Now Eclipse knows about the library.
![ControlsFX Libaray](/assets/library/javafx-8-tutorial/part3/controlsfx-library.png)
We'll add a popup dialog to inform the user.
With some changes made to the `handleDeletePerson()` method, we can show a simple popup dialog whenever the user pushes the delete button while no person is selected in the table:
@@ -316,27 +309,28 @@ private void handleDeletePerson() {
personTable.getItems().remove(selectedIndex);
} else {
// Nothing selected.
Dialogs.create()
.title("No Selection")
.masthead("No Person Selected")
.message("Please select a person in the table.")
.showWarning();
Alert alert = new Alert(AlertType.WARNING);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("No Selection");
alert.setHeaderText("No Person Selected");
alert.setContentText("Please select a person in the table.");
alert.showAndWait();
}
}
</pre>
<div class="alert alert-info">
For more examples on how to use Dialogs read <a class="alert-link" href="/blog/javafx-8-dialogs/">JavaFX 8 Dialogs</a>.
For more examples on how to use Dialogs read my blog post about <a class="alert-link" href="/blog/javafx-dialogs-official/">JavaFX Dialogs</a>.
</div>
*****
## The New and Edit Dialogs
The new and edit actions are a bit more work: We'll need a custom dialog (i.e. a new stage) with a form to ask the user for details about the person.
The new and edit actions are a bit more work: We'll need a custom dialog (that means a new stage) with a form to ask the user for details about the person.
### Design the Dialog
@@ -347,8 +341,6 @@ The new and edit actions are a bit more work: We'll need a custom dialog (i.e. a
2. Use a `GridPane`, `Label`s, `TextField`s and `Button`s to create a Dialog like the following:
![Edit Dialog](/assets/library/javafx-8-tutorial/part3/person-edit-dialog2.png)
*If you don't to do the work, you can download this [PersonEditDialog.fxml](/assets/library/javafx-8-tutorial/part3/PersonEditDialog.fxml).*
### Create the Controller
@@ -360,11 +352,10 @@ Create the controller for the Dialog as `PersonEditDialogController.java`:
package ch.makery.address.view;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import org.controlsfx.dialog.Dialogs;
import ch.makery.address.model.Person;
import ch.makery.address.util.DateUtil;
@@ -507,11 +498,14 @@ public class PersonEditDialogController {
return true;
} else {
// Show the error message.
Dialogs.create()
.title("Invalid Fields")
.masthead("Please correct invalid fields")
.message(errorMessage)
.showError();
Alert alert = new Alert(AlertType.ERROR);
alert.initOwner(dialogStage);
alert.setTitle("Invalid Fields");
alert.setHeaderText("Please correct invalid fields");
alert.setContentText(errorMessage);
alert.showAndWait();
return false;
}
}
@@ -616,11 +610,13 @@ private void handleEditPerson() {
} else {
// Nothing selected.
Dialogs.create()
.title("No Selection")
.masthead("No Person Selected")
.message("Please select a person in the table.")
.showWarning();
Alert alert = new Alert(AlertType.WARNING);
alert.initOwner(mainApp.getPrimaryStage());
alert.setTitle("No Selection");
alert.setHeaderText("No Person Selected");
alert.setContentText("Please select a person in the table.");
alert.showAndWait();
}
}
</pre>
@@ -644,7 +640,7 @@ In [Tutorial Part 4](/java/javafx-8-tutorial-part4/) we will add some CSS stylin
##### Some other articles you might find interesting
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)
@@ -40,8 +40,8 @@ sidebars:
paging: 7
- header: "Download Sources"
body:
- text: Part 4 as Eclipse Project <em>(requires at least JDK 8u20)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-4.zip
- text: Part 4 as Eclipse Project <em>(requires at least JDK 8u40)</em>
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-4.zip
icon-css: fa fa-fw fa-download
- header: Languages
languages: true
@@ -329,7 +329,7 @@ It looks much nicer with a custom icon:
### The Icon File
A possible place to get free icons is [Icon Finder](http://www.iconfinder.com). I downloaded a little [address book icon](http://www.iconfinder.com/icondetails/86957/32/).
A possible place to get free icons is [Icon Finder](http://www.iconfinder.com). I downloaded a little [address book icon](https://www.iconfinder.com/icons/86957/address_book_icon#size=32).
Create a (normal) folder inside your AddressApp project called **resources** and a subfolder called **images** in it. Put the icon of your choice inside the images folder. Your folder structure should look something like this now:
@@ -373,7 +373,7 @@ In [Tutorial Part 5](/java/javafx-8-tutorial-part5/) we will add XML storage for
##### Some other articles you might find interesting
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)
Oops, something went wrong.

0 comments on commit f6b4a51

Please sign in to comment.