Skip to content

Commit f6b4a51

Browse files
committed
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.
1 parent 5fd40a5 commit f6b4a51

8 files changed

Lines changed: 108 additions & 89 deletions

collections/java/javafx-8-tutorial-intro.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: article
33
title: "JavaFX 8 Tutorial"
44
date: 2014-04-19 00:00
5-
updated: 2014-08-27 00:00
5+
updated: 2015-03-12 00:00
66
slug: javafx-8-tutorial-intro
77
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-intro.md
88
description: "This seven-part tutorial walks through designing, programming and deploying an address application with JavaFX."

collections/java/javafx-8-tutorial-part1.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: article
33
title: "JavaFX 8 Tutorial - Part 1: Scene Builder"
44
date: 2014-04-19 01:00
5-
updated: 2014-08-27 00:00
5+
updated: 2015-03-12 00:00
66
slug: javafx-8-tutorial-part1
77
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part1.md
88
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:
4040
paging: 7
4141
- header: "Download Sources"
4242
body:
43-
- text: Part 1 as Eclipse Project <em>(requires at least JDK 8u20)</em>
44-
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-1.zip
43+
- text: Part 1 as Eclipse Project <em>(requires at least JDK 8u40)</em>
44+
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-1.zip
4545
icon-css: fa fa-fw fa-download
4646
- header: Languages
4747
languages: true
@@ -86,8 +86,8 @@ sidebars:
8686
### Prerequisites
8787

8888
* Latest [Java JDK 8](http://www.oracle.com/technetwork/java/javase/downloads/index.html) (includes **JavaFX 8**).
89-
* 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.
90-
* [Scene Builder 2.0](http://www.oracle.com/technetwork/java/javase/downloads/javafxscenebuilder-info-2157684.html) or greater
89+
* 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.
90+
* [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)).
9191

9292

9393
### Eclipse Configurations
@@ -168,6 +168,8 @@ Right-click on the view package and create a new *FXML Document* called `PersonO
168168

169169
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).
170170

171+
(If Scene Builder does not open, go to *Window | Preferences | JavaFX* and set the correct path to your Scene Builder installation).
172+
171173
1. Select the *Anchor Pane* in your Hierarchy and adjust the size under Layout (right side):
172174
![Anchor Pane Size](/assets/library/javafx-8-tutorial/part1/anchor-pane-size.png)
173175

@@ -182,7 +184,7 @@ Right-click on `PersonOverview.fxml` and choose *Open with Scene Builder*. Now y
182184
5. Change the column text (under Properties) to "First Name" and "Last Name".
183185
![Column Texts](/assets/library/javafx-8-tutorial/part1/column-texts.png)
184186

185-
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.
187+
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.
186188
![Column Resize Policy](/assets/library/javafx-8-tutorial/part1/column-resize-policy.png)
187189

188190
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
195197
*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".*
196198
![Add labels](/assets/library/javafx-8-tutorial/part1/add-labels.png)
197199

198-
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.
200+
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.
199201
![Button Group](/assets/library/javafx-8-tutorial/part1/button-group.png)
200202

201203
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
333335

334336
### Frequent Problems
335337

336-
If JavaFX can't find the `fxml` file you speicified, you might get the following error message:
338+
If JavaFX can't find the `fxml` file you specified, you might get the following error message:
337339

338340
`java.lang.IllegalStateException: Location is not set.`
339341

@@ -353,7 +355,7 @@ In [Tutorial Part 2](/java/javafx-8-tutorial-part2/) we will add some data and f
353355

354356
##### Some other articles you might find interesting
355357

356-
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
358+
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
357359
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
358360
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
359361
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)

collections/java/javafx-8-tutorial-part2.md

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: article
33
title: "JavaFX 8 Tutorial - Part 2: Model and TableView"
44
date: 2014-04-23 00:00
5-
updated: 2014-08-27 00:00
5+
updated: 2015-03-12 00:00
66
slug: javafx-8-tutorial-part2
77
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part2.md
88
description: "Use a JavaFX TableView to display an ObservableList of Persons."
@@ -40,8 +40,8 @@ sidebars:
4040
paging: 7
4141
- header: "Download Sources"
4242
body:
43-
- text: Part 2 as Eclipse Project <em>(requires at least JDK 8u20)</em>
44-
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-2.zip
43+
- text: Part 2 as Eclipse Project <em>(requires at least JDK 8u40)</em>
44+
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-2.zip
4545
icon-css: fa fa-fw fa-download
4646
- header: Languages
4747
languages: true
@@ -216,7 +216,7 @@ public class Person {
216216

217217
### Explanations
218218

219-
* 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).
219+
* 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).
220220
* [`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/).
221221

222222

@@ -279,7 +279,7 @@ From those collections, we need the `ObservableList`. To create a new `Observabl
279279

280280
Now let's finally get some data into our table. We'll need a controller for our `PersonOverview.fxml`.
281281

282-
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).
282+
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.
283283
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:
284284

285285
<div class="alert alert-info">
@@ -363,6 +363,20 @@ Now this code will probably need some explaining:
363363
* 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).
364364

365365

366+
<div class="alert alert-info">
367+
<p>
368+
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()`:
369+
</p>
370+
<p>
371+
<pre>myIntegerColumn.setCellValueFactory(cellData ->
372+
cellData.getValue().myIntegerProperty().<mark>asObject()</mark>);</pre>
373+
</p>
374+
<p>
375+
This is necessary because of a bad design decision of JavaFX (see <a href="https://community.oracle.com/thread/2575601">this discussion</a>).
376+
</p>
377+
</div>
378+
379+
366380
### Connecting MainApp with the PersonOverviewController
367381

368382
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() {
380394
FXMLLoader loader = new FXMLLoader();
381395
loader.setLocation(MainApp.class.getResource("view/PersonOverview.fxml"));
382396
AnchorPane personOverview = (AnchorPane) loader.load();
383-
397+
384398
// Set person overview into the center of root layout.
385399
rootLayout.setCenter(personOverview);
386400

387-
// Give the controller access to the main app.
401+
<mark> // Give the controller access to the main app.
388402
PersonOverviewController controller = loader.getController();
389-
controller.setMainApp(this);
403+
controller.setMainApp(this);</mark>
390404

391405
} catch (IOException e) {
392406
e.printStackTrace();
@@ -437,7 +451,7 @@ In [Tutorial Part 3](/java/javafx-8-tutorial-part3/) we will add more functional
437451

438452
##### Some other articles you might find interesting
439453

440-
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
454+
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
441455
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
442456
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
443457
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)

collections/java/javafx-8-tutorial-part3.md

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
layout: article
33
title: "JavaFX 8 Tutorial - Part 3: Interacting with the User"
44
date: 2014-04-24 00:00
5-
updated: 2014-08-27 00:00
5+
updated: 2015-03-12 00:00
66
slug: javafx-8-tutorial-part3
77
github: https://github.com/marcojakob/code.makery.ch/edit/master/collections/java/javafx-8-tutorial-part3.md
88
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:
4040
paging: 7
4141
- header: "Download Sources"
4242
body:
43-
- text: Part 3 as Eclipse Project <em>(requires at least JDK 8u20)</em>
44-
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-3.zip
43+
- text: Part 3 as Eclipse Project <em>(requires at least JDK 8u40)</em>
44+
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-3.zip
4545
icon-css: fa fa-fw fa-download
4646
- header: Languages
4747
languages: true
@@ -291,14 +291,7 @@ There will be an `ArrayIndexOutOfBoundsException` because it could not remove a
291291

292292
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.)
293293

294-
We'll add a popup dialog to inform the user. You'll need to **add a library** for the [Dialogs](/blog/javafx-8-dialogs/):
295-
296-
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/)).
297-
**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.**
298-
2. Create a **lib** subfolder in the project and add the controlsfx-jar file to this folder.
299-
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.
300-
301-
![ControlsFX Libaray](/assets/library/javafx-8-tutorial/part3/controlsfx-library.png)
294+
We'll add a popup dialog to inform the user.
302295

303296
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:
304297

@@ -316,27 +309,28 @@ private void handleDeletePerson() {
316309
personTable.getItems().remove(selectedIndex);
317310
} else {
318311
// Nothing selected.
319-
Dialogs.create()
320-
.title("No Selection")
321-
.masthead("No Person Selected")
322-
.message("Please select a person in the table.")
323-
.showWarning();
312+
Alert alert = new Alert(AlertType.WARNING);
313+
alert.initOwner(mainApp.getPrimaryStage());
314+
alert.setTitle("No Selection");
315+
alert.setHeaderText("No Person Selected");
316+
alert.setContentText("Please select a person in the table.");
317+
318+
alert.showAndWait();
324319
}
325320
}
326321
</pre>
327322

328323
<div class="alert alert-info">
329-
For more examples on how to use Dialogs read <a class="alert-link" href="/blog/javafx-8-dialogs/">JavaFX 8 Dialogs</a>.
324+
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>.
330325
</div>
331326

332327

333-
334328
*****
335329

336330

337331
## The New and Edit Dialogs
338332

339-
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.
333+
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.
340334

341335

342336
### 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
347341
2. Use a `GridPane`, `Label`s, `TextField`s and `Button`s to create a Dialog like the following:
348342
![Edit Dialog](/assets/library/javafx-8-tutorial/part3/person-edit-dialog2.png)
349343

350-
*If you don't to do the work, you can download this [PersonEditDialog.fxml](/assets/library/javafx-8-tutorial/part3/PersonEditDialog.fxml).*
351-
352344

353345
### Create the Controller
354346

@@ -360,11 +352,10 @@ Create the controller for the Dialog as `PersonEditDialogController.java`:
360352
package ch.makery.address.view;
361353

362354
import javafx.fxml.FXML;
355+
import javafx.scene.control.Alert;
356+
import javafx.scene.control.Alert.AlertType;
363357
import javafx.scene.control.TextField;
364358
import javafx.stage.Stage;
365-
366-
import org.controlsfx.dialog.Dialogs;
367-
368359
import ch.makery.address.model.Person;
369360
import ch.makery.address.util.DateUtil;
370361

@@ -507,11 +498,14 @@ public class PersonEditDialogController {
507498
return true;
508499
} else {
509500
// Show the error message.
510-
Dialogs.create()
511-
.title("Invalid Fields")
512-
.masthead("Please correct invalid fields")
513-
.message(errorMessage)
514-
.showError();
501+
Alert alert = new Alert(AlertType.ERROR);
502+
alert.initOwner(dialogStage);
503+
alert.setTitle("Invalid Fields");
504+
alert.setHeaderText("Please correct invalid fields");
505+
alert.setContentText(errorMessage);
506+
507+
alert.showAndWait();
508+
515509
return false;
516510
}
517511
}
@@ -616,11 +610,13 @@ private void handleEditPerson() {
616610

617611
} else {
618612
// Nothing selected.
619-
Dialogs.create()
620-
.title("No Selection")
621-
.masthead("No Person Selected")
622-
.message("Please select a person in the table.")
623-
.showWarning();
613+
Alert alert = new Alert(AlertType.WARNING);
614+
alert.initOwner(mainApp.getPrimaryStage());
615+
alert.setTitle("No Selection");
616+
alert.setHeaderText("No Person Selected");
617+
alert.setContentText("Please select a person in the table.");
618+
619+
alert.showAndWait();
624620
}
625621
}
626622
</pre>
@@ -644,7 +640,7 @@ In [Tutorial Part 4](/java/javafx-8-tutorial-part4/) we will add some CSS stylin
644640

645641
##### Some other articles you might find interesting
646642

647-
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
643+
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
648644
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
649645
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
650646
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)

collections/java/javafx-8-tutorial-part4.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ sidebars:
4040
paging: 7
4141
- header: "Download Sources"
4242
body:
43-
- text: Part 4 as Eclipse Project <em>(requires at least JDK 8u20)</em>
44-
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.0/addressapp-jfx8-part-4.zip
43+
- text: Part 4 as Eclipse Project <em>(requires at least JDK 8u40)</em>
44+
link: https://github.com/marcojakob/tutorial-javafx-8/releases/download/v1.1/addressapp-jfx8u40-part-4.zip
4545
icon-css: fa fa-fw fa-download
4646
- header: Languages
4747
languages: true
@@ -329,7 +329,7 @@ It looks much nicer with a custom icon:
329329

330330
### The Icon File
331331

332-
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/).
332+
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).
333333

334334
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:
335335

@@ -373,7 +373,7 @@ In [Tutorial Part 5](/java/javafx-8-tutorial-part5/) we will add XML storage for
373373

374374
##### Some other articles you might find interesting
375375

376-
* [JavaFX Dialogs](/blog/javafx-8-dialogs/)
376+
* [JavaFX Dialogs (official)](/blog/javafx-dialogs-official/)
377377
* [JavaFX Date Picker](/blog/javafx-8-date-picker/)
378378
* [JavaFX Event Handling Examples](/blog/javafx-8-event-handling-examples/)
379379
* [JavaFX TableView Sorting and Filtering](/blog/javafx-8-tableview-sorting-filtering/)

0 commit comments

Comments
 (0)