Vous êtes sur la page 1sur 227



POUL KLAUSEN

JAVA 15: MORE


ABOUT JAVAFX
SOFTWARE DEVELOPMENT

2
Java 15: More about JavaFX: Software Development
1st edition
© 2018 Poul Klausen & bookboon.com
ISBN 978-87-403-2200-2
Peer review by Ove Thomsen, EA Dania

3
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Contents

CONTENTS
Foreword 7

1 Introduction 9

2 JavaFX properties 10
2.1 Binding properties 20
Exercise 1 26
2.2 Observable collections 28
2.3 Binding observable collections 35
Exercise 2 41
2.4 Binding persons 43
2.5 The screen 47
2.6 Decorations 50
2.7 Modality 53
Problem 1 56

www.sylvania.com

We do not reinvent
the wheel we reinvent
light.
Fascinating lighting offers an infinite spectrum of
possibilities: Innovative technologies and new
markets provide both opportunities and challenges.
An environment in which your expertise is in high
demand. Enjoy the supportive working atmosphere
within our global group and benefit from international
career paths. Implement sustainable ideas in close
cooperation with other specialists and contribute to
influencing our future. Come and join us in reinventing
light every day.

Light is OSRAM

4
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Contents

3 Advanced controls 59
3.1 TableView 59
Exercise 3 71
3.2 Edit cells in a TableView 71
Problem 2 83
3.3 Filters 85
Exercise 4 87
3.4 A TreeView control 88
Exercise 5 96
3.5 A TreeView with Country objects 98
3.6 A TreeTableView 103
3.7 A TreeTableView, an extended example 110

4 Drag and drop 114


4.1 Simple press-drag-release gesture 115
4.2 Full press-drag-release gesture 118
4.3 Drag-and-drop gesture 120

5 MVC 134

6 User defined controls 144


6.1 A LabelField 146
6.2 A Canvas 148
6.3 A Spinner 150

7 JavaFX and concurrency 153


7.1 A Task 156
7.2 A Service 162

8 3D Shapes 163
8.1 Box, Sphere and Cylinder 166
8.2 Material 169
8.3 Draw mode 171
8.4 Cull face 172
8.5 Camera and Light 175
Exercise 6 181
Exercise 7 182
8.6 A last remark 182

5
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Contents

9 Charts 183

10 Final Example 191


10.1 Development 192
10.2 A simple prototype 193
10.3 Drawing the axes 194
10.4 Settings for the coordinate system 196
10.5 Drawing a function from a formal 198
10.6 The program architecture 200
10.7 Drawing a plot 202
10.8 Refactoring the expression dialog 205
10.9 Implementing the Functions menu 207
10.10 Implementing the Zoom menu 212
10.11 Implementing the Edit menu 213
10.12 Implementing the Calculations menu 218
10.13 Implementing the File menu 218
10.14 A final iteration 224
10.15 A last remark 226

6
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Foreword

FOREWORD
This book is the fifteenth in a series of books on software development and the book is
a natural continuation of the previous book on programming of GUI applications with
JavaFX. The book focuses primarily on JavaFX properties and data bindings, but also treats
the basic architecture of a JavaFX application as Model-View-Presenter. Other important
topics are advanced controls like TableView and TreeView and also charts and 3D graphics
are mentioned. The book requires knowledge of JavaFX corresponding to what is dealt
with in the book Java 14. After reading this book and solving the corresponding exercises
and tasks, you should be able to write completed GUI applications using JavaFX and use
JavaFX as a alternative to Swing.

As the title says this series of books deals with software development, and the goal is to
teach the reader how to develop applications in Java. It can be learned by reading about
the subject and by studying complete sample programs, but most importantly by yourself
to do it and write your own programs from scratch. Therefore, an important part of the
books is exercises and problems, where the reader has to write programs that correspond to
the substance being treated in the books. All books in the series is built around the same
skeleton and will consist of text and examples and exercises and problems that are placed
in the text where they naturally belongs. The difference between exercises and problems is
that the exercises largely deals with repetitions of the substance that is presented in the text,
and furthermore it is relatively accurately described what to do. Problems are in turn more
loosely described, and are typically a little bigger and there is rarely any clear best solution.
These are books to be read from start to finish, but the many code examples, including
exercises and problems plays a central role, and it is important that the reader predict in
detail studying the code to the many examples and also solves the exercises and problems
or possibly just studying the recommended solutions.

All books ends with one or two larger sample programs, which focus primarily is on process
and an explanation of how the program is written. On the other hand appears the code only
to a limited extent – if at all – and the reader should instead study the finished program
code perhaps while testing the program. In addition to show the development of programs
that are larger than the examples, which otherwise is presented, the aim of the concluding
examples also is to show program examples from varying fields of application.

Most books also ends with an appendix dealing with a subject that would not be treated
in the books. It may be issues on the installation of software or other topics in computer
technology, which are not about software development, but where it is necessary to have
an introductory knowledge. If the reader already is familiar with the subject, the current
appendix can be skipped.

7
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Foreword

The programming language is, as mentioned Java, and besides the books use the following
products:

1. NetBeans as IDE for application development


2. MySQL to the extent there is a need for a database server (from the book Java 6
onwards)
3. GlassFish as a web server and application server (from the book Java 11 onwards)

It is products that are free of charge and free to install, and there is even talk about products,
where the installation is progressing all by itself and without major efforts and challenges.
In addition, there are on the web detailed installation instructions for all the three products.
The products are available on Windows and Linux, and it therefore plays no special role if
you use Linux or Windows.

All sample programs are developed and tested on machines running Linux. In fact, it plays
no major role, as both Java and other products work in exactly the same way whether the
platform is one or the other. Some places will be in the books where you could see that
the platform is Linux, and this applies primarily commands that concerning the file system.
Otherwise it has no meaning to the reader that the programs are developed on a Linux
machine, and they can immediately also run under Windows unless a program refers to
the file system where it may be necessary to change the name of a file.

Finally a little about what the books are not. It is not “how to write” or for that matter
reference manuals in Java, but it is as the title says books on software development. It is
my hope that the reader when reading the books and through the many examples can find
inspiration for how to write good programs, but also can be used as a source collection
with a number of examples of solutions to concrete everyday programming problems that
you regularly face as a software developer.

8
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Introduction

1 INTRODUCTION
This book is an immediate continuation of the previous book on JavaFX, which was not
included due to the number of pages, or topics that are more technical:

-- Properties and databinding


-- Advanced controls
-- Drag and drop
-- Architecture and MVC
-- User defined controls
-- JavaFX and concurrency
-- 3D Shapes
-- Charts
-- Final example

You can also say that the book completes what is needed to write Java desktop applications
with a graphical user interface.

As shown in the above list, this book includes many topics, but apart from the first about
properties and binding, the individual topics do not matter to each other and you can
read the topics in line with current needs. The book should therefore show how to solve
concrete problems as illustrated by examples, and compared to the previous book there will
be only a few exercises.

9
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX properties

2 JAVAFX PROPERTIES
Properties and beans have been mentioned several times in the previous books, and all
classes in JavaFX defines properties that you can read or modify as a programmer. In a
typical bean, a property is nothing but get methods and possibly set methodd that represents
a property of the current class, and typically corresponds to a variable with associated get
and set methods. In addition, a Java Bean uses a particular name convention. In JavaFX,
however, a property is a bit more, as it is sometimes necessary to know. All properties in
JavaFX are observable, where an observer can receive notifications regarding invalidations and
changes. There is a strict distinction between read/write properties and read-only properties.
The value of a property can be either a single value or a collection.

Another important difference is that a property is always an object whose class is part of a
particular class hierarchy for properties. As examples can be mentioned

-- IntegerProperty
-- DoubleProperty

(and there are corresponding classes for the other simple data types). These classes are actually
abstract, and for each class there are two specific classes that for an IntegerProperty are

-- SimpleIntegerProperty
-- ReadOnlyIntegerWrapper

where the first represents a read/write property, while the other represents a read-only
property. A property class defines as usual get and set methods, but the class also defines
two methods called getValue() and setValue(). For primitive types, the get and set methods
works on primitive types (int, double and so on), while the other two works on objects
(such as Integer, Double, etc.). For reference types like

-- StringProperty
-- ObjectProperty<T>

all four methods works on objects, and because of autoboxing, there is no difference in
practice, for example on get and getValue(). As an example, below is shown a method that
creates a read/write IntegerProperty

10
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
JAVA 15: MORE ABOUT JAVAFX: JavaFX properties
SOFTWARE
JAVA DEVELOPMENT
15: MORE ABOUT JAVAFX: JavaFX propertIes
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes
private static void test01()
private
{ static void test01()
private static void test01()
{ IntegerProperty p = new SimpleIntegerProperty(100);
{
IntegerProperty p = new SimpleIntegerProperty(100);
System.out.println(p.get());
IntegerProperty p = new SimpleIntegerProperty(100);
System.out.println(p.get());
p.set(200);
System.out.println(p.get());
p.set(200);
System.out.println(p);
p.set(200);
}System.out.println(p);
System.out.println(p);
}
}
and the method (which is a metodin the project FXProperties) is performed you get the result:
and the method
and the method(which
(whichisisa ametodin
metodinthe
the project
project FXProperties)
FXProperties) is performed
is performed you you getresult:
get the the result:
and the method (which is a metodin the project FXProperties) is performed you get the result:
100
100
IntegerProperty [value: 200]
100
IntegerProperty [value: 200]
IntegerProperty [value: 200]
Here you should note the last line that is the result of toString() in the class SimpleIntegerProperty,
Here
Here you should
shouldnotenote thelast
lastline
linethat
that is the result of toString() in the class SimpleIntegerProperty,
whileyou
Here theshould
you note the
first prints thelast
the value
lineof anis
that the
the result
isint. result of
of toString()
toString() in
in the
the class
class SimpleIntegerProperty,
SimpleIntegerProperty,
while the first
while the first prints
printsthethevalue
valueofofananint. int.
while the first prints the value of an int.
Read-only properties are actually a bit more complex as they are a wrapper about two
Read-only
Read-only properties
properties are ensures
are actually a synchronized.
bit morecomplex complex as they are read-only
a wrapperproperty,
about two
properties that
Read-only the system
properties are actually
actually aais bit
bit more
more complex as
Here, they
as the
theyone are
areisaaa wrapper
wrapper about
about two
two
properties
properties
while the that the
that
other thea system
is systemensures
ensures
read/write. The is issynchronized.
idea synchronized.
is that from Here,
Here,
the the
outsidethe
one one
it is
is aaisread-only
a read-only
read-only property,
property,
property,
properties that the system ensures is synchronized. Here, the one is a read-only property,
while
while
the
but it the
the
other
canother isis a read/write.
be changed
other
read/write.
is aa read/write.
The
internallyThe
from
The ideaideaisis is
ideathe
that
that
class in from
that from
from thethe outside
the outside
which it is
outside it
it is
defined, it isread-only
is aa and
a read-only property,
property,
the application
read-only property,
but it
is typical
but can
it can bea changed
canasbe
be changed internally
internally
private instance
changed fromthe
from
variable.
internally from theclass
the class
class in in
in which
which
which it isit defined,
it is is defined,
defined, andand
and the the application
the application
application
typical
typical as
isis typical as aaa private
as privateinstance
private instancevariable.
instance variable.
variable.
As an example, below is shown a class with two JavaFX properties:
As
As an
an example,
As an example, below
example, belowisisisshown
below shownaa aclass
shown classwith
class with
with two JavaFX
two
two properties:
JavaFX
JavaFX properties:
properties:
package fxproperties;
package fxproperties;
package fxproperties;
import javafx.beans.property.*;
import javafx.beans.property.*;
import javafx.beans.property.*;
public class Counter
public
{ class Counter
public class Counter
{ private IntegerProperty step = new SimpleIntegerProperty(1);
{
private
private IntegerProperty step = value
ReadOnlyIntegerWrapper new SimpleIntegerProperty(1);
= new ReadOnlyIntegerWrapper(0);
private IntegerProperty step = new SimpleIntegerProperty(1);
private ReadOnlyIntegerWrapper value = new ReadOnlyIntegerWrapper(0);
private ReadOnlyIntegerWrapper value = new ReadOnlyIntegerWrapper(0);
public final IntegerProperty stepProperty()
public final IntegerProperty stepProperty()
{
public final IntegerProperty stepProperty()
{ return step;
{
}return step;
return step;
}
}
public final int getStep()
public final int getStep()
{
public final int getStep()
{ return step.get();
{
}return step.get();
return step.get();
}
}

11
11
11
11
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

public final void setStep(int step)


{
this.step.set(step);
}

public final ReadOnlyIntegerProperty valueProperty()


{
return value.getReadOnlyProperty();
}

public final int getValue()


{
return value.get();
}

360°
public void increase()
{

.
value.set(value.get() + step.get());
}

thinking

360°
thinking . 360°
thinking .
Discover the truth at www.deloitte.ca/careers Dis

© Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers © Deloitte & Touche LLP and affiliated entities.

Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers


12
12
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

public void decrease()


public void decrease()
{
{
value.set(value.get() – step.get());
value.set(value.get() – step.get());
}
}

@Override
@Override
public String toString()
public String toString()
{
{
return "" + value.get();
return "" + value.get();
}
}
}
}

This is
This is an example
example of aa JavaFX
JavaFX bean. The
The two properties
properties are called
called step and
and value and
and are aa
This is an
an example of of a JavaFX bean.
bean. The two
two properties are
are called step
step and value
value and are
are a
read/write
read/write property and a read-only property. For both properties is defined a method that
read/write property
property and
and aa read-only
read-only property.
property. For
For both
both properties
properties isis defined
defined aa method
method that
that
returns
returns the value, for example:
returns the
the value,
value, for
for example:
example:
public final IntegerProperty stepProperty()
public final IntegerProperty stepProperty()
{
{
return step;
return step;
}
}

Here you
Here you should note
note the name name conventions, which which is the name
name followed by by the word
word
Here you should
should note thethe name conventions,
conventions, which isis the the name followed
followed by the
the word
property, and
property, and furthermore that that it is defined final.
final. Finally, there
there are defined
defined common get get
property, and furthermore
furthermore that itit isis defined
defined final. Finally,
Finally, there are
are defined common
common get
and set
and set methods (which
(which are also also defined final).
final). In principle,
principle, they are
are not necessary,
necessary, but it
it
and set methods
methods (which are are also defined
defined final). In In principle, they
they are not
not necessary, but
but it
is also
is also part of
of the convention,
convention, to be be in accordance
accordance with the the usual Java
Java beans convention.
convention.
is also part
part of the
the convention, to to be inin accordance withwith the usual
usual Java beans
beans convention.
You should
You should note that
that the methods
methods increase() and and decrease() perform
perform a set method
method on thethe
You should notenote that the
the methods increase()
increase() and decrease()
decrease() perform aa set
set method onon the
property value
property value – even ifif it is readonly. That’s
That’s okay, because
because it takes place
place internally in
in the
property value –– even
even if itit isis readonly.
readonly. That’s okay,
okay, because itit takes
takes place internally
internally in the
the
class Counter.
class Counter. Below
Below is
is aa method
method that that uses
uses the
the class:
class:
class Counter. Below is a method that uses the class:
private static void test02()
private static void test02()
{
{
Counter counter = new Counter();
Counter counter = new Counter();
System.out.printf("%d %s\n", counter.getValue(), counter);
System.out.printf("%d %s\n", counter.getValue(), counter);
for (int i = 0; i < 10; ++i) counter.increase();
for (int i = 0; i < 10; ++i) counter.increase();
System.out.printf("%d %s\n", counter.getValue(), counter);
System.out.printf("%d %s\n", counter.getValue(), counter);
counter.setStep(10);
counter.setStep(10);
for (int i = 0; i < 10; ++i) counter.increase();
for (int i = 0; i < 10; ++i) counter.increase();
System.out.printf("%d %s\n", counter.getValue(), counter);
System.out.printf("%d %s\n", counter.getValue(), counter);
// counter.valueProperty().setValue(10);
// counter.valueProperty().setValue(10);
}
}

There is
There is not much
much to note,
note, but you
you must note note the last
last statement, which
which is a comment,
There is not
not much toto note, but
but you must
must note thethe last statement,
statement, which isis aa comment,
comment,
and
and the statement can not actually be translated, since valueProperty() returns a read-only
and the
the statement
statement can
can not
not actually
actually be
be translated,
translated, since
since valueProperty()
valueProperty() returns
returns aa read-only
read-only
property
property and therefore does not have a set() method.
property and
and therefore
therefore does
does not
not have
have aa set()
set() method.
method.

13
13
13
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT JavaFX properties
JavaFX propertIes

A property
A property class
class encapsulates
encapsulates three
three values
values

1. aa reference
1. reference to
to the
the bean,
bean, that
that the
the property
property belongs
belongs to
to
2. aa name,
2. name, that
that is
is only
only aa String
String
3. aa value
3. value

and the
and the class
class has
has constructors,
constructors, so
so you
you can
can initialize
initialize these
these values
values as
as desired.
desired. For
For example,
example,
for the
for the class
class SimpleIntegerProperty:
SimpleIntegerProperty:

--- SimpleIntegerProperty()
SimpleIntegerProperty()
--- SimpleIntegerProperty(int value)
SimpleIntegerProperty(int value)
--- SimpleIntegerProperty(Object bean,
SimpleIntegerProperty(Object bean, String
String name)
name)
--- SimpleIntegerProperty(Object bean,
SimpleIntegerProperty(Object bean, String
String name,
name, int
int value)
value)

and aa property
and property has
has aa getBean()
getBean() and
and aa getName()
getName() method.
method. To
To show
show another
another example
example ofof the
the
pattern that
pattern that JavaFX
JavaFX uses
uses regarding
regarding properties,
properties, below
below is
is shown
shown aa class,
class, which
which is
is aa normal
normal bean:
bean:

package fxproperties;

import javafx.beans.property.*;

public class King


{
private ReadOnlyStringWrapper name = new ReadOnlyStringWrapper(this, "name");
private IntegerProperty from = new SimpleIntegerProperty(this, "from");
private IntegerProperty to = new SimpleIntegerProperty(this, "to", 9999);

public King()
{
}

public King(String name, int from, int to)


{
this.name.set(name);
this.from.set(from);
this.to.set(to);
}

public final String getName()


{
return name.get();
}

14
14
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

public final ReadOnlyStringProperty nameProperty()


{
return name.getReadOnlyProperty();
}

public final int getFrom()


{
return from.get();
}

public final void setFrom(int from)


{
this.from.set(from);
}

public final IntegerProperty fromProperty()


{
return from;
}

public final int getTo()


{
return to.get();
}

We will turn your CV into


an opportunity of a lifetime

Do you like cars? Would you like to be a part of a successful brand? Send us your CV on
We will appreciate and reward both your enthusiasm and talent. www.employerforlife.com
Send us your CV. You will be surprised where it can take you.

15
15
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

public final void setTo(int to)


public final void setTo(int to)
{{
this.to.set(to);
this.to.set(to);
}}

public final IntegerProperty toProperty()


public final IntegerProperty toProperty()
{{
return to;
to;
return
}
}
}
}

The class
The class has
has three
three properties,
properties, the
the first
first being
being aa read-only
read-only property,
property, while
while the
the others
others are are read/
read/
write properties.
write properties. You
You should
should note
note that
that in
in JavaFX,
JavaFX, properties
properties are
are not
not created
created as as primitive
primitive
types, but
types, but as
as Property
Property objects.
objects. You
You define
define get
get and
and set
set methods
methods in in the
the usual
usual way
way and and with
with
the same
the same names
names convention
convention for for what
what isis standard
standard for for Java
Java beans.
beans. You
You should
should note
note howhow these
these
methods refer
methods refer to
to the
the individual
individual properties,
properties, and and that
that they
they are
are defined
defined final.
final. It
It isis part
part ofof the
the
pattern that
pattern that JavaFX
JavaFX uses.
uses. For
For each
each property,
property, aa method
method isis also
also defined
defined that
that returns
returns the the actual
actual
property object,
property object, such
such as as fromProperty().
fromProperty(). It It isis also
also aa part
part of
of the
the pattern.
pattern. Finally,
Finally, youyou should
should
note that
note that name
name isis aa read-only
read-only property
property andand therefore
therefore hashas no
no set
set method.
method. Also
Also note
note thatthat the
the
method nameProperty()
method nameProperty() returns
returns aa ReadOnlyStringWrapper
ReadOnlyStringWrapper and and not
not aa StringProperty.
StringProperty.

That properties
That properties as
as illustrated
illustrated above
above are
are class
class types
types means
means that
that many
many objects
objects must
must be
be instantiated.
instantiated.
The reason
The reason that
that aa property
property isis defined
defined asas an
an object
object type
type isis aa number
number of of advanced
advanced features
features
that are
that are associated
associated with
with aa property
property (as(as fire
fire events
events and
and binding),
binding), but but often
often they
they are
are not
not used,
used,
and therefore
and therefore JavaFX
JavaFX uses
uses largely
largely lazy
lazy updating,
updating, where
where anan object
object isis first
first instantiated
instantiated when
when
needed. The
needed. The principle
principle cancan be
be illustrated
illustrated with
with the
the class
class King
King as as follows:
follows:

public class
class King
King
public
{
{
private static final String DK = "DK";
private static final String DK = "DK";
private StringProperty
StringProperty country;
country;
private
……

public String
String getCountry()
getCountry()
public
{{
return country == null ? DK : country.get();
return country == null ? DK : country.get();
}}

public void
void setCountry(String
setCountry(String country)
country)
public
{
{
if (country != null || !DK.equals(country)) countryProperty().set(country);
if (country != null || !DK.equals(country)) countryProperty().set(country);
}
}

16
16
16
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

public StringProperty
public StringProperty countryProperty()
countryProperty()
{{
if (country == null) country = new SimpleStringProperty(this, "country", DK);
if (country == null) country = new SimpleStringProperty(this, "country", DK);
return country;
return country;
}}
}
}

where the
where
where the class
the class now
class now has
now has an
has an additional
an additional property,
additional property, representing
property, representing the
representing the name
the name of
name of the
of the country
the country from
country from
from
where the
where
where the king
the king is
king isis from.
from. If
from. IfIf the
the vast
the vast majority
vast majority of
majority of kings
of kings come
kings come from
come from Denmark,
from Denmark, and
Denmark, and when
and when you
when you
you
only need
only
only need to
need to read
to read this
read this value,
this value, it
value, itit is
isis not
not appropriate
not appropriate (for
appropriate (for the
(for the sake
the sake of
sake of performance)
of performance) to
performance) to instantiate
to instantiate
instantiate
aaa Property
Property object
Property object for
object for each
for each King
each King object.
King object. Therefore,
object. Therefore, the
Therefore, the variable
the variable country
variable country from
country from the
from the start
the start is
start isis null
null
null
and an
and
and an object
an object is
object isis first
first instantiated
first instantiated if
instantiated ifif you
you try
you try to
try to change
to change the
change the value
the value to
value to something
to something else
something else than
else than DK
than DK
DK
oror if
or ifif you
you refer
you refer to
refer to the
to the property
the property with
property with countryProperty().
with countryProperty().
countryProperty().

The above
The
The above may
above may seem
may seem overwhelming,
seem overwhelming, but
overwhelming, but the
but the reason
the reason is
reason isis that
that properties
that properties in
properties in JavaFX
in JavaFX are
JavaFX are observable
are observable
observable
and may
and
and may be
may be associated
be associated with
associated with an
with an InvalidationListener
an InvalidationListener and
InvalidationListener and aaa ChangeListener
and ChangeListener <?
ChangeListener <? super
<? super T>.
super T>. The
T>. The
The
first interface
first
first interface defines
interface defines aaa method
defines method invalidated(),
method invalidated(), while
invalidated(), while the
while the other
the other defines
other defines aaa method
defines method changed().
method changed().
changed().
When the
When
When the value
the value of
value ofof aaa property
property changes
property changes from
changes from valid
from valid to
valid to invalid,
to invalid, an
invalid, an invalidation
an invalidation event
invalidation event is
event isis
generated. When
generated.
generated. When it
When itit does
does not
does not necessarily
not necessarily happens
necessarily happens every
happens every time
every time the
time the value
the value of
value of aaa property
of property changes
property changes
changes
(or otherwise
(or
(or otherwise becomes
otherwise becomes invalid),
becomes invalid), it
invalid), itit is
isis to
to avoid
to avoid generating
avoid generating aaa line
generating line of
line of invalidation
of invalidation events.
invalidation events. Change
events. Change
Change
events are,
events
events are, however,
are, however, generated
however, generated each
generated each time
each time the
time the value
the value of
value of aaa property
of property is
property isis changed.
changed. The
changed. The following
The following
following
method will
method
method will illustrate
will illustrate when
illustrate when these
when these events
these events occurs:
events occurs:
occurs:

private static
private static void
void test03()
test03()
{{
IntegerProperty pp == new
IntegerProperty new SimpleIntegerProperty(100);
SimpleIntegerProperty(100);
p.addListener(FXProperties::invalidated);
p.addListener(FXProperties::invalidated);
//
// p.addListener(FXProperties::changed);
p.addListener(FXProperties::changed);
System.out.println("Set to
System.out.println("Set to 101");
101");
p.set(101);
p.set(101);
System.out.println("Changed to
System.out.println("Changed to 101");
101");
System.out.println("Set to 102");
System.out.println("Set to 102");
p.set(102);
p.set(102);
System.out.println("Changed to
System.out.println("Changed to 102");
102");
System.out.println("Set to
System.out.println("Set to 102");
102");
p.set(102);
p.set(102);
System.out.println("Changed to
System.out.println("Changed to 103");
103");
System.out.println("Set to " + p.get());
System.out.println("Set to " + p.get());
p.set(103);
p.set(103);
System.out.println("Changed to
System.out.println("Changed to 103");
103");
}}

public static
public static void
void invalidated(Observable
invalidated(Observable p)
p)
{{
System.out.println("Property is
System.out.println("Property is invalid");
invalid");
}}

17
17
17
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15:
JAVA 15: MORE
SOFTWARE MORE ABOUT JAVAFX:
ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT JavaFX propertIes
JavaFX propertIes

public static void changed(ObservableValue<? extends Number> p,


public static void changed(ObservableValue<? extends Number> p,
Number oldValue, Number newValue)
Number oldValue, Number newValue)
{{
System.out.println("Property is
System.out.println("Property is changed");
changed");
}}

At
At the
the bottom, the event
bottom, the event handlers
handlers are
are defined
definedforforananinvalidation
invalidationevent
eventand
anda achange
changeevent,
event,
respectively. You must
respectively. You must note
note the
the parameters
parameters where
where thethefirst
firsthas
hasa areference
referencetotothe
theproperty
property
that
that has fired the
has fired the event
event in in question.
question. TheThe other
other has
hasaasimilar
similarreference
referencetotothe
theproperty,
property,and
and
also
also the
the old value and
old value and the
the value
value after
after the
thechange.
change.Note
Notethat
thatthe
thetype
typeofofthe
thevalue
valueisisNumber,
Number,
which
which is the base class
class for
for an
an Integer.
Integer. IfIf you
you performs
performsthethefunction
function(without
(withoutremoving
removingthethe
comment)
comment) the result
result is:

Set to
Set to 101
101
Property is
Property is invalid
invalid
Changed to
Changed to 101
101
Set to
Set to 102
102
Changed to
Changed to 102
102
Set to
Set to 102
102
Changed to
Changed to 102
102
Set to
Set to 103
103
Property is
Property is invalid
invalid
Changed to
Changed to 103
103

�e Graduate Programme
I joined MITAS because for Engineers and Geoscientists
I wanted real responsibili� www.discovermitas.com
Maersk.com/Mitas �e G
I joined MITAS because for Engine
I wanted real responsibili� Ma

Month 16
I was a construction Mo
supervisor ina const
I was
the North Sea super
advising and the No
Real work he
helping foremen advis
International
al opportunities
Internationa
�ree wo
work
or placements ssolve problems
Real work he
helping fo
International
Internationaal opportunities
�ree wo
work
or placements ssolve pr

18
18
18
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

and
and that
and that is,
that is, the
is, the event
the event handler
event handler invalidated()
invalidated() isis
handler invalidated() performed
is performed
performed twice. twice.
twice. TheThe function
The function creates
creates aaa
function creates
read/write
read/write IntegerProperty
read/write IntegerProperty
IntegerProperty withwith the
with the value
the value 100,
value 100, and
and isis
100, and then
is then valid.
then valid. Then
valid. Then
Then an an event
an event handler
event handler
handler
for
for invalidate
for invalidate events
invalidate events is added.
events isis added. When
added. When
When the the value
the value of
value of p changes
of pp changes
changes to to 101,
to 101, the
101, the property
the property becomes
property becomes
becomes
invalid
invalid and
invalid and
and an an invalidate
an invalidate event
invalidate event is triggered.
event isis triggered. When
triggered. When
When the the value
the value changes
value changes
changes to to 102,
to 102, an
102, an event
event isis
an event is
not
not fired
not fired because
fired because it is already
because itit isis already invalid.
already invalid. Then
invalid. Then the
Then the method
the method
method reads reads
reads thethe property
the property
property in in question
in question (in
question (in
(in
System.out.println()),
System.out.println()),
System.out.println()), which,which, among
which, among
among otherother things,
other things, means
things, means
means that that it becomes
that itit becomes valid.
becomes valid. When
When itit isis
valid. When it is
subsequently
subsequently
subsequently set set to
set to 102,
to 102,
102, no no invalidation
no invalidation event
invalidation event is fired,
event isis fired,
fired, asas the
as the value
the value is not
value isis not changed.
not changed. This
changed. This
This
happens
happens
happens whenwhen
when thethe value
the value changes
value changes
changes to to 103.
to 103.
103.

IfIf you
If you then
you then remove
then remove the
remove the comment
the comment
comment and and set
set aaa comment
and set comment
comment inin front
in front of
front of the
of the first
the first addListener(),
first addListener(),
addListener(),
instead,
instead, a ChangeListener
instead, aa ChangeListener is added,
ChangeListener isis added, and
added, and if you
and ifif you then
you then performs
then performs the
performs the method
the method
method youyou get
you get the
get the result:
the result:
result:

Set
Set to
to 101
101
Property
Property is
is changed
changed
Changed
Changed to
to 101
101
Set
Set to
to 102
102
Property
Property is
is changed
changed
Changed to 102
Changed to 102
Set
Set to
to 102
102
Changed
Changed to
to 102
102
Set
Set to
to 103
103
Property
Property is
is changed
changed
Changed
Changed to
to 103
103

Note
Note that
Note that aaa change
that change event
change event isis
event is performed
performed each
performed each time
each time the
time the value
the value changes,
value changes, but
changes, but not
but not when
not when the
when the value
the value
value
isis set
set to
to 102
102 the
the second
second time
time as
as the
the value
value is
is set to 102 the second time as the value is not changed.is not
not changed.
changed.

Another
Another difference
Another difference between
difference between invalidation
between invalidation events
invalidation events and
events and change
and change events
change events isis
events is that
that JavaFX
that JavaFX for
JavaFX for
for
invalidation
invalidation events
events uses
uses lazy
lazy evaluation,
evaluation, while
while change
change events
events use
use eager
eager evaluation
evaluation
invalidation events uses lazy evaluation, while change events use eager evaluation as a valueas
as aa value
value
must
must be
must be transferred
be transferred to
transferred to the
to the event
the event handler.
event handler.
handler.

To
To some
To some extent,
some extent, one
extent, one can
one can achieve
can achieve the
achieve the same
the same with
same with an
with an invalidation
an invalidation event
invalidation event and
event and aaa change
and change event,
change event,
event,
but
but an invalidation event is slightly more effective as it is not necessarily fired whenever the
but an
an invalidation
invalidation event
event is
is slightly
slightly more
more effective
effective as
as it
it is
is not
not necessarily
necessarily fired
fired whenever
whenever the
the
value
value changes
changes and
and as
as it
it does
does not
not necessarily
necessarily update
update the
the value.
value.
value changes and as it does not necessarily update the value. If you want to choose which If
If you
you want
want to
to choose
choose which
which
event
event you
event you should
you should listen
should listen to,
listen to, the
to, the main
the main rule
main rule isis
rule is that
that ifif
that if you
you do
you do not
do not read
not read the
read the value
the value in
value in the
in the event
the event
event
handler,
handler, you
you should
should listen
listen to
to invalidation
invalidation events,
events, but
but if
if you
handler, you should listen to invalidation events, but if you read the value, you shouldyou read
read the
the value,
value, you
you should
should
instead
instead listen
instead listen to
listen to aaa change
to change event
change event as
event as itit
as it automatically
automatically updates
automatically updates the
updates the value
the value (and
value (and thus
(and thus validates
thus validates
validates
the
the property).
property). You
You can
can see
see the
the effect
effect if
if you
you in
in the
the above
above program
program
the property). You can see the effect if you in the above program removes both comments: removes
removes both
both comments:
comments:

Set
Set to
to 101
101
Property
Property is
is invalid
invalid
Property
Property is changed
is changed
Changed
Changed to
to 101
101

19
19
19
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
JAVA 15: MORE ABOUT JAVAFX: JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes
Set to 102
Property
Set to 102is invalid
Set to 102
Property is invalid
Property is changed
Property is invalid
Changed to
Property is 102
changed
Property is changed
Set to 102
Changed to 102
Changed to 102
Changed
Set to 102
to 102
Set to 102
Set to 103
Changed to 102
Changed to 102
Set to 103is invalid
Property
Set to 103
Property is
Property is invalid
changed
Property is invalid
Changed to 103
Property is changed
Property is changed
Changed to 103
Changed to 103
The result is that an invalidation event is firing every time the value changes.
The result is that an invalidation event is firing every time the value changes.
The result
The result is
is that
that an
an invalidation
invalidation event
event is
is firing
firing every
every time
time the
the value
value changes.
changes.

2.1 BINDING PROPERTIES


2.1
2.1 BINDING
BINDING PROPERTIES
PROPERTIES
2.1
JavaFXBINDING PROPERTIES
supports binding of properties where a property of a component or node can bind
JavaFX
JavaFX supports
to a property
supports binding
on binding
another of
binding ofproperties
properties
object.
of where
In general,
where itaa isa property
relatively
property of a component
of simple to use, or orinnode
butnode fact, can
bindbind
can many
JavaFX supports properties where property of aa component
component or node can bind
to
to aa property
details
property on another
are assigned
on another object.
to theobject. InIngeneral,
concept,
object. general,itthe
however,
general, itis is relatively
classes
relatively simple
insimple
JavaFX
simple tohidden
toare
use,use,
but but
inthe inmost.
fact,fact,
manymany
In
to a property on another In it is relatively to use, but in fact, many
details
details are assigned
the following,
are assigned
assigned totoillustrate
I willto theconcept,
the concept, however,
with however,
some thethe
simple
however, classes
examples
classes in
in what JavaFX
JavaFX are are
binding ishidden
hidden the the
about. most.
In In
Consider
most.
details are the concept, the classes in JavaFX are hidden the most. In
the
thefollowing,
the I will
will illustrate
following method:
following, illustratewith
withsome
somesimple
simpleexamples examples what binding is about. Consider
the following, II will illustrate with some simple examples what what binding
binding is about.
is about. Consider
Consider
the
the following
the method:
following method:
following method:
private static void test04()
{
private static void test04()
private static void test04()
{ IntegerProperty x = new SimpleIntegerProperty(3);
{
IntegerProperty xy == new
IntegerProperty new SimpleIntegerProperty(3);
SimpleIntegerProperty(5);
IntegerProperty x = new SimpleIntegerProperty(3);
IntegerProperty z = new SimpleIntegerProperty(7);
IntegerProperty y = new SimpleIntegerProperty(5);
IntegerProperty y = new SimpleIntegerProperty(5);
z.bind(x.add(y));
IntegerProperty z = new SimpleIntegerProperty(7);
IntegerProperty z = new SimpleIntegerProperty(7);
System.out.println("Bound = " + z.isBound() + ", z
z.bind(x.add(y)); = " + z.get());
z.bind(x.add(y));
x.set(11);
System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
y.set(13);
x.set(11);
x.set(11);
System.out.println("Bound = " + z.isBound() + ", z
y.set(13); = " + z.get());
y.set(13);
z.unbind();
System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
x.set(17);
z.unbind();
z.unbind();
y.set(19);
x.set(17);
x.set(17);
System.out.println("Bound = " + z.isBound() + ", z
y.set(19); = " + z.get());
y.set(19);
}System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
System.out.println("Bound = " + z.isBound() + ", z = " + z.get());
}
}
The method defines three properties of the type IntegerProperty initialized with values 3, 5
The
and method
The
The method
method defines three
defines
defines threeproperties
7. An IntegerProperty
three properties
has an add()
properties ofofmethod
of the
thethetype
type
type that IntegerProperty
IntegerProperty
IntegerProperty initialized
performs aninitialized
addition
initialized with
with with
of values values
values
valuesof3, 5 3, 5
3,two
5
properties
and
and
and 7. An
7.
7. and returns a binding
IntegerProperty
IntegerProperty
An IntegerProperty has an
hasan
has of
add()
anadd()themethod
add() sum ofthat
method
method the
thatthat two properties
performs
performs
performs an an
an which
addition of
addition
addition ofis values
an
of expression
values of two
values
of twoof two
of the typeand
properties
properties
properties NumberBinding,
and returns
returns representing
returns aaa binding
binding
binding ofofthe
of the sum
thesum the
sumofsum
of oftwo
thethe
ofthe the
twotwovalues of the
properties which
properties
properties whichtwo isproperties.
which
is This
anis expression
an expression
an expression
binding
of
of
of the type
the
the is then
type
type linked to therepresenting
NumberBinding,
NumberBinding,
NumberBinding, property z.the
representing
representing The
the next
sum
thesumsum ofstatement
of thethe
of
the valueswill
values
values of print
of the
the
of twotwo
the
two properties. This This
properties.
properties. This
binding is
binding
binding is then
then linked
then linked to
linked to the
tothe property
theproperty
propertyz.z.z.The
The next
Thenext
next statement
statement
statement willwill
will print
print
print
Bound = true, z = 8
Bound = true, z = 8
Bound = true, z = 8

20

20
20
20
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

which
which states
states that
that the
the variable
variable zz isis bound,
bound, and
and that
that its
its value
value isis 88 and
and hence
hence the
the sum
sum ofof xx and
and
y.y. That
That is,
is, the
the value
value ofof zz has
has been
been changed.
changed. Next,
Next, the
the two
two properties
properties xx and
and yy are
are changed,
changed,
and
and thethe next
next statement
statement prints
prints

Bound = true, z = 24

That
That is,
is, changes
changes of
of the
the two
two properties
properties xx and
and yy automatically
automatically update
update z,
z, which
which exactly
exactly isis what
what
binding
binding isis about.
about. The
The next
next statement
statement again
again removes
removes the
the binding
binding of
of z,z, after
after which
which xx andand yy
are
are changed
changed again.
again. The
The last
last statement
statement will
will then
then print
print

Bound = false, z = 24

which
which partly
partly shows
shows that
that zz isis no
no longer
longer bound
bound and
and its
its value
value has
has not
not changed
changed since
since itit isis no
no
longer
longer linked
linked to
to the
the two
two properties
properties xx and
and y.y.

AA binding
binding isis thus
thus an
an expression
expression thatthat isis evaluated
evaluated to
to aa value.
value. The
The expression
expression consists
consists of
of one
one
or
or more
more observable
observable values,
values, known
known as as dependencies.
dependencies. TheThe binding
binding observes
observes changes
changes of
of its
its
dependencies
dependencies and and its
its value
value isis automatically
automatically updated
updated when
when itsits dependencies
dependencies change
change values.
values.
All
All property
property classes
classes in
in JavaFX
JavaFX havehave built-in
built-in support
support for
for binding.
binding. There
There areare two
two forms
forms
of
of binding:
binding: Unidirectional
Unidirectional binding
binding andand bidirectional
bidirectional binding.
binding. TheThe above
above isis an
an example
example ofof

21
21
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
JAVA 15: MORE ABOUT JAVAFX: JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

unidirectional binding, which is defined by the method bind(). There are several limitations
unidirectional
to binding,
unidirectional whichand
bindings, is defined
you canbynot,
the method bind().directly
for example, There are severalthe
change limitations
value of the
to unidirectional bindings, and you can not, for example, directly change the value of the
property that is bound. You can not directly change the value of z above. In addition, a
property that is bound. You can not directly change the value of z above. In addition, a
property can only be bound to one expression with unidirectional bindings, and trying to
property can only be bound to one expression with unidirectional bindings, and trying to
bind it again, overrides the first binding.
bind it again, overrides the first binding.

A binding can also be bidirectional, which means that you can also change the value of the
A binding can also be bidirectional, which means that you can also change the value of the
property that is bound. Obviously, a binding like the above can not be bidirectional, for
property that is bound. Obviously, a binding like the above can not be bidirectional, for
changing z, there
changing z, there isisnonoway
waytotoautomatically
automatically update
update thethe values
values of xofand
x and y. For
y. For a binding
a binding to to
be
be bidirectional,
bidirectional, itit must
mustbebebetween
betweenproperties
properties of of
thethe same
same type,
type, butbut in return,
in return, a property
a property
may
may be bound to
be bound to several
severalother
otherproperties.
properties.The
The following
following method
method shows
shows the the principles
principles of of
bidirectional binding:
bidirectional binding:

private static void test05()


{
IntegerProperty x = new SimpleIntegerProperty(3);
IntegerProperty y = new SimpleIntegerProperty(5);
IntegerProperty z = new SimpleIntegerProperty(7);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
x.bindBidirectional(y);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
x.bindBidirectional(z);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
z.set(11);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
x.unbindBidirectional(y);
x.unbindBidirectional(z);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
x.set(13);
y.set(17);
z.set(19);
System.out.println("x = " + x.get() + ", y = " + y.get() + ", z = " + z.get());
}

Three
Three properties arecreated
properties are createdagain,
again,and andthe
the first
first println()
println() displays
displays thethe values
values of these
of these properties
properties
before they
before they are
are bound.
bound.Next, Next,x xisisbound
boundtotoy andy and thethe
next println()
next statement
println() statementshows that that
shows x x
now has
now has the
the same
same value
valueasasy.y.Then
Thenx xis isbound
bound to to
z, z,
which
whichmeans thatthat
means x has the the
x has samesame
valuevalue
as z,
as z, and
and since
since xx isis bound
boundtotoy yand andsince
sincethethebinding
binding is bidirectional,
is bidirectional,the the
valuevalue
of y of
also
y also
becomes the value of x. The next println() statement shows that the
becomes the value of x. The next println() statement shows that the three properties now three properties now
all have
all have the
the same
same value.
value.Now,
Now,the thevalue
valueofofz changes
z changes to to
11,11,
andand
whenwhenthe the
threethree
properties
properties
are printed again, they all have the value 11. Then the bindings are removed and three
are printed again, they all have the value 11. Then the bindings are removed and the the three
properties are printed again, and you can see that they still have the value 11. Finally, the
properties are printed again, and you can see that they still have the value 11. Finally, the
values of the three properties are changed, after which they are printed and the new values
values of the three properties are changed, after which they are printed and the new values
are shown:
are shown:

22

22
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
JAVA 15: MORE ABOUT JAVAFX: JavaFX properties
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

x = 3, y = 5, z = 7
x = 3, y = 5, z = 7
x = 5, y = 5, z = 7
x = 5, y = 5, z = 7
x = 7, y = 7, z = 7
x = 7, y = 7, z = 7
x = 11, y = 11, z = 11
x = 11, y = 11, z = 11
x = 11, y = 11, z = 11
x = 11, y = 11, z = 11
x = 13, y = 17, z = 19
x = 13, y = 17, z = 19

In JavaFX, all read/write properties support bidirectional binding, and as an example of


InIn JavaFX,
JavaFX, all
all read/write
read/write properties
properties support
support bidirectional
bidirectional binding,
binding, and
and as
as an example of
how it can be used, consider the following class:
how
howititcan
canbebeused,
used, consider
consider the
the following
following class:
class:

package fxproperties;
package fxproperties;

import javafx.application.Application;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.*;
import javafx.scene.paint.*;
import javafx.scene.paint.*;
import javafx.stage.Stage;
import javafx.stage.Stage;
import javafx.scene.shape.*;
import javafx.scene.shape.*;
import javafx.beans.binding.*;
import javafx.beans.binding.*;

public class CircleView extends Application


public class CircleView extends Application
{
{
@Override
@Override
public void
public void start(Stage
start(Stage primaryStage)
primaryStage)
{
{
Circle c
Circle c =
= new
new Circle();
Circle();
c.setFill(Color.RED);
c.setFill(Color.RED);
Group root
Group root == new
new Group(c);
Group(c);
Scene scene = new Scene(root, 200,
Scene scene = new Scene(root, 200, 200);
200);
c.centerXProperty().bind(scene.widthProperty().divide(2));
c.centerXProperty().bind(scene.widthProperty().divide(2));
c.centerYProperty().bind(scene.heightProperty().divide(2));
c.centerYProperty().bind(scene.heightProperty().divide(2));
c.radiusProperty().bind(Bindings.min(scene.widthProperty(),
c.radiusProperty().bind(Bindings.min(scene.widthProperty(),
scene.heightProperty()).divide(2));
scene.heightProperty()).divide(2));
primaryStage.setTitle("Binding");
primaryStage.setTitle("Binding");
primaryStage.setScene(scene);
primaryStage.setScene(scene);
primaryStage.show();
primaryStage.show();
}
}
}
}

Note that it is a JavaFX


JavaFX window
window (inherits
(inherits thethe class
class Application)
Application) and
and there
there isis only
only aastart()
start()
Note that it is a JavaFX window (inherits the class Application) and there is only a start()
method. Here a red circle
circle isis inserted
inserted as
as aa node
node in
in aa scene
scene graph.
graph. Next,
Next, three
threeproperties
propertiesareare
method. Here a red circle is inserted as a node in a scene graph. Next, three properties are
circle’s center
bound, that are the circle’s center and
and radius,
radius, to to the
the width
width and
and height
height of
of the
the scene
sceneobject
object
bound, that are the circle’s center and radius, to the width and height of the scene object
center becomes
so that the circle’s center becomes the the center
center of of the
the window
window while
while the
the radius
radius becomes
becomesthe the
so that the circle’s center becomes the center of the window while the radius becomes the
the entire
largest possible so that the entire circle
circle isis displayed.
displayed. TheThe window
window will
will thus
thus show
showaacircle:
circle:
largest possible so that the entire circle is displayed. The window will thus show a circle:

23
23
23
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

and
and change
change the
the size
size of
of the
the window,
window, you
you will
will see
see that
that the
the circle
circle follows
follows the
the window
window asas itit always
always
sits
sits in
in the
the middle
middle of of the
the window,
window, and
and the
the radius
radius changes
changes depending
depending on on the
the window
window size. size.

You
You should
should also
also note
note how
how to
to open
open the
the window
window from
from the
the main
main program:
program:

private static void test06()


{
Application.launch(CircleView.class);
}

In the past 5 years we have drilled around

95,000 km
—that’s more than twice around the world.

Who are we?


We are the world’s leading provider of reservoir characterization,
drilling, production, and processing technologies to the oil and
gas industry.

Who are we looking for?


We offer countless opportunities in the following domains:
n Operations
n Research, Engineering, and Manufacturing
n Geoscience and Petrotechnical
n Commercial and Business

We’re looking for high-energy, self-motivated graduates


with vision and integrity to join our team. What will you be?

careers.slb.com

24
24
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT JavaFX properties
JavaFX propertIes

As another example, the method test07() opens the following window:

which includes a Slider, a Label and three Button controls. Here, the Slider component is
bound to the property step in the class Counter with a bidirectional binding while the Label
component is bound to the property value in the class Counter with a unidirectional binding:

public class CounterView extends Application


{
private Counter counter = new Counter();

@Override
public void start(Stage primaryStage)
{
Slider slider = new Slider(1, 10, 1);
Label label = new Label("");
label.setFont(Font.font("Arial", FontWeight.BOLD, FontPosture.REGULAR, 48));
Button cmd1 = new Button("Reset");
cmd1.setOnAction(e -> counter.setStep(1));
Button cmd2 = new Button("Down");
cmd2.setOnAction(e -> counter.decrease());
Button cmd3 = new Button("Up");
cmd3.setOnAction(e -> counter.increase());
HBox commands = new HBox(10, cmd1, cmd2, cmd3);
commands.setAlignment(Pos.CENTER);
VBox root = new VBox(20, slider, label, commands);
root.setAlignment(Pos.TOP_CENTER);
root.setPadding(new Insets(30, 30, 30, 30));
Scene scene = new Scene(root, 300, 200);
label.textProperty().bind(counter.valueProperty().asString());
slider.valueProperty().bindBidirectional(counter.stepProperty());
primaryStage.setTitle("Binding");
primaryStage.setScene(scene);
primaryStage.show();
}
}

25
25
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

AA Label
Label control
control has has aa StringProperty
StringProperty property
property textProperty,
textProperty, and and aa Counter
Counter has has aa property
property
valueProperty
valueProperty of of the
the type
type ReadOnlyIntegerWrapper.
ReadOnlyIntegerWrapper. Since Since the
the latter
latter isis read-only,
read-only, youyou can
can not
not of
of
course
course create
create aa bidirectional
bidirectional binding,
binding, but but aa ReadOnlyIntegerWrapper
ReadOnlyIntegerWrapper has has an
an asString()
asString() method,
method,
which
which returns a StringBinding object, and allows it to create a unidirectional binding. The
returns a StringBinding object, and allows it to create a unidirectional binding. The
result
result isis that
that ifif the
the property
property value
value in in the
the Counter
Counter object
object changes
changes (clicking
(clicking thethe Down
Down andand
Up
Up buttons),
buttons), then then the the Label
Label object
object will
will automatically
automatically be be updated.
updated. AA SliderSlider control
control has
has aa
valueProperty
valueProperty of of thethe type
type IntegerProperty,
IntegerProperty, and and the
the same
same applies
applies to to thethe class
class Counter,
Counter, which
which
has a stepProperty of the same type. You can therefore create a bidirectional
has a stepProperty of the same type. You can therefore create a bidirectional binding between binding between
these
these two
two properties.
properties. The The result
result isis that
that ifif you
you change
change the the slider,
slider, thethe Counter
Counter object’s
object’s step
step
property
property isis updated.
updated. IfIf you you click
click the
the Reset
Reset button,
button, itit sets
sets the
the value
value of of step
step to
to 1,
1, and
and since
since
the
the slider
slider binding
binding isis bidirectional,
bidirectional, thethe slider
slider component
component isis automatically
automatically updated.
updated.

EXERCISE
EXERCISE 11
You
You must
must write
write an
an application
application that
that opens
opens the
the following
following window:
window:

where
where you
you can
can maintain
maintain information
information about
about aa person.
person. The
The displayed
displayed name
name and
and job
job title
title are
are
default
default values.
values. IfIf you
you click
click on
on the
the last
last button,
button, you
you must
must get
get an
an alert
alert that
that shows
shows the
the person’s
person’s
name
name and
and job
job title,
title, and
and clicking
clicking on
on the
the first
first button,
button, the
the values
values must
must be be changed
changed to to default.
default.

The
The program
program must
must use
use the
the following
following model
model class:
class:

package editperson;

import javafx.beans.property.*;

public class Person


{
private StringProperty name = new SimpleStringProperty("Gorm den Gamle");
private StringProperty job = new SimpleStringProperty("King");

26
26
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

public String getName()


{
return name.get();
}

public void setName(String name)


{
this.name.set(name);
}

public StringProperty nameProperty()


{
return name;
}

public String getJob()


{
return job.get();
}

27
27
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15:
JAVA 15: MORE
SOFTWARE MORE ABOUT JAVAFX:
ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT JavaFX propertIes
JavaFX propertIes

public void
public void setJob(String
setJob(String job)
job)
{
{
this.job.set(job);
this.job.set(job);
}
}

public StringProperty
public StringProperty jobProperty()
jobProperty()
{{
return job;
return job;
}}
}}

and
and the
the two
two input
input fields
fields must
must be
be bound
bound to to the
the model
model with
with bidirectional
bidirectional bindings.
bindings. When
When
you
you click
click the
the Default
Default button,
button, the
the default
default values
values must
must be
be set
set by
by directly
directly updating
updating the
the model,
model,
thus
thus performing
performing the
the setName()
setName() and
and setJob()
setJob() methods.
methods.

2.2
2.2 OBSERVABLE COLLECTIONS
JavaFX
JavaFX defines
defines multiple
multiple collections,
collections, which
which are
are extensions
extensions of
of the
the classic
classic collection
collection classes.
classes.
There
There are
are three
three interfaces
interfaces defined
defined

--- ObervableList<T>
ObervableList<T>
--- ObervableSet<T>
ObervableSet<T>
--- ObervableMap<K,V>
ObervableMap<K,V>

which
which inherits
inherits List<T>,
List<T>, Set<T>
Set<T> and
and Map<K,
Map<K, V> V> respectively,
respectively, but
but also
also inherits
inherits the
the interface
interface
Observable.
Observable. JavaFX
JavaFX does
does not
not immediately
immediately have
have classes
classes that
that implements
implements those
those interfaces,
interfaces, but
but
instead,
instead, there
there is
is aa class
class of
of FXCollections
FXCollections that
that has
has static
static methods
methods that
that return
return objects
objects that
that
implement
implement these
these interfaces.
interfaces. Viewed
Viewed from
from the
the programmer,
programmer, an an observable
observable colletion
colletion is
is aa list,
list,
aa set
set or
or aa map
map that
that can
can be
be observed
observed for
for invalidation
invalidation and
and changes
changes of
of the
the content.
content.

Consider
Consider the
the following
following example:
example:

private static
private static void
void test08()
test08()
{{
ObservableList<String> list =
ObservableList<String> list =
FXCollections.observableArrayList("Gorm den Gamle", "Harald Blåtand");
FXCollections.observableArrayList("Gorm den Gamle", "Harald Blåtand");
list.addListener(FXProperties::onChanged);
list.addListener(FXProperties::onChanged);
list.addAll("Svend Tveskæg", "Harald d. 2.");
list.addAll("Svend Tveskæg", "Harald d. 2.");
list.add("Knud d.
list.add("Knud d. Store");
Store");
list.remove(3);
list.remove(3);
show(list);
show(list);
java.util.Collections.sort(list);
java.util.Collections.sort(list);
show(list);
show(list);
}}

28
28
28
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

private static void show(java.util.List<String> list)


{
System.out.println();
for (String name : list) System.out.println(name);
}

private static void onChanged(ListChangeListener.


Change<? extends String> change)
{
System.out.println("List has changed");
}

IfIf the
the method
method isis performed
performed the
the result
result is:
is:

List has changed


List has changed
List has changed

Gorm den Gamle


Harald Blåtand
Svend Tveskæg
Knud d. Store
List has changed

Gorm den Gamle


Harald Blåtand
Knud d. Store
Svend Tveskæg

The
The list
list isis created
created with
with two
two elements,
elements, andand then
then aa ChangeListener
ChangeListener isis associated
associated that
that do do nothing
nothing
but
but prints
prints aa message
message onon the
the console.
console. TheThe first
first event
event occurs
occurs after
after additional
additional twotwo items
items have
have
been
been added
added and and the
the next
next after
after another
another element
element isis added.
added. Finally,
Finally, the the third
third occurs
occurs afterafter an
an
item
item has has beenbeen deleted.
deleted. TheThe method
method show()
show() shows
shows the
the content
content of of the
the list
list on
on the the console
console
and
and thenthen readsreads the
the list.
list. Note
Note that
that the
the parameter
parameter isis aa List<String>
List<String> which which isis ok, ok, since
since an
an
ObservableList<String>
ObservableList<String> isis speciallyspecially aa List<String>.
List<String>. After
After the
the list
list isis printed,
printed, itit isis sorted,
sorted, and
and
as
as itit means
means that that the
the order
order of
of the
the list’s
list’s elements
elements changes,
changes, another
another ChangeEvent
ChangeEvent occurs.occurs.

The
The class
class ListChangeListener.Change
ListChangeListener.Change has has aa variety
variety of
of different
different methods
methods that
that tells
tells you
you about
about
the
the reason
reason for
for the
the event
event and
and you
you are
are encouraged
encouraged to to investigate
investigate which
which ones.
ones. The
The following
following
example
example should
should show
show aa little
little bit
bit about
about how
how these
these methods
methods can can be
be used.
used. First,
First, I’ve
I’ve added
added aa
simple
simple model
model class
class with
with two
two properties
properties that
that adhere
adhere toto the
the JavaFX
JavaFX beans
beans pattern:
pattern:

package fxproperties;

29
29
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

import javafx.beans.property.*;

public class Person implements Comparable<Person>


{
private StringProperty name = new SimpleStringProperty();
private StringProperty job = new SimpleStringProperty();

public Person(String name, String job)


{
setName(name);
setJob(job);
}

public final String getName()


{
return name.get();
}

public final void setName(String name)


{
this.name.set(name);
}

Excellent Economics and Business programmes at:

“The perfect start


of a successful,
international career.”

CLICK HERE
to discover why both socially
and academically the University
of Groningen is one of the best
places for a student to be
www.rug.nl/feb/education

30
30
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE
SOFTWARE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

public StringProperty nameProperty()


public StringProperty nameProperty()
{
{
return name;
return name;
}
}

public final String getJob()


public final String getJob()
{
{
return job.get();
return job.get();
}
}

public final void setJob(String job)


public final void setJob(String job)
{
{
this.job.set(job);
this.job.set(job);
}
}

public StringProperty jobProperty()


public StringProperty jobProperty()
{
{
return job;
return job;
}
}

@Override
@Override
public int compareTo(Person p)
public int compareTo(Person p)
{
{
int val = getName().compareTo(p.getName());
int val = getName().compareTo(p.getName());
if (val == 0) val = this.getJob().compareTo(p.getJob());
if (val == 0) val = this.getJob().compareTo(p.getJob());
return val;
return val;
}
}

@Override
@Override
public String toString()
public String toString()
{
{
return getName() + ": " + getJob();
return getName() + ": " + getJob();
}
}
}
}

and
and in
in relation
relation to
to what
what has
has been
been said
said before,
before, there
there isis nothing
nothing new.
new. Note,
Note, however,
however, that
that the
the
and in relation to what has been said before, there is nothing new. Note, however, that the
class’s
class’s objects
objects are
are comparable
comparable and
and can
can thus
thus be
be sorted.
sorted. II have
have then
then defined
defined aa listener
listener class
class
class’s objects are comparable and can thus be sorted. I have then defined a listener class
for
for change
change events
events for
for an
an ObservableList
ObservableList collection
collection with
with Person
Person objects:
objects:
for change events for an ObservableList collection with Person objects:
package fxproperties;
package fxproperties;

import javafx.collections.ListChangeListener;
import javafx.collections.ListChangeListener;

public class PersonChangeListener implements ListChangeListener<Person>


public class PersonChangeListener implements ListChangeListener<Person>
{
{
@Override
@Override
public void onChanged(ListChangeListener.Change<? extends Person> change)
public void onChanged(ListChangeListener.Change<? extends Person> change)
{
{

31
31
31
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

while
while (change.next())
(change.next())
{
{
if
if (change.wasPermutated())
(change.wasPermutated()) permutated(change);
permutated(change);
else if (change.wasUpdated()) updated(change);
else if (change.wasUpdated()) updated(change);
else
else if
if (change.wasReplaced())
(change.wasReplaced()) replaced(change);
replaced(change);
else if (change.wasRemoved()) removed(change);
else if (change.wasRemoved()) removed(change);
else
else if
if (change.wasAdded())
(change.wasAdded()) added(change);
added(change);
}
}
}
}

private void permutated(ListChangeListener.Change<? extends Person> change)


private void permutated(ListChangeListener.Change<? extends Person> change)
{
{

System.out.println("Sort: " + change.getFrom() + " – "+ change.getTo());
System.out.println("Sort: " + change.getFrom() + " – "+ change.getTo());
}
}

private void updated(ListChangeListener.Change<? extends Person> change)


private void updated(ListChangeListener.Change<? extends Person> change)
{
{

System.out.println("Updated: " +
System.out.println("Updated: " +

change.getList().subList(change.getFrom(), change.getTo()));
change.getList().subList(change.getFrom(), change.getTo()));
}
}

private void replaced(ListChangeListener.Change<? extends Person> change)


private void replaced(ListChangeListener.Change<? extends Person> change)
{
{
removed(change);
removed(change);
added(change);
added(change);
}
}

private void removed(ListChangeListener.Change<? extends Person> change)


private void removed(ListChangeListener.Change<? extends Person> change)
{
{
System.out.println("Removed "
System.out.println("Removed " +
+ change.getRemovedSize()
change.getRemovedSize() +
+ "
" person(s):
person(s): "
"
+
+
change.getRemoved());
change.getRemoved());
}
}

private void added(ListChangeListener.Change<? extends Person> change)


private void added(ListChangeListener.Change<? extends Person> change)
{
{
System.out.println("Added "
System.out.println("Added " +
+ change.getAddedSize()
change.getAddedSize() +
+ "
" person(s):
person(s): "
" +
+
change.getAddedSubList());
change.getAddedSubList());
}
}
}
}

A single event handler must be implemented with the name onChanged(), whose parameter
A single event handler must be implemented with the name onChanged(), whose parameter
is a
is a

ListChangeListener.Change<? extends Person>


ListChangeListener.Change<? extends Person>

32
32
32
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

object
object named
named change.
change. When
When an an event
event occurs
occurs andand the
the method
method isis called,
called, the
the event
event may
may be be
triggered
triggered by
by one
one oror more
more changes
changes to to the
the list,
list, and
and therefore,
therefore, the
the method
method starts
starts with
with aa loop
loop
that
that iterates
iterates over
over these
these changes.
changes. AsAs shown
shown by by the
the method,
method, there
there may
may bebe 55 different
different types
types
of
of changes,
changes, and
and each
each iteration
iteration ofof the
the loop
loop calls
calls aa method
method corresponding
corresponding to to the
the change
change inin
question.
question. InIn this
this case,
case, the
the methods
methods are are all
all trivial
trivial and
and do
do nothing
nothing but
but print
print aa text
text on
on the
the
screen,
screen, and
and the
the purpose
purpose isis to
to show
show only
only when
when the the event
event occurs.
occurs.

With
With the
the above
above two
two classes
classes available,
available, you
you can
can perform
perform the
the following
following method:
method:

private static void test09()


{
Person p1 = new Person("Gudrun Jensen", "Heks");
Person p2 = new Person("Carlo Andersen", "Skarpretter");
Person p3 = new Person("Valborg Kristensen", "Spåkone");
Person p4 = new Person("Egon Knudsen", "Kriger");
Person p5 = new Person("Abelone Jensen", "Sin mands kone");
Person p6 = new Person("Viktor Hansen", "Høvding");
Callback<Person, Observable[]> cb =
(Person p) -> new Observable[] { p.nameProperty(), p.jobProperty() };
ObservableList<Person> list = FXCollections.observableArrayList(cb);
list.addListener(new PersonChangeListener());
System.out.println(list);

American online
LIGS University
is currently enrolling in the
Interactive Online BBA, MBA, MSc,
DBA and PhD programs:

▶▶ enroll by September 30th, 2014 and


▶▶ save up to 16% on the tuition!
▶▶ pay in 10 installments / 2 years
▶▶ Interactive Online education
▶▶ visit www.ligsuniversity.com to
find out more!

Note: LIGS University is not accredited by any


nationally recognized accrediting agency listed
by the US Secretary of Education.
More info here.

33
33
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
SOFTWARE MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX propertIes
propertIes

list.add(p1);
list.add(p1);
System.out.println(list);
System.out.println(list);
list.addAll(p2,
list.addAll(p2, p3);
p3);
System.out.println(list);
System.out.println(list);
FXCollections.sort(list);
FXCollections.sort(list);
System.out.println(list);
System.out.println(list);
p1.setName("Gunhild Mikkelsen");
p1.setName("Gunhild Mikkelsen");
p2.setJob("Natmand");
p2.setJob("Natmand");
list.set(0,
list.set(0, new
new Person("Olga
Person("Olga Hansen",
Hansen", "Sypige"));
"Sypige"));
System.out.println(list);
System.out.println(list);
list.setAll(p4,
list.setAll(p4, p5,
p5, p6);
p6);
System.out.println(list);
System.out.println(list);
list.removeAll(p4,
list.removeAll(p4, p6);
p6);
System.out.println(list);
System.out.println(list);
}}

Performing
Performing the
the method
method gives
gives you
you the
the result:
result:

[]
[]
Added
Added 11 person(s):
person(s): [Gudrun
[Gudrun Jensen:
Jensen: Heks]
Heks]
[Gudrun
[Gudrun Jensen:
Jensen: Heks]
Heks]
Added 2 person(s): [Carlo Andersen: Skarpretter, Valborg Kristensen: Spåkone]
Added 2 person(s): [Carlo Andersen: Skarpretter, Valborg Kristensen: Spåkone]
[Gudrun Jensen: Heks, Carlo Andersen: Skarpretter, Valborg Kristensen: Spåkone]
Sort: 0 – 3
[Carlo Andersen: Skarpretter, Gudrun Jensen: Heks, Valborg Kristensen: Spåkone]
Updated: [Gunhild Mikkelsen: Heks]
Updated: [Carlo Andersen: Natmand]
Removed 1 person(s): [Carlo Andersen: Natmand]
Added 1 person(s): [Olga Hansen: Sypige]
[Olga Hansen: Sypige, Gunhild Mikkelsen: Heks, Valborg Kristensen: Spåkone]
[Olga Hansen: Sypige, Gunhild Mikkelsen: Heks, Valborg Kristensen: Spåkone]
Removed 3 person(s): [Olga Hansen: Sypige, Gunhild Mikkelsen: Heks,
Removed 3 person(s): [Olga Hansen: Sypige, Gunhild Mikkelsen: Heks,
Valborg Kristensen: Spåkone]
Valborg Kristensen: Spåkone]
Added 3 person(s): [Egon Knudsen: Kriger, Abelone Jensen: Sin mands kone,
Added 3 person(s): [Egon Knudsen: Kriger, Abelone Jensen: Sin mands kone,
Viktor Hansen: Høvding]
[Egon Knudsen: Kriger, Abelone Jensen: Sin
mands kone, Viktor Hansen: Høvding]
mands kone, Viktor Hansen: Høvding]
Removed 1 person(s): [Egon Knudsen: Kriger]
Removed 1 person(s): [Egon Knudsen: Kriger]
Removed 1 person(s): [Viktor Hansen: Høvding]
[Abelone
[Abelone Jensen:
Jensen: Sin
Sin mands
mands kone]

The
The test
test method
method starts
starts by by creating
creating 66 Person
Person objects.
objects. Next,
Next, aa Callback
Callback object
object isis defined
defined
which
which indicates
indicates which
which properties
properties for
for aa Person
Person object
object to to be
be observed
observed regarding
regarding changes.
changes. As As
the
the next
next step,
step, the
the class
class FXCollections
FXCollections isis used
used to
to create
create an an ObservableList<Person>
ObservableList<Person> with with the
the
above
above Callback
Callback object
object as as parameter.
parameter. Next,
Next, the
the list
list isis printed
printed onon the
the screen,
screen, which
which isis thethe
first line in the result, and it is just an empty list. The next statement adds
first line in the result, and it is just an empty list. The next statement adds p1 to the list, p1 to the list,
after
after which
which the
the list
list isis printed
printed again.
again. The
The result
result shows
shows that that the
the event
event handler
handler has
has performed
performed

34
34
34
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
propertIes

the
the method
method added()
added() andand added
added an
an object
object list,
list, and
and thethe list
list then
then contains
contains oneone object.
object. As
As the
the
next operation, p2 and p3 are added to the list and it is printed again.
next operation, p2 and p3 are added to the list and it is printed again. The result shows The result shows
that
that the
the event
event handler
handler hashas performed
performed the the method
method added()
added() again
again and
and added
added twotwo objects,
objects, and
and
the
the list now contains 3 objects. Next, the list is sorted and it is printed again. As shown by
list now contains 3 objects. Next, the list is sorted and it is printed again. As shown by
the
the result,
result, the
the event
event handler
handler has
has performed
performed the the method
method permuted()
permuted() corresponding
corresponding to to two
two
or more of the list’s objects have been replaced. Next, the value of a
or more of the list’s objects have been replaced. Next, the value of a property for p1 and property for p1 and
p2,
p2, respectively,
respectively, isis changed
changed and
and here
here you
you should
should note
note that
that the
the event
event handler
handler performs
performs thethe
method updated() and note that it is not the list’s content that has
method updated() and note that it is not the list’s content that has been changed but thebeen changed but the
objects
objects that
that the
the list
list contains.
contains. The
The next
next statement
statement again
again changes
changes the the actual
actual contents
contents of
of the
the list:
list:

list.set(0, new Person("Olga Hansen", "Sypige"));

and you can see from the result that the event handler has performed the method replaced().
After the list is printed again, the method will performe the statement

list.setAll(p4, p5, p6);

which means that the list content are replaced with three new objects. From the result, you
can see that both the method removed() and added() are performed. Finally, two objects are
deleted, and then one is left.

Looking at the above example, which should illustrate how an ObservableList works, you
could write similar programs that can illustrate how an ObservableSet and an ObservableMap
works. I do not want to show examples here as there are no big differences compared to
the above example.

2.3
2.3 BINDING OBSERVABLE COLLECTIONS
There is a class ListProperty that represents a property for an ObservableList, and you can think
of the class as a wrapper for an ObervableList. It is a property type similar to other properties
presented in this chapter. You can associate three kinds of listeners with a ListProperty:

-- InvallidationListener
-- ChangeListener
-- ListChangeListener

and these listeners will receive notifications when the OberservableList is changed as the
ListProperty object in question wrapper. Consider the following method:

35
35
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes

private static void test10()


{
ListProperty<String> property =
new SimpleListProperty(FXCollections.observableArrayList());
IntegerProperty count = new SimpleIntegerProperty();
count.bind(property.sizeProperty());
System.out.println(count.get());
property.addListener(FXProperties::propertyInvalidated);
property.addListener(FXProperties::propertyChanged);
property.addListener(FXProperties::propertyListChanged);
property.add("Gorm");
property.add("Harald");
System.out.println(count.get());
property.set(FXCollections.observableArrayList("Svend", "Knud", "Valdemar"));
System.out.println(count.get());
property.remove("Knud");
System.out.println(count.get());
System.out.println(property.get());
}

The method creates a ListProperty named property as a SimpleListProperty, which wrapper


The method creates a ListProperty named property as a SimpleListProperty, which wrapper
an ObservableList. In addition, an integerProperty is defined with the name count, and it
an ObservableList. In addition, an integerProperty is defined with the name count, and it
is bounded to the list’s size. Here, you should note that a ListProperty implements the
is bounded to the list’s size. Here, you should note that a ListProperty implements the

36
36
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE
JAVA DEVELOPMENT
15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

ObservableList
ObservableList
ObservableList interface
interface
interface and
and
and therefore
therefore
therefore has
has
has the
the
the same
same
same properties
properties
properties as
as
as an
an
an ObservableList.
ObservableList.
ObservableList. property
property
property
ObservableList
therefore has ainterface and
sizeProperty therefore
which is has
an the same properties
IntegerProperty and as
can an ObservableList.
therefore be boundedproperty
to
therefore
therefore has
has aa sizeProperty
sizeProperty which
which is
is an
an IntegerProperty
IntegerProperty and
and can
can therefore
therefore be
be bounded
bounded to
to
therefore
count. The has a
next sizeProperty
print statementwhichwillis an IntegerProperty
therefore print 0 onandthe can therefore
screen as the be
list bounded
is currently to
count.
count. The
The next
next print
print statement
statement will
will therefore
therefore print
print 00 on
on the
the screen
screen as
as the
the list
list is
is currently
currently
count.
empty. The
As nextnext
the print statement
step, the will methods
listener thereforeare print 0 on for
defined thethescreen asevents.
three the listTheis currently
first one
empty.
empty. As
As the
the next
next step,
step, the
the listener
listener methods
methods are
are defined
defined for
for the
the three
three events.
events. The
The first
first one
one
empty. As the next step, the listener methods are defined for the three events. The first one
isis
is trivial
trivial
trivial and
and
and does
does
does nothing
nothing
nothing but
but
but prints
prints
prints a
a
a text:
text:
text:
is trivial and does nothing but prints a text:
private static void propertyInvalidated(Observable list)
private static void propertyInvalidated(Observable list)
private
{ static void propertyInvalidated(Observable list)
{
{System.out.println("Property invalid…");
System.out.println("Property invalid…");
}System.out.println("Property invalid…");
}
}

You
You
You must
must
must note
note
note the
the
the parameter
parameter
parameter and
and
and that
that
that itit
it isis
is an
an
an Observable.
Observable.
Observable. The
The
The next
next
next listener
listener
listener method
method
method isis
is also
also
also
You must
trivial and note
it the
prints parameter
the and
contents ofthat
the it is
list an Observable.
before and afterThe
it next
has listener
been method
changed: is also
trivial
trivial and
and itit prints
prints the
the contents
contents of
of the
the list
list before
before and
and after
after itit has
has been
been changed:
changed:
trivial and it prints the contents of the list before and after it has been changed:
private static void propertyChanged(
private static void propertyChanged(
private static void propertyChanged(
ObservableValue<? extends ObservableList<String>> observable,
ObservableValue<? extends ObservableList<String>> observable,
ObservableValue<? extends ObservableList<String>> observable,
ObservableList<String> oldList, ObservableList<String> newList)
ObservableList<String> oldList, ObservableList<String> newList)
ObservableList<String> oldList, ObservableList<String> newList)
{
{
{System.out.println("Old: " + oldList);
System.out.println("Old: " + oldList);
System.out.println("Old: " + oldList);
System.out.println("New: " + newList);
System.out.println("New: " + newList);
System.out.println("New: " + newList);
}
}
}

You
You should
should primarily
primarily note
note the
the parameters
parameters that
that are
are a reference to the list (the object that
You
You should
should primarily
primarily note
note the
the parameters
parameters that
that are
are aaa reference
reference
reference to
to
to the
the
the list
list
list (the
(the
(the object
object
object that
that
that
caused
caused the
the event
event in
in question)
question) and
and the
the list’s
list’s value
value before
before the
the change
change and
and its
its value
value after
after
caused
caused the
the event
event in
in question)
question) and
and the
the list’s
list’s value before
value butbefore the
the achange
change and
and itsits value
value after
after
the
the change.
change. The
The last
last event
event handler
handler does
does nothing
nothing but prints
prints a text
text (possibly
(possibly more),
more), but
but
the
the change.
change. The
The last
last event
event handler
handler does
does nothing
nothing but
but prints
prints aa text
text (possibly
(possibly more),
more), but
but
distinguishes
distinguishes the
the reason
reason for
for the
the event:
event:
distinguishes
distinguishes the
the reason
reason for
for the
the event:
event:
private static void propertyListChanged(
private static void propertyListChanged(
private static void propertyListChanged(
ListChangeListener.Change<? extends String> change)
ListChangeListener.Change<? extends String> change)
ListChangeListener.Change<? extends String> change)
{
{
{while (change.next())
while (change.next())
while
{ (change.next())
{
{if (change.wasPermutated()) System.out.println("Permutated");
if (change.wasPermutated()) System.out.println("Permutated");
if (change.wasPermutated()) System.out.println("Permutated");
else if (change.wasUpdated()) System.out.println("Updated");
else if (change.wasUpdated()) System.out.println("Updated");
else
else if (change.wasUpdated()) System.out.println("Updated");
if (change.wasReplaced()) System.out.println("Replaced");
else if (change.wasReplaced()) System.out.println("Replaced");
else
else if
if (change.wasReplaced()) System.out.println("Replaced");
(change.wasRemoved()) System.out.println("Removed");
else if (change.wasRemoved()) System.out.println("Removed");
else if
else if (change.wasAdded())
(change.wasRemoved()) System.out.println("Removed");
System.out.println("Added");
else if (change.wasAdded()) System.out.println("Added");
} else if (change.wasAdded()) System.out.println("Added");
}
}}
}
}

Below
Below is shown the result of performing the test method:
Below isis
Below shown
is shown the
shown the result
the result of
result of performing
of performing the
performing the test
the test method:
test method:
method:
0
0
0
Property invalid…
Property invalid…
Property invalid…
Old: [Gorm]
Old: [Gorm]
Old: [Gorm]
New: [Gorm]
New: [Gorm]
New: [Gorm]

37
37
37
37
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT JavaFX properties
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX propertIes
propertIes

Added
Added
Property
Property invalid…
invalid…
Old:
Old: [Gorm,
[Gorm, Harald]
Harald]
New: [Gorm, Harald]
New: [Gorm, Harald]
Added
Added
2
2
Property
Property invalid…
invalid…
Old:
Old: [Gorm, Harald]
[Gorm, Harald]
New: [Svend, Knud, Valdemar]
New: [Svend, Knud, Valdemar]
Replaced
Replaced
3
3
Property
Property invalid…
invalid…
Old: [Svend, Valdemar]
Old: [Svend, Valdemar]
New: [Svend, Valdemar]
New: [Svend, Valdemar]
Removed
Removed
2
2
[Svend, Valdemar]
[Svend, Valdemar]

ItIt
It isis easy
is easy to
easy to follow
to follow the
follow the program
the program code
program code and
code and compare
and compare with
compare with the
with the results,
the results, and
results, and the
and the important
the important thing
important thing
thing
isis of
of course
course to
to observe
observe when
when each
each event
event handler
handler is
is performing.
performing.
is of course to observe when each event handler is performing.

You
You can
You can also
can also bind
also bind two
bind two ListProperty
two ListProperty objects
ListProperty objects to
objects to each
to each other,
each other, which
other, which means
which means that
means that the
that the lists
the lists that
lists that
that
they
they wrapper
they wrapper are
wrapper are bound.
are bound. Consider
bound. Consider the
Consider the following
the following method:
following method:
method:

private
private static
static void
void test11()
test11()
{
{
ListProperty<String> property1 =
ListProperty<String> property1 =

new SimpleListProperty<>(FXCollections.observableArrayList());
new SimpleListProperty<>(FXCollections.observableArrayList());
ListProperty<String> property2 =
ListProperty<String> property2 =

new SimpleListProperty<>(FXCollections.observableArrayList());
new SimpleListProperty<>(FXCollections.observableArrayList());
property1.add("Kristian");
property1.add("Kristian");
property2.add("Frederik");
property2.add("Frederik");
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
property1.bind(property2);
property1.bind(property2);
property1.addAll("Svend", "Knud", "Valdemar");
property1.addAll("Svend", "Knud", "Valdemar");
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
property2.set(FXCollections.observableArrayList("Gorm", "Harald"));
property2.set(FXCollections.observableArrayList("Gorm", "Harald"));
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
//
// property1.set(FXCollections.observableArrayList("Harld", "Oluf"));
property1.set(FXCollections.observableArrayList("Harld", "Oluf"));
property1.unbind();
property1.unbind();
property1.bindBidirectional(property2);
property1.bindBidirectional(property2);
property1.set(FXCollections.observableArrayList("Erik", "Kristoffer"));
property1.set(FXCollections.observableArrayList("Erik", "Kristoffer"));
property2.set(FXCollections.observableArrayList("Niels", "Abel"));
property2.set(FXCollections.observableArrayList("Niels", "Abel"));
property1.add("Oluf");
property1.add("Oluf");
property2.add("Knud");
property2.add("Knud");

38
38
38
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15:
SOFTWARE MORE ABOUT JAVAFX:
DEVELOPMENT JavaFX propertIes
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX properties
SOFTWARE DEVELOPMENT JavaFX propertIes
SOFTWARE DEVELOPMENT JavaFX propertIes

System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property1.get());
System.out.println(property2.get());
}System.out.println(property2.get());
}
}
Above this is defined two ListProperty objects that wrapper each their ObservableList, and
Above this is defined two ListProperty objects that wrapper each their ObservableList, and
Above
the firstthis
twois print
defined two ListProperty
statements objects
will therefore that
print: wrapper each their ObservableList, and
the first two print statements will therefore print:
the first two print statements will therefore print:
[Kristian]
[Kristian]
[Frederik]
[Kristian]
[Frederik]
[Frederik]
what there is no strange in. Because of the JavaFX properties, they can of course be bound:
what there is no strange in. Because of the JavaFX properties, they can of course be bound:
what there is no strange in. Because of the JavaFX properties, they can of course be bound:
property1.bind(property2);
property1.bind(property2);
property1.bind(property2);
which binds property1 to property2 with a unidirectional binding. Quite exactly, it means
which binds property1 to property2 with a unidirectional binding. Quite exactly, it means
which
that thebinds property1
list for to property2
which property1 with a for
is wrapper unidirectional
is the same binding. Quite exactly,
list that property2 it means
is wrapper for.
that the list for which property1 is wrapper for is the same list that property2 is wrapper for.
that next
The the list for which
statement property1
adds is wrapper
three names for is theand
to property1, same
thelist
nextthat property2again
statement is wrapper
a namefor.
to
The next statement adds three names to property1, and the next statement again a name to
The next statement
property2. The next adds three statments
two print names to results
property1,
in and the next statement again a name to
property2. The next two print statments results in
property2. The next two print statments results in
[Frederik, Svend, Knud, Valdemar, Hans]
[Frederik, Svend, Knud, Valdemar, Hans]
[Frederik, Svend, Knud, Valdemar, Hans]
[Frederik, Svend, Knud, Valdemar, Hans]
[Frederik, Svend, Knud, Valdemar, Hans]

39
39
39
39
JAVA
JAVA 15:
JAVA 15: MORE
15: MORE ABOUT
MORE ABOUT JAVAFX:
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX properties
JavaFX propertIes
propertIes

and
and perhaps
perhaps itit was was not
not what
what one
one would
would expect
expect as
as itit isis aa unidirectional
unidirectional binding,
binding, but
but since
since the
the
two
two property
property objectsobjects wrapper
wrapper thethe same
same list
list (and
(and the
the one
one thatthat property2
property2 was
was originally
originally wrapper
wrapper
for),
for), itit isis in
in both
both cases
cases that
that list
list that
that isis being
being updated.
updated. IfIf you you then
then perform
perform the
the statement
statement

property2.set(FXCollections.observableArrayList("Gorm", "Harald"));
property2.set(FXCollections.observableArrayList("Gorm", "Harald"));

property2isisnow
property2 nowwrapper
wrapperfor foraalist
listwith
withtwo
twonames,
names,and andbecause
becauseof ofthethebinding,
binding,bothbothproperties
properties
will refer
will refer to
to this
this list.
list. IfIf you
you try
try instead
instead to
to execute
execute thethe statement,
statement, whichwhich isis comment
comment out,out, you
you
get an
get an exception
exception due due to to the
the fact
fact that
that propert1
propert1 isis bound
bound to to property2
property2 with with aa unidirectional
unidirectional
binding.
binding. Therefore,
Therefore, do do not not change
change thethe object
object as as property1
property1 isis wrapper
wrapper for. for. Next,
Next, the
the binding
binding
isis removed
removed and and aa bidirectional
bidirectional bindingbinding isis instead
instead created.
created. Now
Now you you can
can change
change the
the list
list for
for
both properties,
both properties, since
since the the binding
binding now
now isis bidirectional,
bidirectional, andand itit isis the
the last
last value
value that
that applies.
applies.
The last
The last print
print statements
statements therefore
therefore results
results in:
in:

[Niels, Abel, Oluf, Knud]


[Niels, Abel, Oluf, Knud]
[Niels, Abel, Oluf, Knud]
[Niels, Abel, Oluf, Knud]

The above
The above bindings
bindings bind
bind the
the lists
lists that
that the
the properties
properties are
are wrappers
wrappers for,
for, but
but you
you can
can instead
instead
bind their
bind their contents
contents as
as you
you do
do with
with the
the methods
methods bindContent()
bindContent() and
and bindContentBidirectional():
bindContentBidirectional():

private
private static
static void
void test12()
test12()
{
{
ListProperty<String> property1 =
ListProperty<String> property1 =
new SimpleListProperty<>(FXCollections.observableArrayList());
new SimpleListProperty<>(FXCollections.observableArrayList());
ListProperty<String> property2 =
ListProperty<String> property2 =
new SimpleListProperty<>(FXCollections.observableArrayList());
new SimpleListProperty<>(FXCollections.observableArrayList());
property1.bindContent(property2);
property1.bindContent(property2);
property1.addAll("Svend", "Knud", "Valdemar");
property1.addAll("Svend", "Knud", "Valdemar");
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
property2.set(FXCollections.observableArrayList("Gorm", "Harald"));
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
property1.unbindContent(property2);
property1.unbindContent(property2);
property1.bindContentBidirectional(property2);
property1.bindContentBidirectional(property2);
property1.add("Oluf");
property1.add("Oluf");
property2.add("Knud");
property2.add("Knud");
System.out.println(property1.get());
System.out.println(property1.get());
System.out.println(property2.get());
System.out.println(property2.get());
}
}

Above this
Above this defines
defines aa binding
binding of
of the
the two
two lists’
lists’ content,
content, but
but this
this means
means that
that the
the two
two lists’
lists’
content by
content by the
the unidirectional
unidirectional binding
binding isis not
not synchronized:
synchronized:

40
40
40
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15:
15: MORE
SOFTWARE ABOUT
ABOUT JAVAFX:
DEVELOPMENT
MORE JAVAFX: Exercise 2
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT eXerCIse
eXerCIse 2
SOFTWARE eXerCIse 2
2

[Svend, Knud, Valdemar]


[Svend, Knud, Valdemar]
[]
[]
[Gorm, Harald, Svend, Knud, Valdemar]
[Gorm, Harald, Svend, Knud, Valdemar]
[Gorm,
[Gorm, Harald]
Harald]
[Gorm,
[Gorm, Harald,
Harald, Oluf,
Oluf, Knud]
Knud]
[Gorm,
[Gorm, Harald, Oluf, Knud]
Harald, Oluf, Knud]

As
As the
the last
last example,
example, II will
will show
show how
how to
to bind
bind to
to aa single
single element
element in
in an
an ObservableList:
ObservableList:

private
private static
static void
void test13()
test13()
{
{
ListProperty<Person> property =
ListProperty<Person> property =

new SimpleListProperty<>(FXCollections.observableArrayList());
new SimpleListProperty<>(FXCollections.observableArrayList());
ObjectBinding<Person> last =
ObjectBinding<Person> last =
property.valueAt(property.sizeProperty().subtract(1));
property.valueAt(property.sizeProperty().subtract(1));
property.add(new
property.add(new Person("Gudrun
Person("Gudrun Jensen",
Jensen", "Heks"));
"Heks"));
property.add(new
property.add(new Person("Carlo Andersen", "Skarpretter"));
Person("Carlo Andersen", "Skarpretter"));
property.add(new Person("Valborg Kristensen", "Spåkone"));
property.add(new Person("Valborg Kristensen", "Spåkone"));
System.out.println(property.get());
System.out.println(property.get());
System.out.println(last.get());
System.out.println(last.get());
}
}

property is
property is aa ListProperty,
ListProperty, which
which wrapper
wrapper an an ObservableList
ObservableList with
with Person
Person objects.
objects. last
last is
is an
an
ObjectBinding object
ObjectBinding object for
for aa Person
Person object
object that
that is
is bounded
bounded to to the
the last
last item
item inin the
the list
list that
that
property is
property is wrapper
wrapper for.
for. Note
Note the
the syntax.
syntax. The
The method
method valueAt()
valueAt() has
has as
as parameter
parameter an an index
index
and returns
and returns anan ObjectBinding
ObjectBinding to to the
the object
object in
in the
the list
list to
to which
which the
the index
index refers.
refers. After
After adding
adding
three objects
three objects to
to the
the list,
list, the
the print
print statements
statements shows:
shows:

[Gudrun
[Gudrun Jensen:
Jensen: Heks,
Heks, Carlo
Carlo Andersen:
Andersen: Skarpretter,
Skarpretter, Valborg
Valborg Kristensen:
Kristensen: Spåkone]
Spåkone]
Valborg Kristensen: Spåkone
Valborg Kristensen: Spåkone

In
In the
In the same
the same way
same way as
way as shown
as shown in
shown in this
in this section,
this section, there
section, there are
there are also
are also wrapper
also wrapper properties
wrapper properties called
properties called SetProperty
called SetProperty
SetProperty
and MapProperty
and MapProperty
and for
MapProperty for an
for an ObeservableSet
an ObeservableSet and
ObeservableSet and an
and an ObservableMap
an ObservableMap respectively.
ObservableMap respectively.
respectively.

EXERCISE
EXERCISE 2
2
Create
Create aaa simple
Create simple console
simple console application,
console application, which
application, which you
which you
you can
can call
can call BindingElements.
call BindingElements. The
BindingElements. The project
The project
project
FXProperties has
FXProperties has
FXProperties a class
has aa class Person.
class Person. Copy
Person. Copy this
Copy this class
class to
this class to
to the new
the new
the project
new project and
project and add
and add the
add the following
the following
following
simple
simple method
simple method
method to to the
to the class
the class BindingElements:
class BindingElements:
BindingElements:

private static void print(List<Person> list)


private static void print(List<Person> list)
{
{
for
for (Person
(Person p
p :
: list)
list) System.out.println(p);
System.out.println(p);
System.out.println();
System.out.println();
}
}

41
41
41
41
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 22

Then
Then write
write the
the following
following main()
main() method:
method:

public static void main(String[] args)


{
// Create an ObservableList<Person> to Person objects
// Add 5 Person objects to list, what names and job titles do not matter
// Create a ListProperty for the above list
// Define a binding for the element with index 1
// Define a binding for the element with index 3
// Print the list on the screen
// Insert a new Person in list at position 1
// Insert a new Person in list at position 3
// Modify the name of the Person that is bound with p1
// Modify the job title of the Person that is bound with p3
// Print the list on the screen
}

Test
Test the
the program.
program. Do
Do you
you get
get the
the expected
expected result?
result? Are
Are there
there the
the expected
expected objects
objects that
that have
have
been
been changed?
changed?

Join the best at Top master’s programmes


• 3
 3rd place Financial Times worldwide ranking: MSc
the Maastricht University International Business
• 1st place: MSc International Business
School of Business and • 1st place: MSc Financial Economics
• 2nd place: MSc Management of Learning

Economics! • 2nd place: MSc Economics


• 2nd place: MSc Econometrics and Operations Research
• 2nd place: MSc Global Supply Chain Management and
Change
Sources: Keuzegids Master ranking 2013; Elsevier ‘Beste Studies’ ranking 2012;
Financial Times Global Masters in Management ranking 2012

Maastricht
University is
the best specialist
university in the
Visit us and find out why we are the best! Netherlands
(Elsevier)
Master’s Open Day: 22 February 2014

www.mastersopenday.nl

42
42
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 22

2.4
2.4 BINDING
BINDING PERSONS
PERSONS
As
As aa final
final example
example of
of properties,
properties, the
the application
application PersonProgram
PersonProgram opens
opens the
the following
following window:
window:

where
where youyou inin the
the two
two top
top entry
entry fields,
fields, can
can enter
enter thethe name
name and
and job
job title
title of
of aa person.
person. IfIf you
you
click
click OK,
OK, aa person
person will
will be
be added
added to to aa ListView.
ListView. In In the
the window
window above
above 66 persons
persons have
have been
been
created
created // entered.
entered. IfIf you
you double-click
double-click on on aa person
person in in the
the ListView
ListView control,
control, the
the person’s
person’s
data
data isis inserted
inserted into
into the
the input
input fields,
fields, and
and they
they cancan then
then be
be edited.
edited. IfIf you
you double
double click
click onon
aa person,
person, this
this can
can be
be deleted
deleted byby clicking
clicking the
the Remove
Remove button.
button. Finally,
Finally, the
the Clear
Clear button
button isis
used
used toto delete
delete the
the entry
entry fields
fields and
and remove
remove aa selction
selction in in the
the ListView
ListView control.
control. The
The bottom
bottom
button
button isis used
used to
to delete
delete the
the content
content of of the
the list.
list.

The
The program
program uses
uses the
the class
class Person
Person from
from the
the project
project FXProperties
FXProperties –– expanded
expanded by
by two
two trivial
trivial
methods.
methods. The
The code
code for
for the
the PersonProgram’s
PersonProgram’s window
window isis as
as follows:
follows:

package personprogram;

import javafx.application.Application;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.geometry.*;
import javafx.scene.input.*;
import javafx.collections.*;
import javafx.beans.property.*;

43
43
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 2
SOFTWARE DEVELOPMENT eXerCIse 2

public class PersonProgram extends Application


{
private TextField txtName = new TextField();
private TextField txtJob = new TextField();
private ListView lstView = null;
private Person person = new Person("", "");
private ObservableList<Person> persons =
FXCollections.observableArrayList();
private IntegerProperty selected = new SimpleIntegerProperty(-1);

@Override
public void start(Stage primaryStage)
{
lstView = new ListView(persons);
lstView.setPrefHeight(300);
lstView.setOnMouseClicked(this::clickHandler);
selected.bind(lstView.getSelectionModel().selectedIndexProperty());
BorderPane root =
new BorderPane(lstView, createTop(), null, createBottom(), null);
root.setPadding(new Insets(20, 20, 20, 20));
BorderPane.setMargin(lstView, new Insets(20, 0, 20, 0));
Scene scene = new Scene(root);
primaryStage.setTitle("Persons");
primaryStage.setScene(scene);
primaryStage.show();
}

private Pane createBottom()


{
HBox pane = new HBox(createButton("Delete", this::deleteHandler));
pane.setAlignment(Pos.CENTER_RIGHT);
return new BorderPane(null, null, pane, null, null);
}

private Pane createTop()


{
txtName.textProperty().bindBidirectional(person.nameProperty());
txtJob.textProperty().bindBidirectional(person.jobProperty());
txtName.setPrefWidth(300);
HBox commands = new HBox(10, createButton("Remove", this::removeHandler),
createButton("Clear", this::clearHandler),
createButton("OK", this::okHandler));
commands.setAlignment(Pos.CENTER_RIGHT);
GridPane pane = new GridPane();
pane.setVgap(10);
pane.setHgap(20);
pane.addRow(0, new Label("Name"), txtName);
pane.addRow(1, new Label("Job"), txtJob);

44
44
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 2
SOFTWARE DEVELOPMENT eXerCIse 2

pane.add(commands, 1, 2);
return pane;
}

private Button createButton(String text, EventHandler<ActionEvent> handler)


{
Button cmd = new Button(text);
cmd.setOnAction(handler);
return cmd;
}

private void okHandler(ActionEvent e)


{
if (person.getName().trim().length() > 0 &&
person.getJob().trim().length() > 0)
{
if (selected.get() < 0)
persons.add(new Person(person.getName(), person.getJob()));
else persons.set(selected.get(),
new Person(person.getName(), person.getJob()));
clearHandler(e);
}
}

45
45
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 2
SOFTWARE DEVELOPMENT eXerCIse 2

private void clearHandler(ActionEvent e)


{
person.clear();
lstView.getSelectionModel().clearSelection();
txtName.requestFocus();
}

private void removeHandler(ActionEvent e)


{
if (selected.get() >= 0) persons.remove(selected.get());
clearHandler(e);
}

private void deleteHandler(ActionEvent e)


{
persons.clear();
clearHandler(e);
}

private void clickHandler(MouseEvent e)


{
if (e.getButton() == MouseButton.PRIMARY && e.getClickCount() == 2)
{
if (selected.get() >= 0) person.update(persons.get(selected.get()));
}
else lstView.getSelectionModel().clearSelection();
}

public static void main(String[] args)


{
launch(args);
}
}

The class has 6 instance variables, where the first three are for controls. The next has the type
Person and represents the object on which you work, and thus the object whose properties
appear in the two entry fields. The next again is an ObservableList and represents the content
of the ListView control. Finally, the last one is a property that must represent the index of
the Person object in the list that is selected.

Examining the method start() is the first thing that happens that the lstView object is created
with persons as a parameter for the constructor. This means that a bidirectional binding
is created between the ListView component and the list persons. An event handler is also
associated with the ListView component for mouse events. Finally, the property selected is
bound to the selected index in the ListView component. The rest of the method start()

46
46
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 22

does
does not
not contain
contain anything
anything new
new and
and isis only
only intended
intended toto create
create the
the window’s
window’s scene
scene graph.
graph.
However,
However, you
you must
must note
note the
the method
method createTop()
createTop() that
that creates
creates aa GridPane
GridPane for
for entering
entering aa
person.
person. Here
Here you
you should
should especially
especially note
note how
how the
the two
two TextField
TextField controls
controls bind
bind to
to properties
properties
of the Person object.
of the Person object.

Then
Then there
there are
are the
the event
event handlers
handlers where
where there
there are are 5,
5, but
but they
they areare generally
generally simple.
simple. The
The first
first
concerns
concerns thethe OKOK button
button andand starts
starts by
by testing
testing whether
whether something
something has has been
been entered
entered for
for both
both
name
name and job title. If this is the case, the property selected is used to determine whether to
and job title. If this is the case, the property selected is used to determine whether to
add
add aa new
new object
object or or whether
whether an an existing
existing object
object isis to to be
be modified.
modified. You You should
should note
note that
that in
in
either
either case,
case, aa new
new Person
Person object
object isis instantiated.
instantiated. ItIt isis necessary
necessary because
because the the variable
variable person
person
can
can not
not be
be set
set to
to refer
refer to
to another
another object
object as
as itit isis bound
bound to to the
the input
input fields.
fields. Whether
Whether youyou add
add
an object or modify an object, the event handler for the Clear button
an object or modify an object, the event handler for the Clear button is called that clears is called that clears
the
the fields
fields in
in the
the person
person object
object andand removes
removes any any selection
selection in in the
the ListView
ListView component.
component. The The
event
event handlers
handlers for for the
the Remove
Remove and and Delete
Delete buttons
buttons are are both
both trivial
trivial and
and the
the event
event handler
handler for
for
clicks
clicks with
with the
the mouse
mouse in in the
the ListView
ListView component
component isis also also simple,
simple, andand youyou should
should especially
especially
note how to test for double-click.
note how to test for double-click.

When
When youyou test
test the
the program,
program, note
note how
how the
the user
user interface
interface isis automatically
automatically updated
updated for
for reasons
reasons
of
of the
the bindings.
bindings.

2.5
2.5 THE
THE SCREEN
SCREEN
In
In these
these and
and the
the following
following two
two sections
sections II briefly
briefly will
will mention
mention howhow to
to refer
refer to
to the
the screen
screen
and
and aa little
little more
more remarks
remarks about
about the
the program’s
program’s Stage
Stage object
object –– although
although itit does
does not
not have
have
much
much to do with properties, but the examples are part of the project FXProperties. The
to do with properties, but the examples are part of the project FXProperties. The
following
following class
class opens
opens aa window
window that
that prints
prints informations
informations onon the
the console
console about
about thethe screen
screen
and
and components
components size:size:

public class ScreenView extends Application


{
@Override
public void start(Stage stage)
{
BorderPane root = new BorderPane(new Label("Tekst"));
root.setPadding(new Insets(30, 30, 30, 30));
Scene scene = new Scene(root, 300, 200);
stage.setScene(scene);
stage.setTitle("Screen");
stage.setWidth(500);
stage.setHeight(400);
stage.show();

47
47
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 2
SOFTWARE DEVELOPMENT eXerCIse 2

showSize();
showSize(stage);
showSize(root);
}

private void showSize()


{
Screen screen = Screen.getPrimary();
Rectangle2D r1 = screen.getBounds();
Rectangle2D r2 = screen.getVisualBounds();
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n", r1.getMinX(),
r1.getMinY(), r1.getWidth(), r1.getHeight());
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n\n", r2.getMinX(),
r2.getMinY(), r2.getWidth(), r2.getHeight());
}

private void showSize(Stage s)


{
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n\n", s.getX(), s.getY(),
s.getWidth(), s.getHeight());
}

48
48
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 2
eXerCIse 2
SOFTWARE DEVELOPMENT eXerCIse 2

private void showSize(Pane p)


private void showSize(Pane p)
{
{
Bounds b1 = p.getBoundsInLocal();
Bounds b1 = p.getBoundsInLocal();
Bounds b2 = p.getBoundsInParent();
Bounds b2 = p.getBoundsInParent();
Bounds b3 = p.getLayoutBounds();
Bounds b3 = p.getLayoutBounds();
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n", b1.getMinX(),
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n", b1.getMinX(),
b1.getMinY(), b1.getWidth(), b1.getHeight());
b1.getMinY(), b1.getWidth(), b1.getHeight());
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n", b2.getMinX(),
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n", b2.getMinX(),
b2.getMinY(), b2.getWidth(), b2.getHeight());
b2.getMinY(), b2.getWidth(), b2.getHeight());
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n\n", b3.getMinX(),
System.out.printf("(%1.0f, %1.0f) %1.0f x %1.0f\n\n", b3.getMinX(),
b3.getMinY(), b3.getWidth(), b3.getHeight());
b3.getMinY(), b3.getWidth(), b3.getHeight());
}
}
}
}

The program is simple and does nothing but create a window with a button. You should
The program is simple and does nothing but create a window with a button. You should
note that when the root object is added to the scene object, the window size is defined,
note that when the root object is added to the scene object, the window size is defined,
and thus becoming the Stage object’s size, but also the size of the root object, that is a
and thus becoming the Stage object’s size, but also the size of the root object, that is a
BorderPane. This size is changed later in the method start(), partly to show that it is possible,
BorderPane. This size is changed later in the method start(), partly to show that it is possible,
and partly to show that it does not change the size of the root object. After the window is
and partly to show that it does not change the size of the root object. After the window is
displayed on screen, three methods are called, which prints text on the console. You should
displayed on screen, three methods are called, which prints text on the console. You should
note that these methods must be called after the Stage object is displayed and the scene
note that these methods must be called after the Stage object is displayed and the scene
graph’s components are rendered.
graph’s components are rendered.

The first method uses a class Screen that has static methods that return a Screen object that
The first method uses a class Screen that has static methods that return a Screen object that
represents the screen and which is used to determine properties of the screen. In this case,
represents the screen and which is used to determine properties of the screen. In this case,
two methods are used which return a Rectangle2D object with information about the screen
two methods are used which return a Rectangle2D object with information about the screen
size (measured in pixels and thus the resolution of the screen). The first returns the physical
size (measured in pixels and thus the resolution of the screen). The first returns the physical
size of the screen while the other returns the size available for the program. The difference
size of the screen while the other returns the size available for the program. The difference
depends on the current platform, but the result could be as follows:
depends on the current platform, but the result could be as follows:
(0, 0) 1920 x 1080
(0, 0) 1920 x 1080
(0, 27) 1920 x 1020
(0, 27) 1920 x 1020

The
The difference
difference is
is because
because my
my screen
screen at
at the
the top
top has
has the
the Activity
Activity line
line (Fedora)
(Fedora) and
and below
below
The difference is because my screen at the top has the Activity line (Fedora) and below
aa taskbar.
taskbar.
a taskbar.
The
The next
next method
method prints
prints the
the Stage
Stage object’s
object’s size
size and
and position
position on
on the
the screen
screen of
of its
its upper
upper left
left
The next method prints the Stage object’s size and position on the screen of its upper left
corner. Here you should note which properties the class Stage has regarding
corner. Here you should note which properties the class Stage has regarding position andposition and
corner. Here you should note which properties the class Stage has regarding position and
size,
size, and
and that
that the
the size
size is
is determined
determined by
by the
the values
values II have
have assigned
assigned in
in the
the start()
start() method:
method:
size, and that the size is determined by the values I have assigned in the start() method:
(710, 234) 500 x 400
(710, 234) 500 x 400

49
49
49
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 2

The last method prints information about the size of a node, as here is root and thus a
BorderPane. The size is determined using three methods, all of which return a Bound object:

1. getBoundsInLocal(), as the position and size before any possible transformation


2. getBoundsInParent(), which is the position and size after a possible transformation
3. getLayoutBounds(), which is the position and size as a layout pane uses for calculations
and may be different from the other sizes and is used if you write custom controls

In this case they are all alike.

2.6 DECORATIONS
A typical window looks something like the following:

where there is a title bar and a border so you can change the window size. In addition,
there is the window content, like here a scene graph with a label and a button. How the
title bar and border are displayed depends on the current platform, and for the title bar,
the platform determines which buttons are available. The window’s title bar is also used to
move the window on the screen by dragging it with the mouse and for example maximizing
it by double-clicking the title bar.

Title bar and border are referred to as the window’s decorations or styles, and here are actually
more options, which are defined as properties of the Stage object. I want to mention three:

1. StageStyle.DECORATED, which is the default where the window has a title bar
and a border
2. StageStyle.UNDECORATED, where the window is not decorated and therefore does
not have a title bar or border
3. StageStyle.TRANSPARENT, where the window is not decorated and also has a
transparent background

50
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT Exercise
eXerCIse22

For
For example,
example, ifif you
you defines
defines the
the above
above window
window as
as UNDECORATED,
UNDECORATED, the
the result
result is:
is:

and
and ifif you
you defines
defines the
the window
window as
as TRANSPARENT
TRANSPARENT isis the
the result:
result:

The
The above
above can
can be
be illustrated
illustrated by
by the
the following
following class:
class:

public class StyleView extends Application


{
private Stage stage;
private double xpos;
private double ypos;

Need help with your


dissertation?
Get in-depth feedback & advice from experts in your
topic area. Find out what you can do to improve
the quality of your dissertation!

Get Help Now

Go to www.helpmyassignment.co.uk for more info

51
51
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
JAVA 15: MORE ABOUT JAVAFX: Exercise 2
SOFTWARE DEVELOPMENT eXerCIse 2

public void start(Stage stage)


{
this.stage = stage;
Label lbl = new Label();
Button cmd = new Button("Close");
cmd.setOnAction(e -> stage.close());
VBox root = new VBox(10, lbl, cmd);
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 200, 100);
stage.setScene(scene);
stage.setTitle("StyleView");
this.show(scene, lbl, StageStyle.DECORATED);
// this.show(scene, lbl, StageStyle.UNDECORATED);
// this.show(scene, lbl, StageStyle.TRANSPARENT);
}

private void show(Scene scene, Label lbl, StageStyle style)


{
lbl.setText(style.toString());
stage.initStyle(style);
if (style == StageStyle.UNDECORATED || style == StageStyle.TRANSPARENT)
{
scene.setOnMousePressed(e -> handleMousePressed(e));
scene.setOnMouseDragged(e -> handleMouseDragged(e));
}
if (style == StageStyle.TRANSPARENT)
{
stage.getScene().setFill(null);
stage.getScene().getRoot().setStyle("-fx-background-color: transparent");
}
stage.show();
}

private void handleMousePressed(MouseEvent e)


{
xpos = e.getScreenX() – stage.getX();
ypos = e.getScreenY() – stage.getY();
}

private void handleMouseDragged(MouseEvent e)


{
stage.setX(e.getScreenX() – xpos);
stage.setY(e.getScreenY() – ypos);
}
}

52
52
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 2

where the comments in the method start() indicate how the window should be decorated.
There is not much going on in the start() method in addition to creating the scene graph
and initializing the Stage object. Note that the class this time has an instance variable that
refers to the Stage object so that it can be referenced from other class methods. Also note
the event handler to the Close button, which closes the window, thus terminating the
program. It works in this case, but not necessarily in other programs. If you perform a
close() on a Stage object, it will hide the window (perform the hide() method in the base
class to Stage that is named Window) and are there no other windows, the program will
terminate. If you want to terminate the program as soon as a button is clicked, you should
instead execute Platform.exit().

The window opens in the method show(), which has three parameters, which are the scene
graph, its Label control and the style of the window and hence how it should be decorated.
The method starts by setting the text for the window’s Label control and then how the
Stage object has to be decorated. Here you must note the syntax and that it must be done
before the Stage object appears on the screen. If the style is TRANSPARENT, it indicates
that there is no background. If the window is UNDECORATED, there is a problem, as you
can not move it with the mouse. If you wish, you can, as shown above, associate an event
handler for the mouse to the Scene object and then control that the window can be moved.

2.7 MODALITY
As you know it from Swing, a dialog box can be modeless or modal, and of course it also
applies in JavaFX, where it is a property of the Stage object. There are three options:

1. Modality.NONE, where the result is a modeless window, which is the default for
a Stage
2. Modality.WINDOW_MODAL, which is modal and blocks all windows that directly
or indirectly own this window
3. Modality.APPLICATION_MODEL, which is modal and blocks all of the application’s
other windows

The following example shows the syntax, but also shows that an application may well have
multiple Stage objects and thus windows (or dialogs) that explicitly create a Stage object.
The StageView class opens the following window:

53
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 2

where each of the four top buttons opens a dialog box by instantiating a new Stage object,
and the difference is partly modality and partly if the dialog has an owner. For example,
the first is modeless and without an owner. This means clicking on the top button, the
program will open a dialog box and then click at the cross in the main window’s title bar
(and you can because the dialog is modeless) closes the main window but not the dialog
and the program does not terminate, before closing the other window.

Brain power By 2020, wind could provide one-tenth of our planet’s


electricity needs. Already today, SKF’s innovative know-
how is crucial to running a large proportion of the
world’s wind turbines.
Up to 25 % of the generating costs relate to mainte-
nance. These can be reduced dramatically thanks to our
systems for on-line condition monitoring and automatic
lubrication. We help make it more economical to create
cleaner, cheaper energy out of thin air.
By sharing our experience, expertise, and creativity,
industries can boost performance beyond expectations.
Therefore we need the best employees who can
meet this challenge!

The Power of Knowledge Engineering

Plug into The Power of Knowledge Engineering.


Visit us at www.skf.com/knowledge

54
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT eXerCIse 22
Exercise

The last
The last button
button isis included
included toto show
show that
that aa Stage
Stage object
object also
also has
has aa method,
method, so so you
you can
can say
say
that the
that the window
window should
should bebe displayed
displayed full
full screen.
screen. Note
Note that
that displaying
displaying aa full
full screen
screen window
window
you returns
you returns to
to normal
normal viewing
viewing byby pressing
pressing ESC
ESC –– or
or clicking
clicking the
the Full
Full screen
screen button
button again.
again.

The code
The code isis as
as follows:
follows:

public class StagesView extends Application


{
@Override
public void start(Stage stage)
{
VBox root = new VBox(20,
createButton("No owner, NONE", e -> showDialog(null, null)),
createButton("Owner, NONE", e -> showDialog(stage, Modality.NONE)),
createButton("Owner, WINDOW_MODAL",
e -> showDialog(stage, Modality.WINDOW_MODAL)),
createButton("Owner, APPLICATION_MODAL",
e -> showDialog(stage, Modality.APPLICATION_MODAL)),
createButton("Full screen",
e -> stage.setFullScreen(!stage.isFullScreen())));
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Primary Stage");
stage.show();
}

private Button createButton(String text, EventHandler<ActionEvent> handler)


{
Button cmd = new Button(text);
cmd.setOnAction(handler);
return cmd;
}

private void showDialog(Window owner, Modality modality)


{
Stage stage = new Stage();
stage.initOwner(owner);
if (modality != null) stage.initModality(modality);
VBox root = new VBox(20, new Label(owner == null ? "Default" :
"Parent Window"), new Label(modality == null ? "Default" :
modality.toString()), createButton("Close", e -> stage.close()));
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(20, 20, 20, 20));

55
55
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
SOFTWARE ABOUT
ABOUT JAVAFX:
DEVELOPMENT
MORE JAVAFX: Exercise 2
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT eXerCIse
eXerCIse 22

Scene
Scene scene
scene =
= new
new Scene(root);
Scene(root);
stage.setScene(scene);
stage.setScene(scene);

stage.setTitle("Stage");
stage.setTitle("Stage");
stage.show();
stage.show();
}
}
}
}

There is
There is
There not
is not much
not much to
much to explain,
to explain, but
explain, but you
but you should
you should note
should note the
note the method
the method showDialog(),
method showDialog(), which
showDialog(), which creates
which creates
creates
aaa dialog
dialog box
dialog box by
box by instantiating
by instantiating a new
instantiating aa new Stage
new Stage object.
Stage object.
object.

PROBLEM 1
PROBLEM 1
PROBLEM 1
In this
In this
In task
this task you
task you must
you must write
write aaa program
must write program that
program that works
that works in
works in the
in the same
the same way
same way as
way as the
as the program
the program from
program from
from
section 2.4.
section 2.4.
section The
2.4. The database
The database padata
database padata
padata has has a table
has aa table with
table with the
with the name
the name history
name history which
history which contains
which contains information
contains information
information
about historical
about historical
about persons
historical persons (see,
persons (see, if applicable,
(see, ifif applicable, the
applicable, the book
the book Java
book Java 6).
Java 6). The
6). The table
The table is created
table isis created with
created with the
with the
the
following script:
following script:
following script:

use
use padata;
padata;
drop
drop table
table if
if exists
exists history;
history;
create table history
create table history
(
(
id int not null auto_increment primary key, # autogenerated surrogat key
id int not null auto_increment primary key, # autogenerated surrogat key
name varchar(50) not null,
name varchar(50) not null, # the person's name
# the person's name
title varchar(30),
title varchar(30),
# the person's job title
# the person's job title
birth int,
birth int,

# birth, start of reign, or equivalent
# birth, start of reign, or equivalent
death int,
death int,

# the year of death, end of reign, or
# the year of death, end of reign, or equivalent
equivalent
country char(2),
country char(2),
# the country the person comes from
# the country the person comes from
description text
description text
# a description
# a description
);
);

You
You must
must write
write aa program
program that
that can
can maintain
maintain this
this database
database table.
table. For
For example,
example, you
you can
can call
call
You
the must write
project for a program
History. that can maintain this database table. For example, you can call
the project for History.
the project for History.
The
The task
task can
can be
be solved
solved in
in several
several ways,
ways, but
but the
the idea
idea is
is to
to use
use data
data binding,
binding, partly
partly when
when
The
data task
is can be
displayed, solved
and in several
partly when ways, but
editing the idea
information is to use
about a data binding,
single person. partly when
data is displayed, and partly when editing information about a single person.
data is displayed, and partly when editing information about a single person.

56
56
56
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 2

When the program starts, it must display a list of all persons in the database, and it could
be a window as shown below, with a ListView showing the names of all persons:

57
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 2

The button should be used to create a new person and if you double-click a name in the
list, the program must show all information about a person and it must be possible to edit
the information. In both cases, you should use the same dialog box that could be:

58
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT advanCed controls
Advanced Controls

3 ADVANCED CONTROLS
3
In this chapter I will illustrate the use of three controls that did not fit in the previous book:

1. TableView
1.
2. TreeView
2.
3. TreeTableView
3.

where the first corresponds to the component JTable, the second to the component JTree,
while the latter is best characterized as a combination. When the three components were not
included in the previous book, it is partly because they are complex with many possibilities,
and partly that their way of working can best be described after the mentions in the previous
chapter of properties and binding.

3.1 TABLEVIEW
3.1 TABLEVIEW
I want to start with the TableView component, that like JTable, is an extremely complex
control that arranges data in rows and columns, and it is also the most useful of the three
controls. The component’s class is called TableView, but together with the component are
several helper classes:

-- TableColumn
-- TableRow
-- TableCell
-- TablePosition
-- TableView.TableViewFocusModel
-- TableView.TableViewSelectionModel

and the names should tell a little about the purpose of the individual classes. The class
TableView is used a bit like a JTable, where you must define a data model, which is the data
that the component should display, and which columns there should be. I will start with
an example, which I have called ShowKingsProgram, which shows an overview of Danish
kings represented as objects of the type King (the class from the previous chapter):

public class King


{
private static final String DK = "DK";
private ReadOnlyStringWrapper name = new ReadOnlyStringWrapper(this, "name");
private IntegerProperty from = new SimpleIntegerProperty(this, "from", 0);

59
59
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

private IntegerProperty to = new SimpleIntegerProperty(this, "to", 9999);


private StringProperty country;

IfIf you
you run
run the
the program,
program, itit opens
opens the
the window
window below
below which
which shows
shows aa table
table with
with 55 columns
columns
and thus
and thus one
one column
column more
more than than the
the type
type of
of King
King has
has properties
properties for:
for:

Challenge the way we run

EXPERIENCE THE POWER OF


FULL ENGAGEMENT…

RUN FASTER.
RUN LONGER.. READ MORE & PRE-ORDER TODAY
RUN EASIER… WWW.GAITEYE.COM

1349906_A6_4+0.indd 1 22-08-2014 12:56:57

60
60
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT advanCed Controls
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls

If
If you
If you study
you study the
study the program
the program code
program code (the
code (the main
(the main program)
main program) it
program) it is:
it is:
is:

public
public class
class ShowKingsProgram
ShowKingsProgram extends
extends Application
Application
{{
private KingTableModel model = new KingTableModel();
private KingTableModel model = new KingTableModel();

@Override
@Override
public
public void
void start(Stage
start(Stage stage)
stage)
{{
TableView<King> table = new TableView(model.getKings());
TableView<King> table = new TableView(model.getKings());
table.getColumns().addAll(model.getNameCol(), model.getPeriodCol(),
table.getColumns().addAll(model.getNameCol(), model.getPeriodCol(),
model.getCountryCol(),
model.getCountryCol(), model.getYearsCol());
model.getYearsCol());
BorderPane
BorderPane root
root == new
new BorderPane(table);
BorderPane(table);
root.setPadding(new
root.setPadding(new Insets(10,
Insets(10, 10,
10, 10,
10, 10));
10));
Scene
Scene scene = new Scene(root, 500, 400);
scene = new Scene(root, 500, 400);
stage.setScene(scene);
stage.setScene(scene);
stage.setTitle("Show kings");
stage.setTitle("Show kings");
stage.show();
stage.show();
}}

public
public static
static void
void main(String[]
main(String[] args)
args)
{{
launch(args);
launch(args);
}}
}}

which
which isis very
very simple.
simple. Initially,
Initially, aa model
model isis defined
defined (explained
(explained below).
below). Otherwise,
Otherwise, nothing
nothing
happens
happens except the method start(), where a TableView is created for King objects and
except the method start(), where a TableView is created for King objects and
initialized
initialized with the data model, and finally, four columns are added using methods in the
with the data model, and finally, four columns are added using methods in the
data model. The respective TableView is inserted into the program’s scene graph
data model. The respective TableView is inserted into the program’s scene graph encapsulated encapsulated
in
in aa BorderPane.
BorderPane. ItIt isis the
the model
model class
class KingTableModel
KingTableModel thatthat contains
contains the
the most:
most:

public class KingTableModel


public class KingTableModel
{
{
private
final
private ObservableList<King>
final kings
ObservableList<King> =
kings
= FXCollections.observableArrayList();
FXCollections.observableArrayList();

public KingTableModel()
public KingTableModel()
{{
for
for (String[]
(String[] arr
arr :: data)
data) kings.add(new
kings.add(new King(arr[0],
King(arr[0], Integer.parseInt(arr[1]),
Integer.parseInt(arr[1]),
Integer.parseInt(arr[2])));
Integer.parseInt(arr[2])));
}}

public ObservableList<King> getKings()


public ObservableList<King> getKings()
{{
return
return kings;
kings;
}}

61
61
61
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

public TableColumn<King, String> getNameCol()


{
TableColumn<King, String> col = new TableColumn("Name");
col.setCellValueFactory(new PropertyValueFactory("name"));
return col;
}

public TableColumn<King, Integer> getFromCol()


{
TableColumn<King, Integer> col = new TableColumn("From");
col.setCellValueFactory(new PropertyValueFactory("from"));
return col;
}

public TableColumn<King, Integer> getToCol()


{
TableColumn<King, Integer> col = new TableColumn("To");
col.setCellValueFactory(new PropertyValueFactory("to"));
return col;
}

public TableColumn<King, String> getCountryCol()


{
TableColumn<King, String> col = new TableColumn("Country");
col.setCellValueFactory(new PropertyValueFactory("country"));
return col;
}

public TableColumn<King, String> getPeriodCol()


{
TableColumn<King, String> col = new TableColumn<>("Period");
col.getColumns().addAll(getFromCol(), getToCol());
return col;
}

public TableColumn<King, String> getYearsCol()


{
TableColumn<King, String> col = new TableColumn<>("Years");
col.setCellValueFactory(c -> {
King king = c.getValue();
int a = king.getFrom();
int b = king.getTo();
if (a == 0 || b == 9999) return new ReadOnlyStringWrapper("Unknown");
return new ReadOnlyStringWrapper("" + (b – a));
});
return col;
}

62
62
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

private static final String[][] data = {


{ "Gorm den Gamle", "0", "958" },
{ "Harald Blåtand", "958", "987" },

};
}

The
The class
class starts
starts by
by creating
creating an an ObservableList
ObservableList for for King
King objects,
objects, and
and the
the list
list is
is initialized
initialized in
in
the constructor using data defined in an array at the end of the class.
the constructor using data defined in an array at the end of the class. Note that the list Note that the list
as
as an
an alternative
alternative could
could be be initialized
initialized by
by reading
reading aa database
database table.
table. The
The class
class hashas aa method
method
that
that can
can return
return the
the list,
list, which
which was
was used
used in
in the
the method
method start()
start() in
in the
the constructor
constructor for for the
the
TableView component. The rest of the class consists of methods that creates
TableView component. The rest of the class consists of methods that creates the individual the individual
columns.
columns. TheThe first
first is
is for
for the name property,
the name property, and
and the
the type
type of
of aa column
column is is TableColumn,
TableColumn, with with
parameters
parameters indicating
indicating whichwhich thethe objects
objects are
are (here
(here King)
King) and
and the
the type
type ofof the
the property
property inin
question
question (here
(here String).
String). TheThe parameter
parameter of of the
the constructor
constructor inin TableColumn
TableColumn is is the
the text
text shown
shown
in the header of the columns. Next, you must specify which values each cell
in the header of the columns. Next, you must specify which values each cell should contain, should contain,
and
and it
it happens
happens with
with aa PropertyValueFactory,
PropertyValueFactory, wherewhere the
the parameter
parameter of of the
the constructor
constructor is is the
the
name
name ofof the
the property
property in in the
the class
class King
King that
that the
the cell
cell must
must contain,
contain, and
and here
here it it is name.
is name.

This e-book
is made with SETASIGN
SetaPDF

PDF components for PHP developers

www.setasign.com

63
63
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls

The
The two
two next next columns
columns are are basically
basically defined
defined in in the
the same
same way,
way, just
just the
the type
type isis this
this time
time Integer.
Integer.
However,
However, these these columns
columns are are not
not inserted
inserted directly
directly in in the
the table,
table, but
but via via another
another column
column
created
created by by the
the method
method getPeriodCol().
getPeriodCol(). Columns
Columns can can be
be nested
nested and and the the column
column created
created
by
by getPeriodCol() is a column consisting of two other columns. At the user interface, itit
getPeriodCol() is a column consisting of two other columns. At the user interface,
corresponds
corresponds to to that
that the
the column
column withwith the
the header
header Period
Period having
having two
two subcolumns,
subcolumns, respectively
respectively
from
from year
year and
and toto year.
year. InIn this
this case,
case, there
there isis no
no particular
particular reason
reason for
for itit in
in addition
addition to to showing
showing
that
that itit isis possible
possible andand what
what the
the syntax
syntax is.
is.

The
The class
class also
also creates
creates aa column
column for for the
the property
property country,
country, andand here
here isis nothing
nothing new,
new, and
and
actually
actually the
the method
method getCountryCol()
getCountryCol() isis not
not used.
used. The
The goal
goal isis to
to show
show that
that you
you do
do not
not have
have
to
to display
display all
all columns
columns in in the
the user
user interface.
interface.

Finally,
Finally, there
there isis the
the method
method getYearCol(),
getYearCol(), which
which shows
shows howhow many
many years
years that
that king
king has
has ruled,
ruled,
or
or the
the text
text Unknown
Unknown ifif you
you do
do not
not know
know the the government
government period.
period. This
This column
column isis different,
different,
as
as there
there isis no
no corresponding
corresponding property
property in
in the
the King
King class,
class, and
and the
the values
values to
to be
be displayed
displayed inin the
the
cells must therefore be calculated. This happens again using the method setCellValueFactory().
cells must therefore be calculated. This happens again using the method setCellValueFactory().
ItIt has
has the
the following
following prototype:
prototype:

setCellValueFactory(Callback<TableColumn.CellDataFeatures<S,T>,
ObservableValue<T> value)

Callback<P, R>
Callback<P, R> isis an
an interface
interface parameterized
parameterized with
with two
two types,
types, and
and the
the interface
interface defines
defines aa
single
single method
method

R call(P param)

In this
In this case
case for
for the
the column
column Year,
Year, itit means
means that
that the
the cells
cells of
of the
the column
column are
are initialized
initialized by
by aa
method
method of of the
the form
form

ObservableValue<String> call(TableColumn.CellDataFeatures<King, String> value)

which isis used


which used to
to calculate
calculate the
the years
years in
in which
which thethe king
king has
has ruled.
ruled. YouYou can
can thus
thus add
add your
your
own custom-defined
own custom-defined columns.
columns. You You should
should note
note that
that the
the value
value isis returned
returned as
as aa read-only
read-only
property, as
property, as you
you can
can not
not edit
edit such
such aa value
value in
in the
the user
user interface.
interface.

IfIf you
you run
run the
the program,
program, note
note that
that by
by default
default you
you can
can change
change the
the columns
columns width
width using
using the
the
mouse, change
mouse, change the
the order
order of
of columns,
columns, and
and sort
sort them
them by
by clicking
clicking the
the header.
header.

The next
The next example
example isis called
called MapKingProgram
MapKingProgram and
and isis essentially
essentially the
the same
same program
program and
and opens
opens
the following
the following window:
window:

64
64
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT Advanced
advanCedcontrols
Controls

and
andthat
thatis,
is,the
theprogram
programshowsshowsaaTableView
TableViewwith
with33columns
columnscorresponding
correspondingto tothree
threeproperties
properties
in the class King. However, the difference is that the objects (rows)
in the class King. However, the difference is that the objects (rows) that the componentthat the component
shows
shows are
are not
not King
King objects,
objects, but
but instead,
instead, Map<String,
Map<String, Object>
Object> objects.
objects. There
There isis no
no particular
particular
reason
reason for
for that
that in
in this
this example
example besides
besides showing
showing thethe syntax,
syntax, but
but in
in situations
situations where
where the
the rows
rows
in
in the
the table
table do
do not
not match
match aa domain
domain object,
object, the
the option
option can
can be
be used.
used.

The
The class
class King
King isis the
the same
same as
as in
in the
the previous
previous example,
example, but
but the
the class
class KingTableModel
KingTableModel has
has
been
been changed:
changed:

public class KingTableModel


{
private final ObservableList<Map<String, Object>> kings =
FXCollections.observableArrayList();

public KingTableModel()
{
int id = 0;
for (String[] arr : data)
{
King king =
new King(arr[0], Integer.parseInt(arr[1]), Integer.parseInt(arr[2]));
Map map = new HashMap<String, Object>();
map.put("id", String.format("%s%02d", king.getCountry(), ++id));
map.put("name", king.getName());
map.put("from", king.getFrom());
map.put("to", king.getTo());
kings.add(map);
}
}

65
65
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

public ObservableList<Map<String, Object>> getKings()


{
return kings;
}

public TableColumn<Map, String> getIdCol()


{
TableColumn<Map, String> col = new TableColumn("Id");
col.setCellValueFactory(new MapValueFactory("id"));
return col;
}

public TableColumn<Map, String> getNameCol()


{
TableColumn<Map, String> col = new TableColumn("Name");
col.setCellValueFactory(new MapValueFactory("name"));
return col;
}

public TableColumn<Map, Integer> getFromCol()


{
TableColumn<Map, Integer> col = new TableColumn("From");

www.sylvania.com

We do not reinvent
the wheel we reinvent
light.
Fascinating lighting offers an infinite spectrum of
possibilities: Innovative technologies and new
markets provide both opportunities and challenges.
An environment in which your expertise is in high
demand. Enjoy the supportive working atmosphere
within our global group and benefit from international
career paths. Implement sustainable ideas in close
cooperation with other specialists and contribute to
influencing our future. Come and join us in reinventing
light every day.

Light is OSRAM

66
66
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15:
JAVA 15: MORE
SOFTWARE MORE ABOUT JAVAFX:
ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT advanCed Controls
advanCed Controls

col.setCellValueFactory(new MapValueFactory("from"));
return col;
}

public TableColumn<Map, Integer> getToCol()


{
TableColumn<Map, Integer> col = new TableColumn("To");
col.setCellValueFactory(new MapValueFactory("to"));
return col;
}

private static final String[][] data = {


{ "Gorm den Gamle", "0", "958" },
{ "Harald Blåtand", "958", "987" },

};
}

First, the collection persons is this time an ObservableList with objects, which are Map<String,
Object>. The list is created in the constructor, and the difference is that this time, the Map
objects must be instantiated where the key is a String while the value is an object (a String
or an Integer). Note the keys that are created with a continuous number, but preceded the
country code.

Then there are the methods that creates the columns. Column objects are created as in the
first example, but the parameter to setCellValueFactory() is a MapValueFactory object, where
the parameter of the constructor is the key. The result is that the columns are initialized
with the values in the Map object that the key refers to.

In the method start() (the class MapKingsProgram), there are no major changes, and I do
not want to show the code here, but after the table has been created and initialized with
columns, two statements have been added:

table.setTableMenuButtonVisible(true);
idCol.setVisible(false);

where idCol is the name of the first column with the rows id (and thus the key). The first
where idCol is the name of the first column with the rows id (and thus the key). The first
statement indicates that it should be possible to hide columns, while the second statement
statement indicates that it should be possible to hide columns, while the second statement
indicates that
indicates that idCol
idCol should
should be
be hidden
hidden from
from startup.
startup. If
If you
you run
run the
the program,
program, you
you can
can notice
notice
that in
that in the
the header
header line
line above
above the
the scroll
scroll bar
bar there
there is
is aa small
small plus.
plus. If
If you
you click
click on
on it,
it, you’ll
you’ll get
get
a little popup where you can click from or to if the individual columns should be hidden.
a little popup where you can click from or to if the individual columns should be hidden.

67
67
67
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls

The next example is called RenderKingsProgram and opens the following window:

and will show you how to define how the content of the individual cells should be displayed.
In this case, the content of the From column appear as blank if the value is 0 corresponding
to the meaning that you do not know the start of the king’s government period. The same
applies to the To column if the value is 9999. In addition, the two columns are right-
aligned. Finally, the last column shows the value of the property country as a checkbox that
is checked if the value is DK.

The objects that are displayed again have the type King, and the most important changes
are again in the class KingTableModel:

public class KingTableModel


{
private final ObservableList<King> kings = FXCollections.observableArrayList();

68
68
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

public TableColumn<King, Integer> getFromCol()


{
TableColumn<King, Integer> col = new TableColumn("From");
col.setCellValueFactory(new PropertyValueFactory("from"));
col.setCellFactory(c -> {
TableCell<King, Integer> cell = new TableCell<King, Integer>()
{
@Override
public void updateItem(Integer item, boolean empty)
{
super.updateItem(item, empty);
this.setText(null);
this.setGraphic(null);
if (!empty && item != 0) this.setText("" + item);
}
};

360°
return cell;
});

.
col.setPrefWidth(60);

thinking
col.setStyle("-fx-alignment: CENTER_RIGHT;");
col.getStyleClass().add("salary-header");
return col;
}

360°
thinking . 360°
thinking .
Discover the truth at www.deloitte.ca/careers Dis

© Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers © Deloitte & Touche LLP and affiliated entities.

Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers


69
69
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT advanCed Controls
advanCed Controls

public TableColumn<King, Boolean> getCountryCol()


public TableColumn<King, Boolean> getCountryCol()
{
{
TableColumn<King, Boolean> col = new TableColumn<>("Danish");
TableColumn<King, Boolean> col = new TableColumn<>("Danish");
col.setCellValueFactory(cell -> {
col.setCellValueFactory(cell -> {
King king = cell.getValue();
King king = cell.getValue();
return new ReadOnlyBooleanWrapper(king.getCountry().equals("DK"));
return new ReadOnlyBooleanWrapper(king.getCountry().equals("DK"));
});
});
col.setCellFactory(CheckBoxTableCell.<King>forTableColumn(col));
col.setCellFactory(CheckBoxTableCell.<King>forTableColumn(col));
return col;
return col;
}
}

private static final String[][] data = {


private static final String[][] data = {
{{ "Gorm
"Gorm den
den Gamle",
Gamle", "0",
"0", "958"
"958" },
},
……
};
};
}
}

The
The start
The start of
start of the
of the class
the class is
class is essentially
is essentially the
essentially the same
the same as
same as in
as in the
in the first
the first example.
first example. That
example. That is,
That is, the
is, the construter,
the construter, the
construter, the
the
method
method getKing()
method getKing() and
getKing() and the
and the method
the method getNamCol()
method getNamCol() are
getNamCol() are unchanged
are unchanged and
unchanged and are
and are therefore
are therefore not
therefore not shown
not shown
shown
above.
above. However,
above. However, the
However, the method
the method getFromCol()
method getFromCol() is
getFromCol() is different.
is different. It
different. It still
It still has
still has to
has to return
to return aaa TableColumn
return TableColumn
TableColumn
for
for the
for the property
the property from,
property from, and
from, and this
and this column
this column object
column object is
object is created
is created as
created as before,
as before, but
before, but then
but then the
then the method
the method
method
setCellFactory()
setCellFactory() is
setCellFactory() is used
is used to
used to tell
to tell how
tell how the
how the value
the value should
value should be
should be displayed.
be displayed. This
displayed. This happens
This happens with
happens with aaa
with
TableCell
TableCell object,
TableCell object, which
object, which is
which is an
is an interface
an interface that
interface that defines
that defines aaa method
defines method update().
method update(). The
update(). The method
The method has
method has as
has as
as
parameter,
parameter, the
parameter, the object
the object to
object to be
to be rendered,
be rendered, and
rendered, and aaa boolean
and boolean that
boolean that tells
that tells if
tells ifif the
the cell
the cell is
cell is empty.
is empty. If
empty. If there
If there
there
isis aaa non-zero
is non-zero content,
non-zero content, it
content, it is
it is used
is used to
used to update
to update the
update the cell.
the cell. After
cell. After being
After being associated
being associated with
associated with aaa TableCell,
with TableCell,
TableCell,
aaa column
column is
column is assigned
is assigned aaa preferred
assigned preferred width
preferred width and
width and aaa style
and style is
style is attached
is attached to
attached to the
to the column
the column and
column and to
and to its
to its
its
header,
header, where
header, where the
where the last
the last is
last is defined
is defined in
defined in aaa style
in style sheet.
style sheet. The
sheet. The method
The method getToCol()
method getToCol() is
getToCol() is written
is written in
written in the
in the
the
same
same way
same way and
way and does
and does not
does not appear
not appear here.
appear here.
here.

Then
Then there
Then there is
there is method
is method getCountryCol(),
method getCountryCol(), which
getCountryCol(), which creates
which creates aaa TableColumn
creates TableColumn for
TableColumn for Boolean
for Boolean objects.
Boolean objects. A
objects. A
A
CellValueFactory
CellValueFactory is
CellValueFactory is assigned
is assigned to
assigned to specify
to specify which
specify which value
which value aaa King
value King object
King object should
object should result
should result in,
result in, depending
in, depending
depending
on
on the
on the value
the value of
value of the
of the country
the country property.
country property. Is
property. Is it
Is it DK,
it DK, the
DK, the value
the value must
value must be
must be true
be true and
true and otherwise
and otherwise false.
otherwise false.
false.
You
You should
You should note
should note that
note that the
that the value
the value wrappers
value wrappers in
wrappers in aaa read-only
in read-only property,
read-only property, and
property, and the
and the reason
the reason is
reason is that
is that the
that the
the
TableView
TableView component
TableView component should
component should be
should be able
be able to
able to bind
to bind to
bind to the
to the value.
the value. Finally,
value. Finally, aaa CellFactory
Finally, CellFactory is
CellFactory is associated
is associated
associated
with
with the
with the column
the column telling
column telling how
telling how the
how the value
the value should
value should be
should be displayed
be displayed and
displayed and that
and that it
that it should
it should be
should be like
be like aaa
like
CheckBoxTableCell,
CheckBoxTableCell, which
CheckBoxTableCell, which is
which is aaa wrapper
is wrapper for
wrapper for aaa checkbox.
for checkbox. Note
checkbox. Note that
Note that you
that you also
you also indicate
also indicate that
indicate that the
that the
the
checkbox
checkbox must
checkbox must be
must be initialized
be initialized with
initialized with the
with the value
the value in
value in the
in the current
the current column.
current column.
column.

Then
Then there
Then there is
there is the
is the main
the main program
main program with
program with the
with the method
the method start():
method start():
start():

public void
public void start(Stage
start(Stage stage)
stage)
{{
TableView<King> table = new TableView(model.getKings());
TableView<King> table = new TableView(model.getKings());

70
70
70
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

table.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
table.getSelectionModel().setCellSelectionEnabled(false);
table.getSelectionModel().getSelectedIndices().addListener(
(ListChangeListener.Change<? extends Integer> change) -> {
String text = "";
List<Integer> list = table.getSelectionModel().getSelectedIndices();
for (Integer n : list) text += n + " ";
System.out.println(text);
});
table.getColumns().addAll(model.getNameCol(), model.getFromCol(),
model.getToCol(), model.getCountryCol());
BorderPane root = new BorderPane(table);
root.setPadding(new Insets(10, 10, 10, 10));
Scene scene = new Scene(root, 450, 300);
scene.getStylesheets().add("resources/css/styles.css");
stage.setScene(scene);
stage.setTitle("Show kings");
stage.show();
}

It
It looks
looks like
like the
the above
above examples,
examples, but but should
should show
show aa little
little about
about how
how toto select
select rows.
rows. First,
First,
you
you should be able to select MULTIPLE, and you should not be able to select single cells.
should be able to select MULTIPLE, and you should not be able to select single cells.
Next, an event handler that fires every time you change selection. The handler
Next, an event handler that fires every time you change selection. The handler is trivial is trivial
and
and does
does nothing
nothing but
but write
write aa text
text on
on the
the console,
console, aa text
text that
that shows
shows the
the indexes
indexes of
of the
the rows
rows
that are selected.
that are selected.

EXERCISE
EXERCISE 3
3
The
The database
database padata
padata contains
contains aa table
table zipcode
zipcode with
with Danish
Danish zip
zip codes.
codes. You
You must
must write
write aa program
program
that
that you can call PostProgram. The program should only show the content of the database
you can call PostProgram. The program should only show the content of the database
table
table in a TableView, and you should not do anything specifically about the formatting of
in a TableView, and you should not do anything specifically about the formatting of
the individual columns (there are only
the individual columns (there are only two).two).

3.2
3.2 EDIT
EDIT CELLS
CELLS IN
IN A
A TABLEVIEW
TABLEVIEW
II will
will now
now showshow anan example
example that,
that, in
in principle,
principle, looks
looks like
like the
the above
above examples,
examples, but
but where
where
you
you can edit the content of the individual cells. Although it may not be surprisingly new,
can edit the content of the individual cells. Although it may not be surprisingly new,
it
it is still relatively simple. In general, it works that way that you double-click on the cell
is still relatively simple. In general, it works that way that you double-click on the cell
you want to edit, after which the cell opens with the option of changing
you want to edit, after which the cell opens with the option of changing the value. When the value. When
the
the cell
cell is
is opened,
opened, it it happens
happens by
by the
the cell
cell shows
shows another
another control
control that
that basically
basically can
can be
be

71
71
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls

1.
1. CheckBoxTableCell (see the previous example)
2.
2. ChoiceBoxTableCell
3.
3. ComboBoxTableCell
4.
4. TextFieldTableCell

and you can also define your own controls. To show how it works, I will use another object
type this time, which is a class that represents a Person:

public class Person implements Comparable<Person>


{
private static int ID = 0;
private final ReadOnlyIntegerWrapper id = new ReadOnlyIntegerWrapper();
private final StringProperty name = new SimpleStringProperty();
private final StringProperty job = new SimpleStringProperty();
private final StringProperty gender = new SimpleStringProperty();
private final IntegerProperty year = new SimpleIntegerProperty();
private final DoubleProperty salary = new SimpleDoubleProperty();
private final BooleanProperty weekly = new SimpleBooleanProperty();
private final ObjectProperty<LocalDate> date = new SimpleObjectProperty();

We will turn your CV into


an opportunity of a lifetime

Do you like cars? Would you like to be a part of a successful brand? Send us your CV on
We will appreciate and reward both your enthusiasm and talent. www.employerforlife.com
Send us your CV. You will be surprised where it can take you.

72
72
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:15:
SOFTWARE MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT advanCed
advanCed Controls
Controls

publicPerson(String
public Person(Stringname,
name,String
Stringjob,
job,String
Stringgender,
gender,Integer
Integeryear,
year,
Double salary, Boolean weekly, LocalDate date)
Double salary, Boolean weekly, LocalDate date)
{{
id.set(++ID);
id.set(++ID);
setName(name);
setName(name);
……
}}

It’s
It’saa astandard
It’s standardJavaFX JavaFX
JavaFX modelmodel
model class, so so
class,
class, I so
doI not
Idodoshow
not the
notshow
show details here.
thedetails
the detailsThe class
here.
here. Theis an
The extension
class
class is isanan
of the class
extension
extension Person
ofof theclass
the thatPerson
class I havethat
Person used inhave
thatI Ihavetheused
previous
usedininthe chapter,
the previous
previous butchapter,
this time,
chapter, objects
but
but are assigned
thistime,
this time, objects
objects
aare
are current
assigned
assigned IDa arepresented
currentID
current asrepresented
a readonlyasas
IDrepresented property.
a areadonly
readonlyIn property.
fact, the In
property. interpretation
Infact,
fact,the of the last four
theinterpretation
interpretation ofof
properties,
thethelastlastfour
fouritproperties,
is not important,
properties, notbut
it itis isnot it couldbut
important,
important, be
butitbirth
itcouldyear
could (for
bebe year),
birth
birth yearsalary
year (for salary
(foryear),
(for year), salary) and
salary(for(for
whether
salary)and
salary) the
and salary the
whether
whether istheweeklysalaryor
salary monthly
weeklyoror(for
is isweekly weekly).
monthly
monthly Finally,
(for
(for weekly).
weekly). the last property
Finally,
Finally, thelast
the could
lastproperty
property be
interpreted as the date
couldbebeinterpreted
could interpreted oftheemployment.
asasthe The important
dateofofemployment.
date employment. is not the
Theimportant
The important interpretation,
is isnot
notthe but that
theinterpretation,
interpretation,
the
but parameters
butthatthatthe have different
theparameters
parameters types. Iftypes.
havedifferent
have different you run
types. therun
IfIfyou
you program,
runthe the result
theprogram,
program, thecould
the resultbe
result as shown
could
could bebeasas
below,
shownbelow,
shown where allwhere
below,where values except
allallvalues
valuesexceptthe Id the
except column can becan
theIdIdcolumn
column edited. The
canbebeedited. Add
edited. The button
The isbutton
Addbutton
Add usedisto add
isused
used
toatonew
addaddarowanew torow
new the
rowto table,
tothe thus
thetable,
table, creating a Person,
thuscreating
thus creating while
a aPerson, the
Person,while Remove
while buttonbutton
theRemove
the Remove is usedis isto
button delete
used
used toto
the
delete
delete row that
the
the row
row isthat
selected.
thatis isselected.
selected.

In
In addition
additiontoto
Inaddition the
tothe class
theclass Person,
classPerson, the
Person,the project
theproject has
hasaaaclass
projecthas class called
classcalled PersonModel:
calledPersonModel:
PersonModel:

packageeditpersonsprogram;
package editpersonsprogram;
import java.time.LocalDate;
import java.time.LocalDate;
import javafx.collections.FXCollections;
import javafx.collections.FXCollections;
importjavafx.collections.ObservableList;
import javafx.collections.ObservableList;

public class PersonsModel


public class PersonsModel
{{
private final ObservableList<Person> persons =
private final ObservableList<Person> persons =
FXCollections.observableArrayList();
FXCollections.observableArrayList();

73
7373
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE
SOFTWARE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls
SOFTWARE DEVELOPMENT advanCed Controls

public PersonsModel()
public PersonsModel()
{
{
initialize();
initialize();
}
}

public ObservableList<Person> getPersons()


public ObservableList<Person> getPersons()
{
{
return persons;
return persons;
}
}

public void add()


public void add()
{
{
persons.add(new Person("", "", "", null, null, true, null));
persons.add(new Person("", "", "", null, null, true, null));
}
}

public void remove(int n)


public void remove(int n)
{
{
persons.remove(n);
persons.remove(n);
}
}

private void initialize()


private void initialize()
{
{


}
}
}
}

which represents
which represents the
the persons
persons onon whom
whom thethe program
program is is working.
working. The
The method
method initialize()
initialize()
which represents the persons on whom the program is working. The method initialize()
creates 66 persons,
creates persons, so
so the
the table
table is
is not
not empty
empty when
when the
the program
program starts.
starts. Note
Note that
that the
the objects
objects
creates 6 persons, so the table is not empty when the program starts. Note that the objects
are stored
are stored inin an
an ObservableList
ObservableList to to Person
Person objects
objects and
and note
note how
how the
the methods
methods add()
add() and
and
are stored in an ObservableList to Person objects and note how the methods add() and
remove() maintains
remove() maintains this
this list.
list.
remove() maintains this list.

Otherwise II want
Otherwise want to
to start
start with
with the
the class
class EditPersonsProgram:
EditPersonsProgram:
Otherwise I want to start with the class EditPersonsProgram:
public class EditPersonsProgram extends Application
public class EditPersonsProgram extends Application
{
{
private PersonsModel model = new PersonsModel();
private PersonsModel model = new PersonsModel();
private TableView<Person> table = null;
private TableView<Person> table = null;

@Override
@Override
public void start(Stage stage)
public void start(Stage stage)
{
{
table = new TableView(model.getPersons());
table = new TableView(model.getPersons());
PersonTableModel cols = new PersonTableModel();
PersonTableModel cols = new PersonTableModel();
table.getColumns().addAll(cols.getIdCol(), cols.getNameCol(),
table.getColumns().addAll(cols.getIdCol(), cols.getNameCol(),
cols.getJobCol(), cols.getGenderCol(), cols.getYearCol(),
cols.getJobCol(), cols.getGenderCol(), cols.getYearCol(),
cols.getSalaryCol(), cols.getWeeklyCol(), cols.getDateCol());
cols.getSalaryCol(), cols.getWeeklyCol(), cols.getDateCol());
table.setEditable(true);
table.setEditable(true);

74
74
74
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

BorderPane root = new BorderPane(table, null, null, createBottom(), null);


root.setPadding(new Insets(10, 10, 10, 10));
Scene scene = new Scene(root);
scene.getStylesheets().add("resources/css/styles.css");
stage.setScene(scene);
stage.setTitle("Show kings");
stage.show();
}

private Pane createBottom()


{
HBox pane = new HBox(20, createButton("Test", this::test),
createButton("Remove", this::remove), createButton("Add", e -> model.add()));
pane.setAlignment(Pos.CENTER_RIGHT);
pane.setPadding(new Insets(10, 0, 0, 0));
return pane;
}

private Button createButton(String text, EventHandler<ActionEvent> handler)


{
Button cmd = new Button(text);
cmd.setOnAction(handler);
return cmd;
}

�e Graduate Programme
I joined MITAS because for Engineers and Geoscientists
I wanted real responsibili� www.discovermitas.com
Maersk.com/Mitas �e G
I joined MITAS because for Engine
I wanted real responsibili� Ma

Month 16
I was a construction Mo
supervisor ina const
I was
the North Sea super
advising and the No
Real work he
helping foremen advis
International
al opportunities
Internationa
�ree wo
work
or placements ssolve problems
Real work he
helping fo
International
Internationaal opportunities
�ree wo
work
or placements ssolve pr

75
75
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT advanCed Controls
SOFTWARE DEVELOPMENT advanCed Controls

private void remove(ActionEvent e)


private void remove(ActionEvent e)
{
{
int row = table.getSelectionModel().getSelectedIndex();
int row = table.getSelectionModel().getSelectedIndex();
if (row >= 0)
if (row >= 0)
{
{
model.remove(row);
model.remove(row);
table.getSelectionModel().clearSelection();
table.getSelectionModel().clearSelection();
}
}
}
}

private void test(ActionEvent e)


private void test(ActionEvent e)
{
{
for (Person p : model.getPersons()) System.out.println(p);
for (Person p : model.getPersons()) System.out.println(p);
System.out.println();
System.out.println();
}
}

public static void main(String[] args)


public static void main(String[] args)
{
{
launch(args);
launch(args);
}
}
}
}

The class starts by defining a model object – not for the TableView component, but for
The
The class
class starts
starts by
by defining
defining aa model
model object
object –– not
not for
for the
the TableView
TableView component,
component, butbut for
for
the data that the program needs to maintain. In addition, a TableView for Person objects
the
the data
data that
that the
the program
program needs
needs toto maintain.
maintain. In
In addition,
addition, aa TableView
TableView for
for Person
Person objects
objects
are defined. In the method start() where the table is created, there is not much new to
are
are defined.
defined. In
In the
the method
method start()
start() where
where the
the table
table is
is created,
created, there
there is
is not
not much
much new
new to
to
explain, but you should note that the table columns are created by methods in a class
explain, but you should note that the table columns are created by methods
explain, but you should note that the table columns are created by methods in a class in a class
PersonTableModel this time. Finally, note that the table is defined as editable:
PersonTableModel
PersonTableModel this
this time.
time. Finally,
Finally, note
note that
that the
the table
table is
is defined
defined as
as editable:
editable:
table.setEditable(true);
table.setEditable(true);

and that’s all you need to edit the cells if a column relates to read/write property and if the
and that’s
and that’s all
all you
you need
need to to edit
edit the cells
cells if
if aa column
column relates
relates to
to read/write
read/write property
property and ifif the
the
column has a CellFactory that isthe
a TableCell control. You should also note the eventand
handlers
column has
column has aa CellFactory
CellFactory that
that is aa TableCell
TableCell control.
control. You
You should
should also
also note
note the
the event
event handlers
where the Add button handleris is trivial, while the handler for the Remove button handlers
requires
where the
where the Add
Add button
button handler
handler isis trivial,
trivial, while
while thethe handler
handler for
for the
the Remove
Remove button
button requires
requires
you to determine the index for the row that is selected. Finally, there is the handler for the
you to
you to determine
determine thethe index for
for the
the row
row that is is selected.
selected. Finally,
Finally, there isis the handler for
for the
Test button, which onindex
the console printsthat
the objects in the list. there
The goaltheofhandler
this handlertheis
Test button,
Test button, which
which onon the
the console
console prints
prints the
the objects
objects in
in the
the list.
list. The
The goal
goal of
of this
this handler
handler isis
to test whether there is consistency with what the TableView control shows and what the
to test
to test whether
whether there
there isis consistency with
with what the the TableView
TableView control
control shows
shows and
and what
what the
the
model contains. It is to consistency
show that changeswhat in the TableView control automatically updates
model contains.
model contains. ItIt is
is to
to show
show that
that changes
changes in in the
the TableView
TableView control
control automatically
automatically updates
updates
the model.
the model.
the model.

Then there is the class PersonTableModel that has methods that create the table columns.
Then there
Then there is
is the
the class
class PersonTableModel
PersonTableModel that
that has
has methods
methods that
that create
create the
the table columns.
On the other hand, it is also the most complex of the program’s classes. table columns.
On the
On the other
other hand,
hand, it
it is
is also
also the
the most
most complex
complex of
of the
the program’s
program’s classes.
classes.

76
76
76
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

public class PersonTableModel


{
public TableColumn<Person, Integer> getIdCol()
{
TableColumn<Person, Integer> idCol = new TableColumn("Id");
idCol.setCellValueFactory(new PropertyValueFactory("id"));
return idCol;
}

public TableColumn<Person, String> getNameCol()


{
TableColumn<Person, String> col = new TableColumn("Name");
col.setCellValueFactory(new PropertyValueFactory("name"));
col.setCellFactory(TextFieldTableCell.<Person>forTableColumn());
return col;
}

public TableColumn<Person, String> getJobCol()


{

}

public TableColumn<Person, String> getGenderCol()


{
TableColumn<Person, String> col = new TableColumn("Gender");
col.setCellValueFactory(new PropertyValueFactory("gender"));
col.setCellFactory(ChoiceBoxTableCell.<Person, String>forTableColumn(
"Male", "Female"));
return col;
}

public TableColumn<Person, Integer> getYearCol()


{
TableColumn<Person, Integer> col = new TableColumn("Year");
col.setCellValueFactory(new PropertyValueFactory("year"));
col.setCellFactory(ComboBoxTableCell.<Person,
Integer>forTableColumn(new YearConverter(), getYears()));
return col;
}

public TableColumn<Person, Double> getSalaryCol()


{
TableColumn<Person, Double> col = new TableColumn("Salary");
col.setCellValueFactory(new PropertyValueFactory("salary"));
col.setCellFactory(TextFieldTableCell.<Person,
Double>forTableColumn(new SalaryConverter()));
col.setOnEditCommit((TableColumn.CellEditEvent<Person, Double> e) -> {
int row = e.getTablePosition().getRow();

77
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

Person person = e.getTableView().getItems().get(row);


if (Math.abs(e.getNewValue()) < 0.1)
{
e.getTableView().getItems().set(row, person);
}
else person.setSalary(e.getNewValue());
});
col.setPrefWidth(100);
col.setStyle("-fx-alignment: CENTER_RIGHT;");
col.getStyleClass().add("salary-header");
return col;
}

public TableColumn<Person, Boolean> getWeeklyCol()


{
TableColumn<Person, Boolean> col = new TableColumn("Weekly");
col.setCellValueFactory(new PropertyValueFactory("weekly"));
col.setCellFactory(CheckBoxTableCell.<Person>forTableColumn(col));
return col;
}

78
78
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

public TableColumn<Person, LocalDate> getDateCol()


{
TableColumn<Person, LocalDate> col = new TableColumn("Date");
col.setCellValueFactory(new PropertyValueFactory("date"));
col.setCellFactory(DatePickerTableCell.<Person>forTableColumn());
return col;
}

private ObservableList<Integer> getYears()


{
int year = LocalDate.now().getYear() – 10;
ObservableList<Integer> list = FXCollections.observableArrayList();
for (int y = year – 90; y < year; ++y) list.add(y);
return list;
}
}

class YearConverter extends StringConverter<Integer>


{
@Override
public Integer fromString(String string)
{
try
{
return Integer.parseInt(string);
}
catch (Exception ex)
{
return 0;
}
}

@Override
public String toString(Integer value)
{
return value == 0 ? "" : "" + value;
}
}

class SalaryConverter extends StringConverter<Double>


{
@Override
public Double fromString(String string)
{
try
{
return Double.parseDouble(string);
}

79
79
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

catch (Exception ex)


{
return 0.0;
}
}

@Override
public String toString(Double value)
{
return Math.abs(value) < 0.1 ? "" :
String.format("%1.2f", value.doubleValue());
}
}

The
The first
first method
method returns
returns aa TableColumn
TableColumn for
for the
the column
column idid and
and is
is the
the simplest,
simplest, and
and all
all you
you
need to note is that it does not have a CellFactory as the column is not editable.
need to note is that it does not have a CellFactory as the column is not editable.

The
The two
two next
next methods
methods areare in
in principle
principle identical,
identical, as
as in
in both
both cases
cases it
it is
is aa column
column whose
whose
values
values are
are text.
text. Therefore,
Therefore, they
they have
have aa CellFactory
CellFactory which
which isis aa TextFieldTableCell,
TextFieldTableCell, and
and the
the
result is if you double-click in a cell in these columns, a TextField control opens
result is if you double-click in a cell in these columns, a TextField control opens where the where the
content
content can
can bebe edited.
edited. You
You should
should note
note that
that it
it is
is the
the method
method forTableColumn()
forTableColumn() that
that opens
opens
the
the entry
entry field.
field.

Then
Then there
there isis the
the method
method getGenderCol()
getGenderCol() that
that returns
returns aa TableColumn
TableColumn forfor the
the Gender
Gender column.
column.
It has a CellFactory of the type ChoiceBoxTableCell, and the result is, if you
It has a CellFactory of the type ChoiceBoxTableCell, and the result is, if you double-click double-click
in
in aa cell,
cell, aa ChoiseBox
ChoiseBox with
with two
two values:
values: Male
Male and
and Female,
Female, where
where the
the user
user cancan select
select aa value.
value.
Here
Here you
you must
must note
note the
the method
method forTableColumn(),
forTableColumn(), which
which asas parameters
parameters has has the
the values
values for
for
which the ChoiceBox control should be initialized.
which the ChoiceBox control should be initialized.

The
The next
next method
method isis for
for the
the year
year column,
column, andand it
it uses
uses aa ComboBoxTableCell
ComboBoxTableCell with with the
the result
result
that
that the
the cell
cell opens
opens aa ComboBox.
ComboBox. The The class
class has
has aa private
private method
method that
that creates
creates an
an ObservableList
ObservableList
with
with the years to be selected. It is used as a parameter for forTableColumn(), but there
the years to be selected. It is used as a parameter for forTableColumn(), but there is
is also
also
aa YearConverter parameter (as defined at the end of the file). There is generally
YearConverter parameter (as defined at the end of the file). There is generally an override an override
of
of forTableColumn(),
forTableColumn(), wherewhere you
you cancan specify
specify aa converter
converter asas parameter,
parameter, and
and in
in this
this case
case it
it is
is
only
only to
to ensure
ensure that
that aa missing
missing year
year isis not
not displayed
displayed asas 0.
0.

Then
Then there
there isis the
the method
method getSalaryCol(),
getSalaryCol(), which
which returns
returns aa TableColumn
TableColumn for for aa Double,
Double, and
and
where
where it it should
should be be possible
possible to
to edit
edit aa Double.
Double. Here
Here are
are several
several things
things to
to notice.
notice. First,
First, as
as
CellFactory,
CellFactory, aa TextFieldTableCell
TextFieldTableCell isis used
used toto enter
enter aa random
random decimal
decimal number.
number. In In order
order for
for
the result to look nice, a converter of the type SalaryConveter, which shows
the result to look nice, a converter of the type SalaryConveter, which shows a Double with a Double with
two
two decimal,
decimal, is is attached
attached –– but
but only
only if
if the
the number
number isis not
not 0.
0. If
If that
that happens,
happens, the
the result
result will
will
appear
appear asas blank.
blank. When
When the
the user
user enters
enters aa number,
number, they
they can
can of
of course
course enter
enter something
something illegal,
illegal,
and
and if
if that
that is
is the
the case
case (the
(the entered
entered can
can not
not be
be converted
converted toto aa number),
number), anan exception
exception appears
appears

80
80
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Advanced controls

with the result that the value is set to 0. However, the problem is that the model is then
updated with the value 0, which is not really the thought, but the model should retains
the old value. The problem is solved by adding an event handler that is executed when the
entry is completed (and the TextField component closes). If the value is 0, the old value
is set, and otherwise the new value. Reintroducing the old value looks a bit weird and in
fact the model still has the old value, but the user interface is not updated. The problem
is solved by assigning the Person object to itself, which means that the model fires an event
that updates the user interface. As the last, the column content is right aligned, but it is
the same as in the previous example.

Then there is the method getWeeklyCol() that uses a CheckBoxTableCell. Here is not much
new, but note the parameter for forTableColumn(), which is the column to be edited.

Finally, there is getDateCol(), and the goal of this method is to show a column that uses a
custom CellFactory. It is a DatePickerTableCell since it is desired that the user should get a
DatePicker by double-clicking the cell. A custom CellFactory is a class that implements the
interface TableCell and otherwise has a control of the desired kind (in this case a DatePicker).
The class must be able to override the following methods

In the past 5 years we have drilled around

95,000 km
—that’s more than twice around the world.

Who are we?


We are the world’s leading provider of reservoir characterization,
drilling, production, and processing technologies to the oil and
gas industry.

Who are we looking for?


We offer countless opportunities in the following domains:
n Operations
n Research, Engineering, and Manufacturing
n Geoscience and Petrotechnical
n Commercial and Business

We’re looking for high-energy, self-motivated graduates


with vision and integrity to join our team. What will you be?

careers.slb.com

81
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCed controls
Controls

--- startEdit()
startEdit()
--- commitEdit()
commitEdit()
--- cancelEdit()
cancelEdit()
--- updateItem()
updateItem()

but
but otherwise
otherwise the
the class
class consists
consists of
of constructors
constructors and
and static
static forTableColumn()
forTableColumn() methods.
methods. Below,
Below,
only
only the
the overriding
overriding methods
methods ofof the
the class
class are
are shown:
shown:

public class DatePickerTableCell<S, T> extends TableCell<S, LocalDate>


{
private DatePicker datePicker;
private StringConverter converter = null;
private boolean editable = true;

@Override
public void startEdit()
{
if (!isEditable() || !getTableView().isEditable() ||
!getTableColumn().isEditable()) return;
super.startEdit();
if (datePicker == null) this.createDatePicker();
setGraphic(datePicker);
}

@Override
public void cancelEdit()
{
super.cancelEdit();
setText(converter.toString(getItem()));
setGraphic(null);
}

@Override
public void updateItem(LocalDate item, boolean empty)
{
super.updateItem(item, empty);
if (empty)
{
setText(null);
setGraphic(null);
}
else
{

82
82
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

if (this.isEditing())
{
if (datePicker != null) datePicker.setValue((LocalDate)item);
setText(null);
setGraphic(datePicker);
}
else
{
setText(converter.toString(item));
setGraphic(null);
}
}
}

When you run the program, including editing persons as well as creating new ones and
deleting existing ones, please note that the model is automatically updated and the window
is automatically updated (Add and Remove buttons). All this happens because of bidirectional
bindings. To test that the window has the Test button.

PROBLEM 2
You must solve the same task as in problem 1, but the user interface should be as shown in
the window below, where the individual persons appear as a row in a TableView. Clicking
the Add button will add a new person (where all fields are blank) to the list and if you
click the Remove button, the person selected must be deleted. All cells must be editable and
for the Name, Title, Birth, and Death columns, a TextFieldTableCell should be used, while
for the Country column a ComboBoxTableCell should be used. The database has a table
country, and the combobox must be initialized with all the country codes from this table.
Back there is column Text, where the cells must be edited with a TextArea control and thus
a custom TableCell. Note that it may mean that you need to add one way or another to
finish entering text, for example, by typing F12.

A particular problem is when physically writing to the database. You can of course write
each time you create a person and delete a person, but writing each time you edit a cell may
not be appropriate. You can therefore choose a different strategy, where you write back all
changes when you click on a button. That’s the purpose of the Save button. In my solution,
I simply update all rows (with a batch update) when clicking on the Save button. That’s

83
83
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Advanced controls

probably the easy solution, as it means I’ll update all rows, regardless of whether they are
changed. Perhaps you can find a better solution?

84
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Advanced
advanCed controls
Controls

3.3 FILTERS
3.3 FILTERS
One of the important features of a JTable is the use of filters, and with a TableView, it’s
all a bit easier. A TableView shows the content of an ObersvableList and you can set a filter
with a filter wrapper to the list and encapsulated in a sort wrapper. To conclude this review
of the TableView component, I will show an example that sets a filter.

The example is called FilterKingsProgram and I want to reuse objects of the type King, and
the data model for the TableView component is essentially unchanged from previously and
will not be shown here.

The window’s code is:

public class FilterKingsProgram extends Application


{
private TextField txtName = new TextField();

@Override
public void start(Stage stage)
{
TableView<King> table = new TableView();
table.getColumns().addAll(KingTableModel.getNameCol(),
KingTableModel.getFromCol(), KingTableModel.getToCol());
initialize(table);
BorderPane root = new BorderPane(table, null, null, createBottom(), null);
root.setPadding(new Insets(10, 10, 10, 10));
Scene scene = new Scene(root, 500, 400);
stage.setScene(scene);
stage.setTitle("Show kings");
stage.show();
}

private void initialize(TableView table)


{
FilteredList<King> filter =
new FilteredList<>(KingTableModel.getKings(), king -> true);
txtName.textProperty().addListener((observable, oldValue, newValue) ->
{
filter.setPredicate(king ->
{
if (newValue == null || newValue.isEmpty()) return true;
String lowerCaseFilter = newValue.toLowerCase();
if (king.getName().toLowerCase().contains(lowerCaseFilter)) return true;
return false;
});
});

85
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

SortedList<King> sorter = new SortedList<>(filter);


sorter.comparatorProperty().bind(table.comparatorProperty());
table.setItems(sorter);
}

private Pane createBottom()


{
HBox pane = new HBox(10, new Label("Filter for name"), txtName);
pane.setPadding(new Insets(10, 0, 0, 0));
return pane;
}

public static void main(String[] args)


{
launch(args);
}
}

There is
There is nothing
nothing newnew inin the
the start()
start() method,
method, andand the
the new
new is is done
done in in the
the method
method initialize(),
initialize(),
which initializes
which initializes the
the table
table control.
control. Note
Note first
first that
that aa filter
filter isis created
created forfor the
the data
data to
to be
be shown
shown
in the
in the table,
table, and
and the
the type
type for
for aa filter
filter is
is FilteredList.
FilteredList. Next,
Next, aa listener
listener must
must be be associated
associated with
with
the input
the input field,
field, which
which is is defined
defined as as aa predicat
predicat for
for the
the filter,
filter, and
and asas in
in this
this case
case returns
returns true
true if
if
aa King
King object’s
object’s name
name property
property contains
contains the the value
value of
of the
the input
input field
field –– without
without distinguishing
distinguishing
between upper
between upper andand lowercase
lowercase letters.
letters. Finally
Finally the
the filter
filter is
is inserted
inserted in in aa wrapper
wrapper as as aa SortedList,
SortedList,
which has
which has aa comparator
comparator thatthat binds
binds to to the
the table’s
table’s comparator.
comparator. Finally,
Finally, aa sorter
sorter object
object isis used
used
as the
as the data
data model
model forfor the
the table.
table.

If you
If you run
run the
the program,
program, youyou get
get the
the following
following window,
window, where
where at
at the
the bottom
bottom there
there is
is aa entry
entry
field used
field used to
to enter
enter aa filter
filter for
for the
the Name
Name column:
column:

86
86
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Advanced controls

EXERCISE 4
Create a copy of the project PostProgram from exercise 3. You need to expand the program
so it has a filter for both zip code and city name:

Excellent Economics and Business programmes at:

“The perfect start


of a successful,
international career.”

CLICK HERE
to discover why both socially
and academically the University
of Groningen is one of the best
places for a student to be
www.rug.nl/feb/education

87
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Advanced controls

3.4 A TREEVIEW CONTROL


JavaFX also has an TreeView control, which corresponds to a JTree from Swing and is a
control that visualizes hierarchical data. Basically, there are two classes TreeItem and TreeView,
the first representing an element in the tree, while the latter is the actual component. A
TreeItem is either a composite or a leaf and it is determined by whether it has child elements.

The program ShowWorldProgram shows some of the world’s countries organized in a hierarchy:

Above, all continents in these world, which all of the Antarctica are composite nodes, as
are shown with the arrow, showing that it is a node with child nodes and that it can be
expanded by clicking the arrow with the mouse. Below is the same window where Asia and
North America are expanded (you should note that the component automatically displays
a scrollbar when necessary):

A TreeView shows data defined in a model, which is a hierarchy of TreeItem elements, and
in this case, the model is defined in the method build():

88
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

package showworldprogram;

import javafx.scene.control.*;

public class TreeWorldModel


{
private TreeItem<String> root = new TreeItem("This World");

public TreeWorldModel()
{
build();
}

public TreeItem<String> getData()


{
return root;
}

private void build()


{
TreeItem<String> af = new TreeItem("Africa");
af.getChildren().addAll(new TreeItem("South Africa"), new TreeItem("Namibia"),
new TreeItem("Botswana"), new TreeItem("Zimbabwe"));
TreeItem<String> an = new TreeItem("Antarctica");
TreeItem<String> as = new TreeItem("Asia");
as.getChildren().addAll(new TreeItem("China"), new TreeItem("India"),
new TreeItem("Japan"));
TreeItem<String> eu = new TreeItem("Europe");
eu.getChildren().addAll(new TreeItem("Denmark"), new TreeItem("Norway"),
new TreeItem("Sweden"));
TreeItem<String> na = new TreeItem("North America");
na.getChildren().addAll(new TreeItem("Canada"), new TreeItem("Mecico"),
new TreeItem("United States"));
TreeItem<String> oc = new TreeItem("Oceania");
oc.getChildren().addAll(new TreeItem("Australia"),
new TreeItem("New Zealand"));
TreeItem<String> sa = new TreeItem("South Amaerica");
sa.getChildren().addAll(new TreeItem("Argentina"), new TreeItem("Brazil"),
new TreeItem("Chile"), new TreeItem("Bolivia"), new TreeItem("Peru"));
root.getChildren().addAll(af, an, as, eu, na, oc, sa);
}
}

89
89
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT advanCed controls
Advanced Controls

The code
The code for
for the
the program
program isis quite
quite simple:
simple:

package showworldprogram;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.*;
import javafx.scene.control.*;
import javafx.stage.Stage;
import javafx.geometry.*;

public class ShowWorldProgram extends Application


{
@Override
public void start(Stage primaryStage)
{
TreeView view = new TreeView((new TreeWorldModel()).getData());
view.setShowRoot(false);
BorderPane root = new BorderPane(view);
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root, 300, 300);
primaryStage.setTitle("The World!");
primaryStage.setScene(scene);

American online
LIGS University
is currently enrolling in the
Interactive Online BBA, MBA, MSc,
DBA and PhD programs:

▶▶ enroll by September 30th, 2014 and


▶▶ save up to 16% on the tuition!
▶▶ pay in 10 installments / 2 years
▶▶ Interactive Online education
▶▶ visit www.ligsuniversity.com to
find out more!

Note: LIGS University is not accredited by any


nationally recognized accrediting agency listed
by the US Secretary of Education.
More info here.

90
90
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE DEVELOPMENT advanCed Controls

primaryStage.show();
}

public static void main(String[] args)


{
launch(args);
}
}

and there
and there is
is nothing
nothing to
to explain.
explain. However,
However, you
you must
must note
note that
that with
with setShowRoot()
setShowRoot() II defined
defined
that the
that the root
root of
of the
the tree
tree should
should not
not be
be displayed.
displayed. You
You can
can try
try to
to set
set aa comment
comment inin front
front
of the
of the line
line and
and see
see what
what happens.
happens.

The
The next example
next example is
is called
called MaintainWorldProgram
MaintainWorldProgram and
and is
is aa variation
variation of
of the
the above
above program
program
and
and opens the
opens the following
following window:
window:

As shown
As shown byby the
the buttons,
buttons, one
one of
of the
the differences
differences is
is that
that you
you should
should also
also be
be able
able to
to edit
edit the
the
content of
content of the
the tree:
tree:

1. Clicking
1. Clicking the
the Add
Add button
button adds
adds aa node
node to
to the
the item
item that
that has
has been
been selected
selected –
– if
if it
it is
is
not aa leaf
not leaf node
node
2. Clicking
2. Clicking onon the
the Delete
Delete button
button deletes
deletes the
the node
node that
that is
is selected,
selected, but
but only
only if
if it
it is
is aa
leaf node
leaf node
3. Double-clicking
3. Double-clicking aa leaf
leaf node
node will
will allow
allow you
you to
to change
change the
the name
name

91
91
JAVA 15:
JAVA 15:
JAVA MORE
15: MORE ABOUT JAVAFX:
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT advanCed Controls
advanCed controls
Advanced Controls

Finally, there
Finally, there
Finally, is
is aaa button
there is button Test
button Test that
Test that only
that only makes
makes itit
only makes possible
it possible to
possible to print
to print the
print the number
the number
number ofof leaf
of leaf nodes
leaf nodes
nodes
in the
in the
in tree,
the tree, and
tree, and you
and you should
you should note
should note that
note that it is
that itit is number
is number
number of of leaf
of leaf nodes
leaf nodes in
nodes in the
in the TreeView
the TreeView component’s
TreeView component’s
component’s
model, and
model, and
model, the
and the button
the button
button isis used
is used to
used to test
to test that
test that
that thethe above
the above operations
above operations not
operations not only
not only update
only update the
update the TreeView
the TreeView
TreeView
controller but
controller but
controller also
but also the
also the model.
the model.
model.

The program
The program
The should
program should also
should also show
also show something
show something about
something about what
about what events
what events occurs
events occurs when
occurs when you
when you use
use aaa TreeView.
you use TreeView.
TreeView.

The model
The model
The for
model for the
for the TreeView
the TreeView component
TreeView component is
component is the
is the same
the same as
same as in
as in the
in the previous
the previous example
previous example and
example and
and isis not
is not
not
shown here.
shown here.
shown The
here. The class
The class MaintainWorldProgram,
class MaintainWorldProgram,
MaintainWorldProgram, onon the
on the other
the other hand,
other hand, fills
fills aaa part,
hand, fills part, so
so III will
part, so will just
will just
just
show the
show the
show code
the code for
code for the
for the most
the most important
most important methods.
important methods.
methods.

The method
The method
The start()
method start() is
start() is essentially
is essentially unchanged,
essentially unchanged, but
unchanged, but there
but there are
there are now
are now instance
now instance variables
instance variables for
variables for both
for both
both
the TreeView
the TreeView
the control
TreeView control and
control and the
and the model:
the model:
model:

public class MaintainWorldProgram extends Application


public class MaintainWorldProgram extends Application
{
{
private TreeWorldModel model = new TreeWorldModel();
private TreeWorldModel model = new TreeWorldModel();
private TreeView<String> view;
private TreeView<String> view;

Otherwise,
Otherwise, most
Otherwise, most important
most important in
important in the
in the method
the method start()
method start() are
start() are that
that itit
are that calls
calls aaa method
it calls method addHandlers(),
method addHandlers(),
addHandlers(),
which
which adds
which adds event
adds event handlers
event handlers to
handlers to the
to the TreeView
the TreeView component:
TreeView component:
component:

private
private voidvoid addHandlers()
addHandlers()
{
{

model.getData().addEventHandler(TreeItem.<Str
m odel.getData().addEventHandler(TreeItem.<Str
ing>branchExpandedEvent(), e -> );
ing>branchExpandedEvent(), e -> );

model.getData().addEventHandler(TreeItem.<Stri
m odel.getData().addEventHandler(TreeItem.<Stri
ng>branchCollapsedEvent(), e -> );
ng>branchCollapsedEvent(), e -> );

model.getData().addEventHandler(TreeItem.<Str
m odel.getData().addEventHandler(TreeItem.<Str
ing>childrenModificationEvent(), );
ing>childrenModificationEvent(), );

model.getData().addEventHandler(TreeItem.<St
m odel.getData().addEventHandler(TreeItem.<St
ring>valueChangedEvent(), e -> );
ring>valueChangedEvent(), e -> );
view.setOnMouseClicked(new EventHandler<MouseEvent>()
view.setOnMouseClicked(new EventHandler<MouseEvent>()
{
{
@Override
@Override

public void handle(MouseEvent mouseEvent)
public void handle(MouseEvent mouseEvent)
{
{

if(mouseEvent.getClickCount() == 2)
if(mouseEvent.getClickCount() == 2)
{
{

TreeItem<String> item = view.getSelectionModel().getSelectedItem();
TreeItem<String> item = view.getSelectionModel().getSelectedItem();
if (item
if (item !=
!= null)
null) modify(item);
modify(item);
}
}
}
}
});
});
}
}

92
92
92
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT advanCed controls
Advanced Controls

There are
There are aa total
total of
of 55 event
event handlers.
handlers. TheThe names
names tell
tell you
you whenwhen thethe event
event handlers
handlers are
are
performed. The
performed. The first
first three
three (where
(where only
only the
the code
code for
for first
first is
is shown)
shown) does
does nothing
nothing but
but print
print
aa text
text on
on the
the console.
console. The
The fourth
fourth uses
uses aa method
method printModel()
printModel() that that prints
prints the
the contents
contents of
of aa
subtree on
subtree on the
the console
console and
and actually
actually prints
prints the
the entire
entire tree.
tree. Its
Its purpose
purpose is is to
to show
show that
that the
the model
model
is updated
is updated and
and you
you are
are encouraged
encouraged toto examine
examine thethe code.
code. TheThe last
last event
event handler
handler concerns
concerns
the mouse
the mouse and
and tests
tests for
for double
double click
click with
with the
the mouse.
mouse. If If so,
so, isis executed
executed thethe method
method modify():
modify():

private void modify(TreeItem<String> item)


{
if (item.isLeaf())
{
TextInputDialog dialog = new TextInputDialog(item.getValue());
dialog.setTitle("Modify country");
dialog.setHeaderText("Change the country's name");
Optional<String> result = dialog.showAndWait();
if (result.isPresent())
{
String name = result.get().trim();
if (name.length() > 0) item.setValue(name);
}
view.getSelectionModel().clearSelection();
}
}

93
93
JAVA
JAVA15:
JAVA 15:MORE
15: MOREABOUT
MORE ABOUTJAVAFX:
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT Advanced
advanCedcontrols
advanCed Controls
Controls

In
In the
the case
case of
of aa leaf
leaf node,
node, aa simple
simple TextInputDialog
TextInputDialog opens
opens where
where you
you can
can change
change the
the value.
value.
Doing
Doing so, so, updates
updates the the current
current TreeItem,
TreeItem, and
and you
you should
should note
note that
that itit also
also updates
updates the
the
user
user interface.
interface.

The
The event
event handler
handler for
for the
the Add
Add button
button isis in
in principle
principle identical,
identical, while
while the
the event
event handler
handler for
for
the
the Remove
Remove button
button is:
is:

private void remove(ActionEvent e)


private void remove(ActionEvent e)
{
{
TreeItem<String> item = view.getSelectionModel().getSelectedItem();
TreeItem<String> item = view.getSelectionModel().getSelectedItem();
if (item != null && item.isLeaf() && item.getParent() != null)
if (item != null && item.isLeaf() && item.getParent() != null)
{
{
TreeItem<String> parent = item.getParent();
TreeItem<String> parent = item.getParent();
parent.getChildren().remove(item);
parent.getChildren().remove(item);
view.getSelectionModel().clearSelection();
view.getSelectionModel().clearSelection();
}
}
}
}

Here you
Here you should
should notenote how
how to
to refer
refer to
to the
the item
item that
that isis selected
selected and
and again
again that
that the
the user
user
interface isis automatically
interface automatically updated.
updated. The
The last
last event
event handler
handler isis about
about the
theTest
Test button
button counting
counting
the number
the number of of leaf
leaf nodes
nodes and
and then
then opening
opening an an Alert
Alert with
with thethe result.
result.

Inthe
In theabove
aboveexample,
example,the
thecontent
contentof
ofaaTreeItem
TreeItemare areedited
editedbybyopening
openingaasimple
simpleTextInputDialog,
TextInputDialog,
but you
but you can
can also
also edit
edit the
the content
content inline
inline likelike aa TableView.
TableView. ItIt isis used
used inin the
the example
example
EditWorldProgram. The
EditWorldProgram. The user
user interface
interface isis the
the same
same asas above,
above, but
but there
there isis aa minor
minor change
change to
to
the
the model:
model:

public class TreeWorldModel


public class TreeWorldModel
{
{
private TreeItem<String> root = new TreeItem("This World");
private TreeItem<String> root = new TreeItem("This World");

public TreeWorldModel()
public TreeWorldModel()
{
{
build();
build();
}
}

public TreeItem<String> getData()


public TreeItem<String> getData()
{
{
return
return root;
root;
}
}

public
public void
void add(TreeItem<String>
add(TreeItem<String> parent)
parent)
{
{
parent.getChildren().add(new
parent.getChildren().add(new TreeItem(""));
TreeItem(""));
}
}

94
94
94
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
SOFTWARE MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
DEVELOPMENT Advanced controls
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT advanCed
advanCed Controls
Controls

public void remove(TreeItem item)


{
item.getParent().getChildren().remove(item);
}

}

The
The method
method start()
start() is:
is:

public void start(Stage primaryStage)


{
view = new TreeView(model.getData());
view.setShowRoot(false);
view.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
view.setEditable(true);
view.setCellFactory(TextFieldTreeCell.forTreeView());
view.setOnEditStart(this::start);
view.setOnEditCommit(this::commit);
view.setOnEditCancel(this::cancel);
BorderPane root = new BorderPane(view, null, null, createCommands(), null);
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root, 350, 400);
primaryStage.setTitle("This World");
primaryStage.setScene(scene);
primaryStage.show();
}

Here
Here you
you should
should notenote that
that the
the TreeView
TreeView component
component must must bebe defined
defined as as editable,
editable, andand in
in
addition,
addition, aa CellFactory
CellFactory must
must bebe attached,
attached, as
as here
here is
is aa TextFieldTreeCell.
TextFieldTreeCell. This
This means
means that
that ifif
you
you double-click
double-click on on aa TreeItem,
TreeItem, aa TextField
TextField opens,
opens, allowing
allowing you
you to
to edit
edit the
the content.
content. Just
Just as
as
you’ve
you’ve seen
seen itit for
for aa TableView,
TableView, there
there are
are also
also other
other CellFactory
CellFactory types
types that
that can
can be be used
used for
for
other
other data
data types.
types. There
There are
are also
also associated
associated three
three event
event handlers
handlers that
that do
do nothing
nothing but but print
print
aa text
text on
on the
the console
console and
and in
in the
the example
example they
they are
are used
used to
to show
show that
that the
the first
first is
is executed
executed
when
when the
the entry
entry field
field opens
opens while
while the
the other
other two
two are
are executed
executed depending
depending on on whether
whether youyou
quit
quit with
with Enter
Enter or or ESC.
ESC.

The
The method
method createCommands()
createCommands() creates
creates aa Pane
Pane with
with the
the three
three buttons,
buttons, and
and the
the associated
associated
event
event handlers
handlers are
are all
all simple
simple and
and use
use the
the two
two new
new methods
methods in
in the
the model.
model.

95
95
95
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 55

EXERCISE
EXERCISE 55
The
The database
database padata
padata has
has four
four tables
tables that
that contain
contain information
information about
about Danish
Danish regions,
regions, Danish
Danish
municipalities
municipalitiesand
andDanish
Danishzipzipcodes,
codes,while
whilethe
thefourth
fourthtable
tablerepresents
representsaamany-many
many-manyrelationship
relationship
between
between municipality
municipality and
and zipcode.
zipcode. The
The four
four tables
tables were
were created
created with
with the
the following
following script:
script:

create table region


(
regnr int not null primary key,
name varchar(30) not null
);

create table municipality


(
munnr int not null primary key,
name varchar(30) not null,
regnr int not null,
area decimal(10, 2),
number int,
year int,
foreign key (regnr) references region(regnr)
);

96
96
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

create table zipcode


(
code char(4) not null primary key,
city varchar(30) not null
);

create table post


(
code char(4) not null,
munnr int not null,
primary key (code, munnr),
foreign key (code) references zipcode(code),
foreign key (munnr) references municipality(munnr)
);

You must
You must write
write aa program
program that
that you
you can
can call
call Denmark,
Denmark, which
which displays
displays this
this data
data in
in an
an TreeView.
TreeView.
Note that
Note that the
the program
program only
only should
should display
display names,
names, but
but you
you should
should not
not be
be able
able to
to edit
edit the
the
content. When
content. When the the program
program starts,
starts, you
you should
should see
see the
the following
following window:
window:

and below
and below the
the same
same window
window after
after the
the root,
root, Region
Region Midtjylland
Midtjylland and
and the
the municipality
municipality Holstebro
Holstebro
are expanded:
are expanded:

97
97
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 5

3.5 A TREEVIEW WITH COUNTRY OBJECTS


As a final example of using a TreeView, I will show a program called UpdateWorldProgram.
The program is similar to the previous one, but partly the individual objects are of a
custom type and not just strings, and partly there are more data. The database padata (see,
if applicable, the book Java 6) contains three tables that contain data about currencies,
continents and countries:

where the last two columns in the country table are foreign keys. The program will show
an overview of all countries, but organized in an TreeView, and where it should be possible
to edit the information about a country. If you open the program, you get the following
window where North America is expanded:

For example, if you double-click on the United States, you will see the following window
where you can edit data about the United States:

98
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 5

The two comboboxes contains all continents and all currencies, respectively, and are used to
change a country’s currency or continent. Note that the above window with the TreeView
component does not show all the world’s countries as only the countries in the database
where a foreign key to the table world is included. You should also note that the program
does not provide opportunities to create new countries or delete existing countries, but of
course it would be easy to expand the program with these features.

Join the best at Top master’s programmes


• 3
 3rd place Financial Times worldwide ranking: MSc
the Maastricht University International Business
• 1st place: MSc International Business
School of Business and • 1st place: MSc Financial Economics
• 2nd place: MSc Management of Learning

Economics! • 2nd place: MSc Economics


• 2nd place: MSc Econometrics and Operations Research
• 2nd place: MSc Global Supply Chain Management and
Change
Sources: Keuzegids Master ranking 2013; Elsevier ‘Beste Studies’ ranking 2012;
Financial Times Global Masters in Management ranking 2012

Maastricht
University is
the best specialist
university in the
Visit us and find out why we are the best! Netherlands
(Elsevier)
Master’s Open Day: 22 February 2014

www.mastersopenday.nl

99
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15: MORE
15:
SOFTWARE MORE ABOUT JAVAFX:
ABOUT JAVAFX:
DEVELOPMENT eXerCIse 5
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT eXerCIse 55
Exercise

As a first step, model classes must be written to the three database tables. For currency, it
As aa first
As first step,
step, model
model classes
classes must
must be
be written
written to
to the
the three
three database
database tables.
tables. For
For currency,
currency, itit
is the following class:
is the
is the following
following class:
class:
public class Currency
public class Currency
{
{
private ReadOnlyStringWrapper code = new ReadOnlyStringWrapper(this, "code");
private ReadOnlyStringWrapper code = new ReadOnlyStringWrapper(this, "code");
private ReadOnlyStringWrapper name = new ReadOnlyStringWrapper(this, "name");
private ReadOnlyStringWrapper name = new ReadOnlyStringWrapper(this, "name");

where II have
where have not included
included the column
column for exchange
exchange rates. Since
Since the information
information can not
not be
where I have not
not included the
the column for
for exchange rates.
rates. Since the
the information can
can not be
be
changed, both
changed, both properties
properties are
are defined
defined readonly.
readonly. The
The table
table world
world uses
uses the
the following
following model
model class:
class:
changed, both properties are defined readonly. The table world uses the following model class:
public class World
public class World
{
{
private ReadOnlyStringWrapper code = new ReadOnlyStringWrapper(this, "code");
private ReadOnlyStringWrapper code = new ReadOnlyStringWrapper(this, "code");
private StringProperty name = new SimpleStringProperty();
private StringProperty name = new SimpleStringProperty();

In
In the
the program,
program, itit should
should not
not be
be possible
possible to
to change
change the
the name
name ofof aa continent,
continent, but
but when
when
In the program, it should not be possible to change the name of a continent, but when
the
the property name is defined read/write, it is because the class Country is defined as
property name is defined read/write, it is because the class Country is defined as aa
the property name is defined read/write, it is because the class Country is defined as a
derivative
derivative class:
class:
derivative class:
public class Country extends World
public class Country extends World
{
{
private IntegerProperty area = new SimpleIntegerProperty();
private IntegerProperty area = new SimpleIntegerProperty();
private IntegerProperty inhabitants = new SimpleIntegerProperty();
private IntegerProperty inhabitants = new SimpleIntegerProperty();
private StringProperty world = new SimpleStringProperty();
private StringProperty world = new SimpleStringProperty();
private StringProperty currency = new SimpleStringProperty();
private StringProperty currency = new SimpleStringProperty();

The
The reason
reason is
is primarily
primarily that
that aa TreeView
TreeView basically
basically contains
contains elements
elements of
of the
the same
same type,
type, as
as
The reason is primarily that a TreeView basically contains elements of the same type, as
in
in this
this case
case is
is World,
World, and
and the
the tree
tree can
can therefore
therefore also
also immediately
immediately contain
contain Country
Country objects.
objects.
in this case is World, and the tree can therefore also immediately contain Country objects.

With
With these
these model
model classes
classes in
in place,
place, II have
have the
the following
following data
data model:
model:
With these model classes in place, I have the following data model:
public class Model
public class Model
{
{
private ObservableList<World> worlds =
private ObservableList<World> worlds =
FXCollections.observableArrayList();
FXCollections.observableArrayList();
private ObservableList<Currency> currencies =
private ObservableList<Currency> currencies =
FXCollections.observableArrayList();
FXCollections.observableArrayList();

private ObservableList<Country> countries =

private ObservableList<Country> countries =
FXCollections.observableArrayList();
FXCollections.observableArrayList();

public Model()
public Model()
{
{
load();
load();
}
}

100
100
100
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

public ObservableList<World> getWorlds()


{
return worlds;
}

public ObservableList<Currency> getCurrencies()


{
return currencies;
}

public ObservableList<Country> getCountries()


{
return countries;
}

public World getWorld(String code)


{
for (World world : worlds) if (world.getCode().equals(code)) return world;
return null;
}

public Currency getCurrency(String code)


{
for (Currency currency : currencies) if (currency.getCode().equals(code))
return currency;
return null;
}

private void load()


{

}

public void save()


{

}

The constructor
The constructor calls
calls the
the method
method load(),
load(), which
which initializes
initializes the
the three
three lists
lists by
by reading
reading the
the content
content
of the
of the database.
database. II have
have not
not displayed
displayed the
the code
code for
for load(),
load(), but
but itit only
only contains
contains simple
simple database
database
operations. It
operations. It should
should also
also be
be possible
possible to
to write
write the
the changes
changes thatthat the
the program
program returns
returns toto the
the
database, and
database, and therefore
therefore the
the method
method save().
save(). When
When examining
examining the the code,
code, note
note that
that it
it writes
writes
all countries
all countries back
back with
with aa batch
batch update.
update. It
It might
might be be aa little
little exaggerated,
exaggerated, andand it
it could
could easily
easily
be solved
be solved by
by expanding
expanding the the class
class Country
Country with
with an
an additional
additional Boolean
Boolean property
property that
that could
could
be set
be set to
to true
true when
when aa value
value was
was changed.
changed. For
For the
the class
class Model,
Model, youyou should
should also
also note
note the
the

101
101
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 55

methods
methods getWorld()
getWorld() and
and getCurrency()
getCurrency() that
that from
from the
the continent’s
continent’s code
code and
and the
the currency
currency code,
code,
respectively,
respectively, returns
returns the
the corresponding
corresponding object.
object. ItIt isis used
used when
when editing
editing data
data for
for aa country.
country.

The
The class
class TreeModel
TreeModel isis data
data model
model forfor the
the TreeView
TreeView component
component and and isis not
not much
much more more than
than
aa thin
thin layer
layer between
between the
the Model
Model class
class and
and the
the user
user interface,
interface, but
but its
its task
task isis to
to arrange
arrange the
the
data
data from
from the
the model
model layer
layer in
in aa hierarchy
hierarchy of of TreeItem
TreeItem objects:
objects:

public class TreeModel


{
private Model model = new Model();
private TreeItem<World> root = new TreeItem(new World("", "This world"));

public TreeModel()
{
build();
}

public Model getModel()


{
return model;
}

102
102
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

public TreeItem getData()


{
return root;
}

public void save()


{
model.save();
}

private void build()


{
List<TreeItem<World>> worlds = new ArrayList();
for (World world : model.getWorlds()) worlds.add(new TreeItem(world));
for (Country country : model.getCountries())
{
for (TreeItem<World> item : worlds)
if (item.getValue().getCode().equals(country.getWorld()))
{
item.getChildren().add(new TreeItem(country));
break;
}
}
root.getChildren().addAll(worlds);
}
}

With
With these
these 5 5 classes
classes in
in place,
place, the
the program’s
program’s classes
classes can
can be
be written
written for
for the
the main
main window
window
and
and the dialog box. Since none of these classes in principle contains something new, II do
the dialog box. Since none of these classes in principle contains something new, do
not want to show the code here, but you are encouraged to study the code,
not want to show the code here, but you are encouraged to study the code, and the dialog and the dialog
is
is not
not quite
quite simple
simple and,
and, among
among other,
other, it
it complicates
complicates the
the task
task changing
changing the
the continent
continent for
for aa
country,
country, asas it
it means
means that
that the
the country
country has
has to
to be
be moved
moved in in the
the tree.
tree. To
To resolve
resolve this,
this, delete
delete
the old node and create a new one somewhere else, and note that the visual
the old node and create a new one somewhere else, and note that the visual representation representation
of
of the
the tree
tree is
is automatically
automatically updated.
updated.

3.6
3.6 AA TREETABLEVIEW
TREETABLEVIEW
JavaFX
JavaFX also
also has
has aa TreeTableView
TreeTableView control,
control, which
which can can be
be characterized
characterized asas aa combination
combination of of
aa TableView
TableView and TreeView. This corresponds to that the component as a TreeView shows aa
and TreeView. This corresponds to that the component as a TreeView shows
hierarchy
hierarchy ofof objects,
objects, but
but where
where each
each object
object appears
appears as as aa row
row of
of multiple
multiple values
values and
and thus
thus
more columns. It sounds complicated and is it, too, but the component works
more columns. It sounds complicated and is it, too, but the component works in principle in principle
like
like the
the previous
previous ones,
ones, though
though there
there are
are more
more sophistry
sophistry forfor the
the programming.
programming. II willwill start
start
with a simple example that will show the basic syntax and I will again
with a simple example that will show the basic syntax and I will again use data about use data about

103
103
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 55

countries
countries organized
organized in
in aa hierarchy
hierarchy where
where aa country’s
country’s parent
parent isis the
the continent
continent to
to which
which the
the
country
country belongs
belongs (and
(and itit isis assumed
assumed –– not
not entirely
entirely correct
correct –– that
that countries
countries belong
belong to
to one
one
particular
particular continent).
continent). If
If you
you runrun the
the program,
program, you
you will
will see
see the
the window
window below,
below, where
where This
This
World
World and
and Asia
Asia are
are expanded.
expanded.

That
That is,
is, for
for each
each country,
country, name,
name, area
area and
and number
number ofof inhabitants
inhabitants are
are displayed.
displayed. Here
Here you
you
should
should note
note that
that aa number
number for
for area
area and
and inhabitants
inhabitants isis shown,
shown, ifif the
the row
row isis aa continent,
continent,
which
which isis the
the sum
sum ofof the
the corresponding
corresponding numbers
numbers for
for child
child nodes.
nodes.

The
The program
program isis called
called ShowCountriesProgram
ShowCountriesProgram andand uses
uses two
two model
model classes
classes called
called World
World
and
and Country.
Country. These
These classes
classes are
are identical
identical to
to the
the corresponding
corresponding classes
classes in
in the
the program
program
UpdateWorldProgram
UpdateWorldProgram andand should
should not
not be
be mentioned
mentioned further.
further. The
The class
class CountriesModel
CountriesModel defines
defines
aa model
model for
for the
the TreeTableView
TreeTableView component:
component:

public class CountriesModel


{
private TreeItem<Country> root =
new TreeItem(new Country("", "This World", null, null, null, null));

public CountriesModel()
{
build();
}

public TreeItem<Country> getData()


{
return root;
}

public TreeTableColumn<Country, String> getNameCol()


{

104
104
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

TreeTableColumn<Country, String> col = new TreeTableColumn<>("Name");


col.setCellValueFactory(new TreeItemPropertyValueFactory("name"));
col.setPrefWidth(200);
return col;
}

public TreeTableColumn<Country, Long> getAreaCol()


{
TreeTableColumn<Country, Long> col = new TreeTableColumn<>("Area");
col.setCellValueFactory(new SumValueFactory("area"));
col.setCellFactory(new LongFactory());
col.setStyle("-fx-alignment: CENTER_RIGHT;");
col.getStyleClass().add("salary-header");
col.setPrefWidth(100);
return col;
}

public TreeTableColumn<Country, Long> getInhabitantsCol()


{
TreeTableColumn<Country, Long> col = new TreeTableColumn<>("Inhabitants");
col.setCellValueFactory(new SumValueFactory("inhabitants"));
col.setCellFactory(new LongFactory());
col.setStyle("-fx-alignment: CENTER_RIGHT;");

105
105
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

col.getStyleClass().add("salary-header");
col.setPrefWidth(100);
return col;
}

private void build()


{
TreeItem<Country> af =
new TreeItem(new Country("AF", "Africa", null, null, null, null));
af.getChildren().add(new TreeItem(new
Country("ZAF", "South Africa", 1221037L,
54956900L, "AF", "ZAR")));

root.getChildren().addAll(af, an, as, eu, na, oc, sa);
}

class LongFactory implements


Callback<TreeTableColumn<Country, Long>, TreeTableCell<Country, Long>>
{
@Override
public TreeTableCell<Country, Long> call(TreeTableColumn<Country, Long> col)
{
return new TreeTableCell<Country, Long>()
{
@Override
public void updateItem(Long item, boolean empty)
{
super.updateItem(item, empty);
this.setText(null);
this.setGraphic(null);
if (!empty && item != 0) this.setText("" + item);
}
};
}
}

class SumValueFactory implements



Callback<TreeTableColumn.CellDataFeatures<Country,
Long>, ObservableValue<Long>>
{
private String field;
private long sum = 0;

public SumValueFactory(String field)


{
this.field = field;
}

106
106
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Exercise 5
SOFTWARE DEVELOPMENT eXerCIse 5

@Override
public ObservableValue<Long>
call(TreeTableColumn.CellDataFeatures<Country, Long> cellData)
{
TreeItem<Country> item = cellData.getValue();
if (item.getValue().getWorld() == null ||
item.getValue().getWorld().length() == 0)
{
sum = 0;
calculate(item);
return new SimpleLongProperty(sum).asObject();
}
return new TreeItemPropertyValueFactory<Cou

ntry, Long>(field).call(cellData);
}

private void calculate(TreeItem<Country> item)


{
sum += getValue(item.getValue());
for (TreeItem<Country> child : item.getChildren())
if (child.getValue().getCode().length() == 3)
sum += getValue(child.getValue());
else calculate(child);
}

private long getValue(Country country)


{
if (field.equals("area"))
return country.getArea() == null ? 0 : country.getArea();
return country.getInhabitants() == null ? 0 : country.getInhabitants();
}
}
}

The class immediately looks like model classes for the other components (TableView and
The class immediately looks like model classes for the other components (TableView and
TreeView) and consists primarily of methods that return column objects. The constructor
TreeView) and consists primarily of methods that return column objects. The constructor
calls a method load(), where I have only shown few statements, but the method organizes
calls a method load(), where I have only shown few statements, but the method organizes
data for 20 countries in a hierarchy under continents. Aside from the fact that the code fills
data for 20 countries in a hierarchy under continents. Aside from the fact that the code fills
a part, there is nothing mysterious in the code. You should note that a country consists of
a part, there is nothing mysterious in the code. You should note that a country consists of
more data than the program shows, and the class CountryModel actually has a column method
more data than the program shows, and the class CountryModel actually has a column method
for each data column. Above, I have only included the methods for the three columns used
for each data column. Above, I have only included the methods for the three columns used
by the program. There is no particular reason not to show all columns besides pointing out
by the program. There is no particular reason not to show all columns besides pointing out
that of course it is not necessary.
that of course it is not necessary.

107
107
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 5

Similar to the columns for the two previous controls, a CellValueFactory object is associated
with which a parameter specifies where to retrieve the individual values. The name of the
property is specified by the specific objects to be displayed, and here it are Country objects.
A CellValueFactory thus indicates which values should be displayed in the columns cells.
For the name column, a TreeItemPropertyValueFactory uses the content of the individual
cells as a Label containing the value. The type TreeItemPropertyValueFactory implements a
Callback interface, and you can therefore type your own CellValueFactory as a class that
implements this interface if you want to determine the value of the columns cells. I have
done that for the next two columns in the form of the class SumValueFactory. The class
has a parameter field, which is the name of the property in the class Country to which the
column relates. The goal is that the same class should apply for both columns Area and
Inhabitants. Otherwise, the class consists primarily of overriding the method call(), which is
defined by the interrface Callback. The method has parameters that represent the current cell
in the model, and tests whether the cell contains a Country that does not have a reference
to a continent. If that is the case, the object itself represents a continent and the method
calls the method calculate() which determines the sum of all child object values for the
current property. You should note that the method calculate() is recursive, and that is why
the root of the tree shows the sum of all the world’s countries. If the current cell is not for
a continent, the value is determined by a default TreeItemPropertyValueFactory.

Need help with your


dissertation?
Get in-depth feedback & advice from experts in your
topic area. Find out what you can do to improve
the quality of your dissertation!

Get Help Now

Go to www.helpmyassignment.co.uk for more info

108
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 55

AA column
column may
may also
also be
be associated
associated with
with aa CellFactory,
CellFactory, and and while
while aa CellValueFactory
CellValueFactory determines
determines
the
the value,
value, aa CellFactory
CellFactory determines
determines which
which object
object will
will display
display the
the value.
value. The
The meaning
meaning of of aa
CellFactory
CellFactory isis to
to associate
associate an
an object
object that
that isis used
used to to edit
edit the
the content
content of of the
the cell
cell (something
(something
to
to be treated in the next example), but in this case, a CellFactory is used simply to
be treated in the next example), but in this case, a CellFactory is used simply to display
display
00 values
values as
as blank
blank (what
(what could
could also
also be
be achieved
achieved with with aa converter).
converter). TheThe content
content ofof aa cell
cell isis
aa TreeTableCell
TreeTableCell object,
object, and
and the
the class
class LongFactory
LongFactory isis aa CellFactory
CellFactory (implementing
(implementing aa Callback
Callback
interface)
interface) that implements the method call(), so it returns a TreeTableCell where the method
that implements the method call(), so it returns a TreeTableCell where the method
updateItem() is overridden.
updateItem() is overridden.

The
The above
above code
code can
can be
be difficult
difficult to
to understand,
understand, butbut ifif you
you think
think on,
on, that
that aa TreeTableView,
TreeTableView,
like
like a TableView and an TreeView, is based on a data model and where the model
a TableView and an TreeView, is based on a data model and where the model (for
(for
aa TreeTableView) should organize data in a hierarchy and define the individual
TreeTableView) should organize data in a hierarchy and define the individual columns columns
then
then it’s
it’s not
not that
that bad
bad again
again and
and happily
happily happening
happening the the same
same way
way every
every time.
time. Have
Have you
you
first
first written
written thethe model,
model, then
then the
the rest
rest goes
goes by
by itself,
itself, and
and for
for this
this example
example isis the
the code
code of
of the
the
method start():
method start():

public void start(Stage primaryStage)


{
TreeTableView<Country> view = new TreeTableView<>(model.getData());
view.getColumns().addAll(model.getNameCol(), model.getAreaCol(),
model.getInhabitantsCol());
BorderPane root = new BorderPane(view);
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root, 500, 300);
scene.getStylesheets().add("resources/css/styles.css");
primaryStage.setTitle("This World");
primaryStage.setScene(scene);
primaryStage.show();
}

109
109
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 5

3.7 A TREETABLEVIEW, AN EXTENDED EXAMPLE

To conclude this chapter, I will show an example similar to the above, but showing countries
created in the database padata, where you can also edit the countries, create new and delete
a country, but such that a country is edited inline, as shown for a TableView in the example
EditPersonProgram. The current example is called UpdateCountriesProgram and opens the
above window, where the row with the name Other countries contains the countries from
the database that are not located under a continent and where the column Code displays
the country code with three characters. In fact, the model actually has two more columns,
showing the country code as two characters, and partly showing the currency code. In order
to simplify the program a bit, I have not loaded the table of currencies from the database
and the program therefore does not validate the codes that are entered. If you enter an
none existing currency code, that country can not be updated due to the foreign key in
the database. Therefore, the column is hidden by default.

In fact, it’s not easy to edit the content of the individual cells in a TreeTableView, and the
result easily leads to many lines of code, as is the case in the current example – and it does
not even work anywhere. I do not want to show the code here, but just highlight the key
things that you should be aware of when studying the code.

The class World is unchanged compared to the previous examples. The class Country, on
the other hand, has changed a bit, consisting of adding a property code3 to the country
code of three characters, and then the type for the two properties area and inhabitants are
changed to Long. The reason is that the world’s population is so large that it can not be
represented by an int.

110
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Exercise
eXerCIse 55

The class Model is similar to the corresponding class in the program UpdateWorldProgram, but
with the difference that, as mentioned, that this time it did not include the database table
currency. The class has as previously a method load(), which loads the two tables world and
country and creates two ObservableList objects for these data. This time, a ListChangeListener
has been added to the list of countries that observe events regarding changes to list contents:

public class Model


{
private Callback<Country, Observable[]> cb = (Country c) ->
new Observable[] { c.nameProperty(),
c.areaProperty(), c.inhabitantsProperty(),c.
worldProperty(), c.currencyProperty() };
private ObservableList<World> worlds = FXCollections.observableArrayList();
private ObservableList<Country> countries =
FXCollections.observableArrayList(cb);

public Model()
{
load();
countries.addListener(new CountryChangeListener());
}

Brain power By 2020, wind could provide one-tenth of our planet’s


electricity needs. Already today, SKF’s innovative know-
how is crucial to running a large proportion of the
world’s wind turbines.
Up to 25 % of the generating costs relate to mainte-
nance. These can be reduced dramatically thanks to our
systems for on-line condition monitoring and automatic
lubrication. We help make it more economical to create
cleaner, cheaper energy out of thin air.
By sharing our experience, expertise, and creativity,
industries can boost performance beyond expectations.
Therefore we need the best employees who can
meet this challenge!

The Power of Knowledge Engineering

Plug into The Power of Knowledge Engineering.


Visit us at www.skf.com/knowledge

111
111
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT Exercise
eXerCIse55

This
Thisevent
eventhandler
handlerisisused
usedtotoupdate
updatethe
thedatabase,
database,andandthus,
thus,asasininthe
theprogram
programUpdateWorldProgram,
UpdateWorldProgram,
aa batch
batch update
update isis not
not used,
used, which
which uncritically
uncritically writes
writes all
all countries
countries back
back to
to the
the database.
database. In
In
the
the current
current application,
application, physical
physical data
data isis written
written toto the
the database
database each
each time
time aa new
new country
country
isisadded,
added, each time a country is deleted and each time a cell is changed. If there aremany
each time a country is deleted and each time a cell is changed. If there are many
changes,
changes,ititisisnot
notnecessarily
necessarilyaagood
goodsolution
solutionasasititcan
canlead
leadto tomany
manywrite-ups
write-upsto tothe
thedatabase.
database.

Then
Then therethere isis the
the class
class CountriesModel,
CountriesModel, which
which isis the
the most
most complex
complex and and then
then also
also the
the
largest
largest of the program’s classes. Basically, the class looks like the corresponding class in
of the program’s classes. Basically, the class looks like the corresponding class in
ShowCountriesProgram
ShowCountriesProgram and and creates
creates the
the data
data model
model forfor the
the TreeTableView
TreeTableView component
component and and
hence
hencemethods
methodsthat thatcreates
createsthe
theindividual
individualcolumns.
columns.The Thefirst
firsttwo
twododonot
notaddaddanything
anythingnew,
new,
but
butthethemethod
methodgetNameCol()
getNameCol()has hasthis
thistime
timeaaCellFactory,
CellFactory,asasyou youcan
canedit
editthe
thecontents
contentsof ofaa
cell.
cell. ItIt isis basically
basically aa TextFieldTreeTableCell,
TextFieldTreeTableCell, andand the
the effect
effect isis to
to open
open aa TextField
TextField when
when youyou
double-click
double-clickthe thecell.
cell.InInthis
thiscase,
case,however,
however,there
thereisisan
anadditional
additionalchallenge
challengeasasnot
notall
allnames
names
are
are editable
editable and and therefore
therefore II have
have defined
defined mymy own
own CellFactory:
CellFactory:

class StringFactory implements Callback<TreeTableColumn<Country, String>,


TreeTableCell<Country, String>>
{
private Callback<TreeTableColumn<Country, String>,
TreeTableCell<Country, String>> cellFactory =
TextFieldTreeTableCell.<Country>forTreeTableColumn();

public TreeTableCell<Country, String>


call(TreeTableColumn<Country, String> col)
{
TreeTableCell<Country, String> cell = cellFactory.call(col);
cell.itemProperty().addListener((obs, oldValue, newValue) ->
{
TreeTableRow<Country> row = cell.getTreeTableRow();
if (row == null) cell.setEditable(false);
else
{
Country item = cell.getTreeTableRow().getItem();
if (item != null)
{
if (item.getCode3() == null || item.getCode3().length() < 3)
cell.setEditable(false);
else cell.setEditable(true);
}
}
});
return cell ;
}
}

112
112
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Exercise 5

The syntax does not look nice, but here you have to remember that a CellFactory is just a
class that implements a Callback interface and hence the method call(). The class creates a
TextFieldTreeTableCell used to edit the content. The method call() is performed every time
a cell becomes visual and it has a handler that primarily checks whether the cell represents
an object for a country and not a continent and sets the cell’s editable property accordingly.

The next method getAreaCol() works almost the same as getNameCol(), but another
TextFieldTreeTableCell is used, as this time you have to edit a Long. The type is LongFactory
and is in principle identical to StringFactory. Finally, the method also uses a CellValueFactory
(because of the sum of all child nodes areas), but it is the same class as in the previous
program. The getInhabitantsCol() method is in principle identical.

The method getCurrencyCol() works in the same way as getNameCol(), but the method
getWorldCol() is a bit different. When you click on a cell, you must have a combobox so
you can choose a continent. It has the type ComboBoxTreeTableCell and must as parameter
have the items to display. The object CellFactory now has the type WorldFactory, and except
that a ComboBoxTreeTableCell is used instead of a TextFieldTreeTableCell, the class is basically
identical to the other two CellFactory classes. However, the getWorldCol() method requires
extra action, as a change in a country’s continent means that the corresponding node must
be moved in the tree (see, if applicable, the program UpdateWorldProgram). This is solved
by associating an event handler for editSubmit, which takes care of what is needed.

Back there are two classes, though both are relatively simple and at least do not add anything
new. The class CountryDialog is a dialog box and is used when creating a new country.
The reason is that a country with a name and legal country codes must be created. Back
is the main program, which does not contain anything new, but you should note that in
order to create a country (and thus click on the Add button), the continent for which the
country is to be created must be selected. Similarly, to delete a country you must select
the country you want to delete. Note that you do not get any warning about what should
be used in practice.

113
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop

4 DRAG AND DROP


JavaFX supports direct drag and drop, such the functionality is built into both a Scene
and a Node object. You are talking about the operation as a press-drag-release gesture, which
means that the user holds one of the mouse’s buttons down, drags the mouse and releases
the mouse again to complete the operation. A gesture can be started of the Scene object
or on any Node object, called the source object, and a gesture can include several objects
(Nodes). During the operation, several events are firing and the use of these events depends
on the purpose of the current gesture, which may be:

1. That you want to change a node’s shape by dragging its perimeter or by dragging
it to another location. In this gesture, only the node that initiates the operation
is involved.
2. That you want to draw a source and drop it to another node (target) and in one
way or another combine the two nodes. When the source node is dropped on the
target node, some action is performed.
3. To drag a node and drop it over another node to transfer data from the source
node to the target node, and the actual data transfer occurs when the source node
is dropped.

114
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop

To describe these gestures, the documentation divides them into three types:

1. simple press-drag-release gesture


2. full press-drag-release gesture
3. drag-and-drop gesture

and here is the last one of the most interesting (which is most to be aware of ), and I will
divide the chapter into sections corresponding to this division.

4.1 SIMPLE PRESS-DRAG-RELEASE GESTURE


As the name says, it is the simplest form for drag-and-drop and is used where the operation
relates only to a single node and which is the node that starts the gesture. During the
operation, all MouseDragEvent types are fired:

-- MouseDragEntered
-- MouseDragOver
-- MouseDragExited
-- MouseDragReleased

but they are only sent to the source node. As an example, below is shown an application
that opens a window with two Label controls. By pointing at the top and holding down
the mouse, the background of the window changes to light green, and moves the mouse,
the text changes the color to yellow and the background turns light blue. If you pull the
mouse around in the window, nothing happens – even if you drag the mouse over the
bottom Label. However, if you release the mouse, the background color and the text color
of the top Label are returned to white and black respectively. The example should show
what happens if you start a drag gesture for a Label (and thus any other node) and drag
the mouse around in the window.

115
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

package simplednd;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.geometry.*;
import javafx.scene.text.Font;
import javafx.scene.paint.*;
import javafx.beans.property.*;

public class SimpleDnD extends Application


{
private Label lbl1 = new Label("Source");
private Label lbl2 = new Label("Target");
private final ObjectProperty<Color> fg =
new SimpleObjectProperty<Color>(Color.BLACK);
private final ObjectProperty<Background> bg =
new SimpleObjectProperty<Background>(background(Color.WHITE));

@Override
public void start(Stage stage)
{
Scene scene = new Scene(getRoot());
lbl1.setOnMousePressed(e -> bg.set(background(Color.LIGHTGREEN)));
lbl1.setOnMouseDragged(e -> bg.set(background(Color.LIGHTBLUE)));
lbl1.setOnDragDetected(e -> fg.set(Color.YELLOW));
lbl1.setOnMouseReleased(
e -> { bg.set(background(Color.WHITE)); fg.set(Color.BLACK); });
lbl2.setOnMouseDragEntered(e -> bg.set(background(Color.DARKGREEN)));
lbl2.setOnMouseDragOver(e -> bg.set(background(Color.DARKBLUE)));
lbl2.setOnMouseDragReleased(e -> fg.set(Color.RED));
lbl2.setOnMouseDragExited(e -> bg.set(background(Color.MAGENTA)));
stage.setScene(scene);
stage.setTitle("Simple DnD");
stage.show();
}

private Pane getRoot()


{
lbl1.setFont(Font.font(24));
lbl2.setFont(Font.font(24));
lbl1.textFillProperty().bind(fg);
VBox pane = new VBox(50, lbl1, lbl2);
pane.setPadding(new Insets(50, 50, 50, 50));
pane.backgroundProperty().bind(bg);
return pane;
}

116
116
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

private static Background background(Color color)


{
return new
Background(new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY));
}

public static void main(String[] args)


{
launch(args);
}
}

The
The program
program hashas two
two Label
Label controls
controls defined
defined as as instance
instance variables,
variables, as
as well
well as
as two
two properties
properties
for
for aa Color
Color and
and aa Background
Background respectively.
respectively. Here
Here you
you should
should especially
especially note
note that
that aa Background
Background
object
object is created for a specific color of the static method background(). The method getRoot()
is created for a specific color of the static method background(). The method getRoot()
intializes
intializes the components and creates the program’s view. Here you should note that root
the components and creates the program’s view. Here you should note that root
is
is a VBox, and that the method binds its background to the property bg, and similarly, the
a VBox, and that the method binds its background to the property bg, and similarly, the
text
text color
color of
of the
the top
top Label
Label binds
binds toto the
the property
property fg.fg. Finally,
Finally, the
the method
method start(),
start(), and
and here
here
is the most important thing that 4 event handlers are associated with
is the most important thing that 4 event handlers are associated with each of the Label each of the Label
controls.
controls. To
To the
the top,
top, two
two drag
drag event
event handlers
handlers areare assigned,
assigned, while
while all
all 44 drag
drag event
event handlers
handlers
are assigned to the bottom. The meaning is that you must observe that these event handlers

Challenge the way we run

EXPERIENCE THE POWER OF


FULL ENGAGEMENT…

RUN FASTER.
RUN LONGER.. READ MORE & PRE-ORDER TODAY
RUN EASIER… WWW.GAITEYE.COM

1349906_A6_4+0.indd 1 22-08-2014 12:56:57

117
117
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT drag and drop

are assigned to the bottom. The meaning is that you must observe that these event handlers
are
are never
never performed.
performed. AA simple
simple press-drag-release
press-drag-release gesture
gesture relates
relates only
only to
to the
the node
node –– and
and sends
sends
only
only notifications
notifications regarding
regarding drag
drag to
to that
that Node
Node –– that
that initiates
initiates the
the operation,
operation, which
which isis the
the
Node
Node the the mouse
mouse points
points when
when the
the button
button isis pressed.
pressed. The
The operation
operation ends
ends when
when the
the mouse
mouse
isis released
released and
and wherever
wherever where
where the
the mouse
mouse points.
points.

4.2
4.2 FULL
FULL PRESS-DRAG-RELEASE
PRESS-DRAG-RELEASE GESTURE
GESTURE
When
When thethe source
source node
node receives
receives aa notification
notification for for aa MouseDragDetected
MouseDragDetected event,event, itit can
can launch
launch
aa full
full press-drag-release
press-drag-release gesture
gesture by by calling
calling the
the method
method startFullDrag().
startFullDrag(). In In addition,
addition, the the
property
property mouseTransparent
mouseTransparent must must be be set
set to
to false
false for
for the
the source
source node
node soso this
this node
node does does not
not
receive
receive all
all drag
drag notifications.
notifications. The The example
example FullpressDnD
FullpressDnD isis almost
almost identical
identical to to the
the above
above
program
program andand opens
opens thethe same
same window.
window. Clicking
Clicking on on the
the top
top Label
Label starts
starts aa drag
drag operation,
operation,
which
which immediately
immediately results
results in
in the
the same
same as as above,
above, butbut when
when the the mouse
mouse isis draged
draged overover the
the
bottom
bottom Label,
Label, the
the background
background of of the
the window
window changes
changes to to dark
dark blue
blue while
while the
the text
text in
in the
the
bottom
bottom label
label becomes
becomes white.
white. IfIf the
the mouse
mouse again
again isis draged
draged outout from
from the
the bottom
bottom label,
label, the
the
text
text color
color in
in the
the top
top label
label changes
changes to to violet.
violet. When
When the the mouse
mouse isis released,
released, itit returns
returns toto
default.
default. The
The code
code isis this
this time
time the
the following:
following:

public class FullpressDnD extends Application


{
private Label lbl1 = new Label("Source");
private Label lbl2 = new Label("Target");
private final ObjectProperty<Color> fg1 =
new SimpleObjectProperty<Color>(Color.BLACK);
private final ObjectProperty<Color> fg2 =
new SimpleObjectProperty<Color>(Color.BLACK);
private final ObjectProperty<Background> bg =
new SimpleObjectProperty<Background>(background(Color.WHITE));

@Override
public void start(Stage stage)
{
Scene scene = new Scene(getRoot());
lbl1.setOnMousePressed(e -> startDrag());
lbl1.setOnMouseDragged(e -> bg.set(background(Color.LIGHTBLUE)));

lbl1.setOnDragDetected(e -> { lbl1.startFullDrag();
fg1.set(Color.YELLOW); });
lbl1.setOnMouseReleased(e -> endDrag());
lbl2.setOnMouseDragEntered(e -> fg2.set(Color.WHITE));
lbl2.setOnMouseDragOver(e -> bg.set(background(Color.DARKBLUE)));
lbl2.setOnMouseDragReleased(e -> lbl1.setText("End"));
lbl2.setOnMouseDragExited(
e -> { if (lbl1.isMouseTransparent()) fg1.set(Color.MAGENTA); });

118

118
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

stage.setScene(scene);
stage.setTitle("Full Press DnD");
stage.show();
}

private void startDrag()


{
lbl1.setText("Source");
lbl1.setMouseTransparent(true);
bg.set(background(Color.LIGHTGREEN));
}

private void endDrag()


{
lbl1.setMouseTransparent(false);
bg.set(background(Color.WHITE));
fg1.set(Color.BLACK);
fg2.set(Color.BLACK);
}

private Pane getRoot()


{
lbl1.setFont(Font.font(24));
lbl2.setFont(Font.font(24));
lbl1.textFillProperty().bind(fg1);
lbl2.textFillProperty().bind(fg2);
VBox pane = new VBox(50, lbl1, lbl2);
pane.setPadding(new Insets(50, 50, 50, 50));
pane.backgroundProperty().bind(bg);
return pane;
}

private static Background background(Color color)


{
return new
Background(new BackgroundFill(color, CornerRadii.EMPTY, Insets.EMPTY));
}

public static void main(String[] args)


{
launch(args);
}
}

This
This time,
time, two
two properties
properties for
for Color
Color objects
objects are
are defined
defined so
so that
that the
the text
text color
color for
for both
both Label
Label
controls is bound to a property (the method getRoot()). Otherwise, you should first
controls is bound to a property (the method getRoot()). Otherwise, you should first notice notice
which
which events
events handlers
handlers are
are associated
associated with
with the
the two
two labels.
labels. When
When thethe mouse
mouse points
points toto the
the

119
119
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop

top label and the mouse is pressed, mouseTransparent is set to true (the method startDrag())
and it is put back to false when the mouse is released (the method endDrag()). Finally, note
that lbl1 at dragDetected executes startFullDrag(), and the result is that the component lbl2
this time receives drag notifications. You are encouraged to experiment with the program
and observe when each event occurs. Here you should especially note dragReleased for the
lower label, which changes the text in the top label. It is executed if you release the mouse
while it points to the bottom label.

4.3 DRAG-AND-DROP GESTURE


The last form of drag and drop gesture is mostly the general and probably also the most
used and used to extract data from the source node and drop them on a target node. The
gesture in question may concern nodes within the same application, but it may also concern
nodes in two different Java applications. In fact, both applications does not necessarily have
to be a Java application.

This e-book
is made with SETASIGN
SetaPDF

PDF components for PHP developers

www.setasign.com

120
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop

In general, a drag-and-drop operation includes the following actions:

-- Point to a node and hold down one of the mouse’s buttons


-- Drag the mouse while the button is held down and the node gets a DragDetected
event and must perform a startDragAndDrop(), after which the node is a gesture
source node and the current data is placed on the clipboard
-- After starting a drag-and-drop gesture, the system no longer sends MouseEvents,
but instead DragEvents
-- If a gesture source is dragged over a gesture target, it will check if it will accept data
on the clipboard and do it, it will with a DragEvent indicate that data is accepted.
-- If the user drops the mouse while pointing to a gesture target, it will apply the
current data and send a DragDropped event
-- When the source gesture node receives a DragDone event, it tells that the operation
has been completed

In this section I will illustrate drag-and-drop with three examples, and the first one is called
TextDnd and opens the following window:

It is basically the same window as in the two previous examples, except that there is a
frame outside of the two Label controls, and a button has been added. In this example,
drag and drop gestures drag the text from the top label and drop it on the bottom label.
A drag-and-drop gesture can be performed in two ways (actually three and you can read
about drag-and-drop in the book Java 10), where one drops a copy of the data element
(here the text in the top label) while the another one moves it. Here the text Copy in the
button means that it is a copy gesture that is being executed. Clicking the button changes
the text and it is a move gesture, while resetting the window. The code is as follows:

121
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

public class TextDnD extends Application


{
private Button cmd = new Button("Copy");
private Label lbl1 = new Label("Source");
private Label lbl2 = new Label("Target");
private TransferMode mode = TransferMode.COPY;

@Override
public void start(Stage stage)
{
Scene scene = new Scene(getRoot());
lbl1.setOnDragDetected(this::dragDetected);
lbl2.setOnDragOver(this::dragOver);
lbl2.setOnDragDropped(this::dragDropped);
lbl1.setOnDragDone(this::dragDone);
stage.setScene(scene);
stage.setTitle("Text DnD");
stage.show();
}

private Pane getRoot()


{
lbl1.setFont(Font.font(24));
lbl2.setFont(Font.font(24));
lbl1.setPadding(new Insets(5, 10, 5, 10));
lbl2.setPadding(new Insets(5, 10, 5, 10));
lbl1.setStyle("-fx-border-color: black;");
lbl2.setStyle("-fx-border-color: black;");
cmd.setOnAction(e -> reset());
VBox pane = new VBox(50, lbl1, lbl2, cmd);
pane.setPadding(new Insets(50, 50, 50, 50));
pane.setAlignment(Pos.CENTER);
return pane;
}

private void dragDetected(MouseEvent e)


{
String text = lbl1.getText();
if (text == null)
{
e.consume();
return;
}
Dragboard dragboard = lbl1.startDragAndDrop(mode);
ClipboardContent content = new ClipboardContent();
content.putString(text);
dragboard.setContent(content);
e.consume();
}

122
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

private void dragOver(DragEvent e)


{
Dragboard dragboard = e.getDragboard();
if (dragboard.hasString()) e.acceptTransferModes(mode);
e.consume();
}

private void dragDropped(DragEvent e)


{
Dragboard dragboard = e.getDragboard();
if (dragboard.hasString())
{
String text = dragboard.getString();
lbl2.setText(text);
e.setDropCompleted(true);
}
else e.setDropCompleted(false);
e.consume();
}

private void dragDone(DragEvent e)


{
TransferMode mode = e.getTransferMode();

www.sylvania.com

We do not reinvent
the wheel we reinvent
light.
Fascinating lighting offers an infinite spectrum of
possibilities: Innovative technologies and new
markets provide both opportunities and challenges.
An environment in which your expertise is in high
demand. Enjoy the supportive working atmosphere
within our global group and benefit from international
career paths. Implement sustainable ideas in close
cooperation with other specialists and contribute to
influencing our future. Come and join us in reinventing
light every day.

Light is OSRAM

123
123
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

if (mode == TransferMode.MOVE) lbl1.setText("");


e.consume();
}

private void reset()


{
lbl1.setText("Source");
lbl2.setText("Target");
if (mode == TransferMode.COPY)
{
cmd.setText("Move");
mode = TransferMode.MOVE;
}
else
{
cmd.setText("Copy");
mode = TransferMode.COPY;
}
}

public static void main(String[] args)


{
launch(args);
}
}

With regard
With regard toto instance
instance variables,
variables, they
they are
are self
self explanatory,
explanatory, but
but note
note the
the last
last one
one used
used
to indicate
to indicate whether
whether aa gesture
gesture should
should be
be Copy
Copy oror Move.
Move. The
The type
type is
is an
an enumeration.
enumeration. The The
method getRoot()
method getRoot() that
that creates
creates the
the program’s
program’s view
view does
does not
not contain
contain anything
anything new,
new, but
but in
in
the method
the method start()
start() you
you should
should note
note which
which events
events handlers
handlers are
are being
being associated.
associated. Generally,
Generally, aa
source node
source node must
must have
have associated
associated two
two event
event handlers:
handlers: DragDetected
DragDetected and
and DragDone.
DragDone. A A target
target
node must
node must correspondingly
correspondingly havehave associated
associated two
two event
event handlers:
handlers: DragOver
DragOver andand DragDropped.
DragDropped.
Corresponding to
Corresponding to this
this is
is the
the most
most important
important inin the
the example
example these
these 44 event
event traders.
traders.

The method
The method dragDetected()
dragDetected() starts
starts by
by testing
testing whether
whether there
there is
is actually
actually aa data
data element
element andand here
here
ifif the
the top
top label
label shows
shows aa text.
text. If
If so,
so, startDragAndDrop()
startDragAndDrop() is is performed
performed on on the
the source
source node,
node,
and the
and the parameter
parameter is is which
which operation
operation to to be
be performed.
performed. TheThe method
method returns
returns aa DragBoard
DragBoard
object, and
object, and is is an
an object
object that
that represents
represents the
the clipboard.
clipboard. InIn fact,
fact, DragBoard
DragBoard is is aa subclass
subclass of
of
the class
the class Clipboard.
Clipboard. The The method
method dragDetected()
dragDetected() also
also has
has aa reference
reference toto the
the clipboard
clipboard andand it
it
saves the
saves the text
text onon the
the clipboard
clipboard andand finally
finally updates
updates thethe DragBoard
DragBoard objectobject with
with the
the current
current
content on
content on the
the clipboard.
clipboard.

The method
The method dragDone()
dragDone() is is not
not always
always necessary,
necessary, but
but in
in this
this case
case it
it tests
tests whether
whether it
it is
is aa Move
Move
operation, and
operation, and ifif so,
so, the
the method
method isis responsible
responsible for
for deleting
deleting the
the text
text in
in the
the Label
Label component
component ––

124
124
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT drag and
Drag and drop
drop

that is,
that is, in
in source
source node.
node. The
The method
method dragOver()
dragOver() isis performed
performed when
when the
the user
user passes
passes the
the mouse
mouse
over aa target
over target node.
node. The
The method
method tests
tests whether
whether something
something isis on
on the
the clipboard,
clipboard, and
and ifif that
that isis
the case,
the case, acceptTransferModes()
acceptTransferModes() isis performed,
performed, which
which means
means that
that the
the cursor
cursor changes,
changes, so so you
you
can visually
can visually seesee that
that you
you are
are over
over aa node
node where
where you you can
can drop.
drop.

Finally, there
Finally, there isis the
the method
method dragDropped().
dragDropped(). In In this
this case,
case, itit starts
starts testing
testing whether
whether there
there isis
aa string
string on
on the
the clipboard,
clipboard, and
and ifif so,
so, the
the text
text isis retrieved
retrieved andand the
the label
label component’s
component’s text
text
isis updated.
updated. Then
Then the the method
method dropCompleted()
dropCompleted() isis performed,
performed, whichwhich sends
sends aa notification
notification to
to
the source
the source node
node that that the
the operation
operation hashas been
been completed.
completed. Before
Before leaving
leaving the
the program,
program, you
you
should also
should also note
note the the method
method reset()
reset() used
used as
as event
event handler
handler for
for the
the button
button and
and among
among other
other
switches mode,
switches mode, so so the
the next
next drag-and-drop
drag-and-drop operation
operation may may be be aa Move
Move gesture.
gesture.

As the
As the next
next example,
example, I’ll
I’ll show
show you
you how
how to
to drag
drag an
an image
image into
into an
an application
application where
where itit can
can
be either
be either an
an image
image or
or aa file
file that
that contains
contains an
an image.
image. That
That is,
is, you
you can
can drag
drag aa data
data element
element
that represents
that represents an
an image
image from
from another
another program
program (such
(such as
as the
the Files
Files program)
program) toto the
the current
current
application. The
application. The example
example isis called
called ImageDnD
ImageDnD andand opens
opens the
the following
following window,
window, which
which
contains aa button
contains button and
and an
an ImageView
ImageView control:
control:

public class ImageDnD extends Application


{
private ImageView view = new ImageView();

@Override
public void start(Stage stage)
{
Scene scene = new Scene(createRoot());
scene.setOnDragOver(this::dragOver);
scene.setOnDragDropped(this::dragDropped);
stage.setScene(scene);
stage.setTitle("Image DnD");
stage.show();
}

125
125
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

private Pane createRoot()


{
view.setFitWidth(300);
view.setFitHeight(200);
view.setSmooth(true);
view.setPreserveRatio(true);
HBox pane = new HBox(10, createButton("Clear", e -> view.setImage(null)));
pane.setAlignment(Pos.CENTER_RIGHT);
VBox root = new VBox(20, view, pane);
root.setPadding(new Insets(20, 20, 20, 20));
return root;
}

private Button createButton(String text, EventHandler<ActionEvent> handler)


{
Button cmd = new Button(text);
cmd.setOnAction(handler);
360°
.
return cmd;
}

private void dragOver(DragEvent e)


{
thinking
Dragboard dragboard = e.getDragboard();

360°
thinking . 360°
thinking .
Discover the truth at www.deloitte.ca/careers Dis

© Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers © Deloitte & Touche LLP and affiliated entities.

Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers


126
126
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

if (dragboard.hasImage() || dragboard.hasFiles())
e.acceptTransferModes(TransferMode.ANY);
e.consume();
}

private void dragDropped(DragEvent e)


{
boolean completed = false;
Dragboard dragboard = e.getDragboard();
if (dragboard.hasImage()) completed = transferImage(dragboard.getImage());
else if (dragboard.hasFiles()) completed =
transferImageFile(dragboard.getFiles());
else System.out.println("Error – Illegal format: Image, File, URL");
e.setDropCompleted(completed);
e.consume();
}

private boolean transferImage(Image image)


{
view.setImage(image);
return true;
}

private boolean transferImageFile(List<File> files)


{
for(File file : files)
{
try
{
String mimeType = Files.probeContentType(file.toPath());
if (mimeType != null && mimeType.startsWith("image/"))
{
view.setImage(new Image(file.toURI().toURL().toExternalForm()));
return true;
}
}
catch (IOException ex)
{
System.out.println(ex.getMessage());
}
}
return false;
}

public static void main(String[] args)


{
launch(args);
}
}

127
127
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Drag
drag and
and drop
drop

The
The method
method createRoot()
createRoot() that that creates
creates the
the program’s
program’s viewview does
does not
not contain
contain anything
anything new, new,
and
and the the task
task isis to
to initialize
initialize the the ImageView
ImageView controller.
controller. Note,
Note, however,
however, that
that the
the button
button isis
assigned
assigned an an event
event handler
handler which which deletes
deletes the
the content
content of of the
the ImageView
ImageView component.
component. The The
method
method start()start() assigns
assigns twotwo event
event handlers
handlers toto the
the Scene
Scene object,
object, which
which means
means that
that you
you can
can
drop
drop an an object
object in in the
the application’s
application’s window.
window. There
There areare only
only two
two handlers
handlers since
since the
the program
program
this
this timetime does
does notnot have
have aa source
source gesture
gesture node
node –– aa drag-and-drop
drag-and-drop operation
operation isis initiated
initiated in
in
another
another application.
application. dragOver()
dragOver() has has the
the same
same function
function as as in
in the
the previous
previous example,
example, andand you
you
should
should note note how
how to to test
test ifif the
the clipboard
clipboard has
has aa data
data element
element thatthat the
the program
program can can accept.
accept.
ItIt isis likewise
likewise tested
tested inin the
the dragDropped()
dragDropped() method
method and and depending
depending on on what
what data
data item
item isis
(an
(an image
image or or aa file),
file), aa method
method isis called
called that
that performs
performs the the data
data transfer.
transfer. Here
Here youyou should
should
especially
especially note note thethe method
method transferImageFile()
transferImageFile() andand the
the syntax
syntax used.
used. This
This means
means thatthat the
the file
file
name
name must must bebe used
used toto load
load thatthat image
image from
from aa file.
file.

As
As the
the last
last example
example of
of drag-and-drop,
drag-and-drop, II will
will show
show aa program
program where
where you
you can
can drag
drag an
an object
object
of
of aa custom
custom type.
type. The
The example
example isis called
called PersonDnD
PersonDnD and and opens
opens the
the following
following window:
window:

The
The window
window contains
contains two
two ListView
ListView controls.
controls. Each
Each line
line in
in the
the left
left ListView
ListView represents
represents aa Person
Person
object,
object, and
and these
these objects
objects can
can be
be draged
draged to to the
the right
right by
by aa drag-and-drop
drag-and-drop gesture.
gesture. Similarly,
Similarly,
you
you can
can drag
drag objects
objects from
from right
right to
to left.
left. AA Person
Person object
object isis aa very
very common
common model
model class
class that
that
represents
represents aa person
person with
with two
two characteristics:
characteristics:

public class Person implements Serializable


{
private String name = "";
private String job = "";

128
128
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

public Person(String name, String job)


{
this.name = name;
this.job = job;
}

public String getName()


{
return name;
}

public void setName(String name)


{
this.name = name;
}

public String getJob()


{
return job;
}

We will turn your CV into


an opportunity of a lifetime

Do you like cars? Would you like to be a part of a successful brand? Send us your CV on
We will appreciate and reward both your enthusiasm and talent. www.employerforlife.com
Send us your CV. You will be surprised where it can take you.

129
129
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT Drag and drop
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT drag
drag and
and drop
drop

public
public void
void setJob(String
setJob(String job)
job)
{
{
this.job
this.job =
= job;
job;
}
}

@Override
@Override
public
public String
String toString()
toString()
{
{

return getName() + ": " + getJob();
return getName() + ": " + getJob();
}
}
}
}

There
There isis only
only one
one thing
thing to
to observe,
observe, namely
namely that
that the
the class
class is
is serializable.
serializable. It
It is
is aa prerequisite
prerequisite
for
for objects to be used in a drag-and-drop gesture. Also note that this means that the
objects to be used in a drag-and-drop gesture. Also note that this means that the types
types
of
of the
the class’s
class’s instance
instance variables
variables must
must be
be serializable.
serializable. The
The class
class PersonDnD
PersonDnD is: is:

public class PersonDnD extends Application


public class PersonDnD extends Application
{
{
private static final DataFormat PERSON_LIST =
private static final DataFormat PERSON_LIST =

new DataFormat("persons/personlist");
new DataFormat("persons/personlist");
ListView<Person> view1 = new ListView();
ListView<Person> view1 = new ListView();
ListView<Person> view2 = new ListView();
ListView<Person> view2 = new ListView();

@Override
@Override
public
public void
void start(Stage
start(Stage stage)
stage)
{
{
Scene
Scene scene
scene == new
new Scene(getRoot());
Scene(getRoot());
stage.setScene(scene);
stage.setScene(scene);

stage.setTitle("Person DnD");
stage.setTitle("Person DnD");
stage.show();
stage.show();
}
}

private
private Pane
Pane getRoot()
getRoot()
{
{
view1.setPrefSize(300,
view1.setPrefSize(300, 300);
300);
view2.setPrefSize(300,
view2.setPrefSize(300, 300);
300);
view1.getItems().addAll(getPersons());
view1.getItems().addAll(getPersons());

view1.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
view1.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
view2.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
view2.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

view1.setOnDragDetected(e -> dragDetected(e, view1));
view1.setOnDragDetected(e -> dragDetected(e, view1));

view2.setOnDragDetected(e -> dragDetected(e, view2));
view2.setOnDragDetected(e -> dragDetected(e, view2));
view1.setOnDragOver(e -> dragOver(e, view1));
view1.setOnDragOver(e -> dragOver(e, view1));
view2.setOnDragOver(e -> dragOver(e, view2));
view2.setOnDragOver(e -> dragOver(e, view2));

view1.setOnDragDropped(e -> dragDropped(e, view1));
view1.setOnDragDropped(e -> dragDropped(e, view1));
view2.setOnDragDropped(e -> dragDropped(e, view2));
view2.setOnDragDropped(e -> dragDropped(e, view2));
view1.setOnDragDone(e -> dragDone(e, view1));
view1.setOnDragDone(e -> dragDone(e, view1));
view2.setOnDragDone(e -> dragDone(e, view2));
view2.setOnDragDone(e -> dragDone(e, view2));

130
130
130
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

GridPane pane = new GridPane();


pane.setPadding(new Insets(20, 20, 20, 20));
pane.setHgap(20);
pane.addRow(0, view1, view2);
return pane;
}

private ObservableList<Person> getPersons() { … }

private void dragDetected(MouseEvent e, ListView<Person> view)


{
int selectedCount = view.getSelectionModel().getSelectedIndices().size();
if (selectedCount == 0)
{
e.consume();
return;
}
Dragboard dragboard = view.startDragAndDrop(TransferMode.COPY_OR_MOVE);
List<Person> items = getSelectedItems(view);
ClipboardContent content = new ClipboardContent();
content.put(PERSON_LIST, items);
dragboard.setContent(content);
e.consume();
}

private void dragOver(DragEvent e, ListView<Person> view)


{
Dragboard dragboard = e.getDragboard();
if (e.getGestureSource() != view && dragboard.hasContent(PERSON_LIST))
e.acceptTransferModes(TransferMode.COPY_OR_MOVE);
e.consume();
}

private void dragDropped(DragEvent e, ListView<Person> view)


{
boolean completed = false;
Dragboard dragboard = e.getDragboard();
if(dragboard.hasContent(PERSON_LIST))
{
view.getItems().addAll((ArrayList<Person>)
dragboard.getContent(PERSON_LIST));
completed = true;
}
e.setDropCompleted(completed);
e.consume();
}

131
131
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

private void dragDone(DragEvent e, ListView<Person> view)


{
TransferMode mode = e.getTransferMode();
if (mode == TransferMode.MOVE) removeSelectedItems(view);
e.consume();
}

private List<Person> getSelectedItems(ListView<Person> listView)


{
return new ArrayList(listView.getSelectionModel().getSelectedItems());
}

private void removeSelectedItems(ListView<Person> view)


{
List<Person> list = new ArrayList();
for(Person pers : view.getSelectionModel().getSelectedItems()) list.add(pers);
view.getSelectionModel().clearSelection();
view.getItems().removeAll(list);
}

�e Graduate Programme
I joined MITAS because for Engineers and Geoscientists
I wanted real responsibili� www.discovermitas.com
Maersk.com/Mitas �e G
I joined MITAS because for Engine
I wanted real responsibili� Ma

Month 16
I was a construction Mo
supervisor ina const
I was
the North Sea super
advising and the No
Real work he
helping foremen advis
International
al opportunities
Internationa
�ree wo
work
or placements ssolve problems
Real work he
helping fo
International
Internationaal opportunities
�ree wo
work
or placements ssolve pr

132
132
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Drag and drop
SOFTWARE DEVELOPMENT drag and drop

public static void main(String[] args)


{
launch(args);
}
}

Custom types can not be immediately transferred via the clipboard as they do not have a
known mime type. This means that a target node can not test what is on the clipboard.
Therefore, the program starts by creating a static object of the type DataFormat named
PERSON_LIST. The value is not important. It just has to be a name that is unique (for
the program). The method getRoot() fills a part, and it must, among other things, initialize
the left ListView with 6 Person objects. These objects are created in the method getPersons(),
but I have not shown the code. Note that for both ListView controls, are select MULTIPLE,
so the user can select more Person objects. However, the most important thing is that 4
event handlers are assigned to each control, since both controls can be both source and
target gesture nodes.

The methods (there are 4) that the event handlers call has a parameter that tells what it is
for a ListView that the event concerns. dragDetected() initiates a drag operation, and you
must note that its mode is COPY_OR_MOVE so that it can be used in either case. You
start a COPY operation by pressing the mouse button, if you also holding down the SHIFT
key, it is a MOVE operation. dragDetected() uses the method getSelectedItems() to return the
Person objects that are selected, and it is this list of objects that is placed on the clipboard.
dragOver() and dragDropped() appear as shown in the two previous examples but note how
dragDropped() using the PERSON_LIST object tests whether it is data of the correct kind
that ara located on the clipboard before the list is copied to the target ListView component.
Finally, there is the method dragDone() that tests whether it is a MOVE operation, and if
necessary, the objects that are moved will be deleted from the source node.

133
133
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT MVC

5 MVC
I have treated the Module-View-Controller pattern earlier, which is the design pattern of a
GUI program, and in this context, I also mentioned that there are several versions of the
pattern, partly because of the development tools used, but also on due to the API used.
Should you use JavaFX fully, you should use the Module-View-Presenter pattern, which you
sometimes see shortened as MVP. The pattern can be sketched as follows:

The principle is that the program’s view takes care of everything regarding the visual, but
can turn to the model to get the data to be displayed. The user interaction takes place in
the view layer, but when there is a user interaction, it is sent to the presenter module, which
takes care of it. That is, a window’s event handlers are placed a presenter class that as a result
can update the view component and execute commands on the model. When the model
is updated as a result of commands from the present, it can send notifications, which the
view component can listen to and possibly read the model to ensure the synchronization
between model and view.

It’s the principle, and in fact, is not very different than I’ve previously mentioned about
MVC, just the pattern is drawn in a way that directly supports JavaFX. Another thing,
however, is what it means in the code, and especially who is responsible for creating the
individual objects, and it is best illustrated with an example.

Looking at the previous examples in this book, they basically had a 2 layer architecture
consisting of a view layer and a model layer. The most important thing in the above
pattern is actually a more accurate breakdown of the view layer in a view component and
a presenter component. The goal of all is to make the code as simple and manageable as
possible, and even as the most important thing to ensure that GUI programs are written
in a standardized manner, and one of the patterns that JavaFX recommends is a systematic
use of data binding. In previous books, I have used a database addresses that only have a
single table:

134
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT MVC
SOFTWARE DEVELOPMENT MvC

use mysql;

create database addresses;

use addresses;

create table address (


id int not null auto_increment,
firstname varchar(50),
lastname varchar(30),
address varchar(50),
code varchar(4),
city varchar(30),
mail varchar(50),
date varchar(10),
title varchar(50),
primary key (id)
);

135
135
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT MVC

As example, I will look at a program that can maintain this database, and when the program
starts, it must open the following window:

as in a TableView shows an overview of the database’s addresses. If you click on the button,
you will see the window below where you can create a new address and you get the same
window (but initialized with data) if you double-click on an address in the table:

136
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT MVC

The program consists of 9 classes:

and in the following I will mention the most important of these classes and the choices
made. If you start with the model layer, it has two classes, and one of the purposes is that
the model via data binding should send notifications to the user interface, but also the
view component classes should automatically update the model. For example, the class
Address must have JavaFX properties corresponding to all columns in the database table,
and since the classs Addresses should represent the table in the above window, it must have
an ObservableList<Address> and have methods that can return the columns to the TableView
component. The model classes Address and Addresses must thus be written according to a
precise pattern that supports JavaFX. In one way or another, it does not fit with that you
want to separate the model and its classes from the rest of the code so that they can be
written independently of how the model has to be used. Therefore, a DAL layer is defined
under the model layer, which consists of two classes Person and Persons, the first being a usual
model class, representing an entity in the database, and containing no other than instance
variables using conventional get and set methods. The class Persons consists primarily of 4
methods, one of which returns a List<Person> with the content of the database, where the
other three are for SQL INSERT, UPDATE and DELETE operations. With this DAL layer
available, the class Address is no more than a thin wrapper of the class Person, where each
property is encapsulated in a JavaFX property. However, the class has a method invalidate(),
as in relation to the current task, can validate if an Address object is legal.

The class Addresses has an instance of the class Persons, starting with reading data in the
database, to create an ObservableList<Address>. In the same way as shown in the examples,
the class defines methods for individual columns so that they can bind to the TableView. In
addition to this, the class has methods save() and remove() used to save and delete data. In

137
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT MVC
MvC

principle,
principle, these
these methods
methods areare trivial
trivial and
and do
do not
not so
so much
much other
other than
than calling
calling the
the corresponding
corresponding
methods
methods inin the
the class
class Persons,
Persons, but
but at
at the
the same
same time
time they
they must
must ensure
ensure the
the class’s
class’s ObservableList
ObservableList
is
is synchronized
synchronized with
with the
the database.
database.

Back
Back there
there are
are the
the presentations
presentations and
and view
view components.
components. The
The class
class AddressesView
AddressesView must
must define
define
the
the main
main window:
window:

import addressesprogram.models.*;

public class AddressesView extends BorderPane


{
Button cmdAdd = new Button("Create address");
TableView<Address> tableView;

public AddressesView(Addresses model)


{
tableView = new TableView(model.getAddresses());
createForm(model);
}

In the past 5 years we have drilled around

95,000 km
—that’s more than twice around the world.

Who are we?


We are the world’s leading provider of reservoir characterization,
drilling, production, and processing technologies to the oil and
gas industry.

Who are we looking for?


We offer countless opportunities in the following domains:
n Operations
n Research, Engineering, and Manufacturing
n Geoscience and Petrotechnical
n Commercial and Business

We’re looking for high-energy, self-motivated graduates


with vision and integrity to join our team. What will you be?

careers.slb.com

138
138
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT MVC
MvC

and
and inin addition
addition toto thethe above,
above, there
there isis only
only createForm(),
createForm(), which
which initializes
initializes aa BorderPane
BorderPane
with
with aa TableView
TableView andand aa Button.
Button. There
There isis therefore
therefore no
no logic
logic including
including event
event handlers
handlers in
in this
this
class.
class. You
You should
should note
note that
that the
the class
class inherits
inherits BorderPane.
BorderPane. AlsoAlso note
note the
the parameter
parameter ofof the
the
constructor, which is the model and thus an object of the type Addresses.
constructor, which is the model and thus an object of the type Addresses. Finally, note the Finally, note the
two
two instance
instance variables,
variables, which
which areare references
references toto the
the window’s
window’s controls.
controls. These
These variables
variables have
have
no
no visibility,
visibility, and
and thus
thus they
they have
have the
the package
package visibility
visibility so
so that
that they
they can
can be be used
used from
from thethe
presenter
presenter class,
class, which
which has has the
the task
task of
of creating
creating the
the event
event handlers.
handlers. ItIt isis therefore
therefore necessary
necessary
that the view and presenter are in the same package. The presenter class
that the view and presenter are in the same package. The presenter class is as follows: is as follows:

public class AddressesPresenter


{
private final Addresses model;
private final AddressesView view;
private final Stage owner;

public AddressesPresenter(Stage owner, Addresses model)


{
this.owner = owner;
this.model = model;
view = new AddressesView(model);
addHandlers();
}

public Pane getView()


{
return view;
}

private void addHandlers()


{
view.cmdAdd.setOnAction(e -> add(new Address()));
view.tableView.setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event)
{
if (event.isPrimaryButtonDown() && event.getClickCount() == 2)
add(view.tableView.getSelectionModel().getSelectedItem());
}
});
}

private void add(Address address)


{
AddressPresenter presenter = new AddressPresenter(model, address);
Scene scene = new Scene(presenter.getView());
Stage stage = new Stage();

139
139
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT MVC
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT MvC
SOFTWARE DEVELOPMENT MvC

stage.initOwner(owner);
stage.initOwner(owner);
stage.initModality(Modality.APPLICATION_MODAL);
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.setResizable(false);
stage.setTitle("Address");
stage.setTitle("Address");
stage.setScene(scene);
stage.setScene(scene);
stage.show();
stage.show();
}
}
}
}

It
It is
is thus
thus the
the presenter
presenter class
class that
that creates
creates the
the view
view class.
class. It
It is
is not
not actually
actually completely
completely consistent
consistent
with
with the pattern as most people choose to create view objects outside the class and
the pattern as most people choose to create view objects outside the class and then
then
transfer
transfer it as a parameter to the constructor. Since I have not done it, it is necessary to add
it as a parameter to the constructor. Since I have not done it, it is necessary to add
aa method getView() such that you can refer to the view object in the
method getView() such that you can refer to the view object in the main class. The class’smain class. The class’s
constructor
constructor has has as as parameters
parameters thethe model
model andand aa reference
reference to to the
the primary
primary Stage
Stage object.
object. It
It is
is
used as the owner of the dialog window to edit an address. You
used as the owner of the dialog window to edit an address. You should note the method should note the method
addHandlers()
addHandlers() as as the
the method
method thatthat associates
associates event
event handlers
handlers to to nodes
nodes defined
defined in in the
the view
view
component.
component. In this case, an event handler must be attached to double-click a row in the
In this case, an event handler must be attached to double-click a row in the
TableView component as well as an event handler for the button. In
TableView component as well as an event handler for the button. In either case, the methodeither case, the method
add(),
add(), which
which opens
opens the
the dialog
dialog toto either
either create
create aa new
new address
address (where
(where the the current
current parameter
parameter
is
is a new Address object) or to edit an existing address (where the address is the object
a new Address object) or to edit an existing address (where the address is the object of
of
the line that is double-clicked).
the line that is double-clicked).

The
The dialog
dialog box
box is
is defined
defined as
as the
the following
following class,
class, which
which is
is aa GridPane:
GridPane:

public class AddressView extends GridPane


public class AddressView extends GridPane
{
{
private final Address model;
private final Address model;
TextField txtFirstname = new TextField();
TextField txtFirstname = new TextField();
TextField txtLastname = new TextField();
TextField txtLastname = new TextField();
TextField txtAddress = new TextField();
TextField txtAddress = new TextField();
TextField txtCode = new TextField();
TextField txtCode = new TextField();
TextField txtCity = new TextField();
TextField txtCity = new TextField();
TextField txtMail = new TextField();
TextField txtMail = new TextField();
TextField txtTitle = new TextField();
TextField txtTitle = new TextField();
DatePicker datePicker = new DatePicker();
DatePicker datePicker = new DatePicker();
Button cmdDel = new Button("Remove");
Button cmdDel = new Button("Remove");
Button cmdOk = new Button("OK");
Button cmdOk = new Button("OK");
Button cmdCancel = new Button("Cancel");
Button cmdCancel = new Button("Cancel");

public AddressView(Address model)


public AddressView(Address model)
{
{
this.model = model;
this.model = model;
createForm();
createForm();
bindFields();
bindFields();
}
}

140
140
140
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT MVC
SOFTWARE DEVELOPMENT MvC

public Address getModel()


{
return model;
}

private void createForm()


{

}

public void bindFields()


{
txtFirstname.textProperty().bindBidirectional(model.firstnameProperty());
txtLastname.textProperty().bindBidirectional(model.lastnameProperty());
txtAddress.textProperty().bindBidirectional(model.addressProperty());
txtCode.textProperty().bindBidirectional(model.codeProperty());
txtCity.textProperty().bindBidirectional(model.cityProperty());
txtMail.textProperty().bindBidirectional(model.mailProperty());
txtTitle.textProperty().bindBidirectional(model.titleProperty());
datePicker.valueProperty().bindBidirectional(model.dateProperty());
}
}

141
141
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT MVC
MvC

Here
Here youyou should
should note
note thatthat all
all nodes
nodes that that can
can be
be referred
referred by
by the
the event
event handlers
handlers are
are defined
defined with
with
package
package visibility
visibility so
so that
that they
they can
can be be referenced
referenced inin the
the presenter
presenter class.
class. In
In some
some way,
way, itit violates
violates
object-oriented
object-oriented principles
principles wherewhere variables
variables must
must bebe private,
private, but
but ifif one
one wishes
wishes to
to comply
comply withwith
these
these principles,
principles, itit isis necessary
necessary to to write
write get
get methods
methods forfor all
all instance
instance variables.
variables. Therefore,
Therefore, youyou
typically
typically implement
implement the the MVP
MVP pattern
pattern as as above
above and
and require
require that
that the
the view
view and
and presenter
presenter areare in
in
the
the same
same package.
package. YouYou should
should note
note the the method
method bindFields()
bindFields() that
that creates
creates bidirectional
bidirectional bindings
bindings
for
for all
all fields,
fields, and
and itit isis here
here that
that itit isis necessary
necessary that
that the
the model
model class
class Address
Address has
has JavaFX
JavaFX properties
properties
that
that you
you can
can bind
bind to.
to. This
This means
means that that the
the values
values entered
entered automatically
automatically update
update the
the model
model class,
class,
and
and vice
vice versa
versa that
that modifications
modifications of of the
the model
model automatically
automatically update
update thethe user
user interface.
interface.

The
The corresponding
corresponding presenter
presenter class
class isis basically
basically simple
simple and
and resembles
resembles thethe previous
previous presenter
presenter
class,
class, and
and among
among other
other things
things itit isis this
this class
class that
that creates
creates the
the view
view component.
component. However,
However,
there
there isis aa problem
problem toto be
be solved.
solved. If
If you
you edit
edit an
an address,
address, the
the model
model isis automatically
automatically updated
updated
because
because of of the
the bindings,
bindings, which
which isis incorrect
incorrect ifif you
you close
close the
the dialog
dialog with
with cancel.
cancel. In
In this
this case,
case,
the
the entries
entries that
that have
have been
been made
made must
must be be canceled.
canceled. Therefore,
Therefore, the
the dialog
dialog must
must work
work on
on aa
copy,
copy, soso only
only in
in case
case of
of clicking
clicking OK,
OK, updates
updates the
the original
original Address
Address object.
object.

Then
Then there
there isis finally
finally the
the main
main program,
program, which
which starts
starts itit all:
all:

public class AddressesProgram extends Application


{
@Override
public void start(Stage stage)
{
AddressesPresenter presenter = new AddressesPresenter(stage, createModel());
Scene scene = new Scene(presenter.getView());
scene.getStylesheets().add("resources/css/styles.css");
stage.setTitle("Addresses");
stage.setScene(scene);
stage.show();
}

private Addresses createModel()


{
try
{
return new Addresses();
}
catch (Exception ex)
{
System.out.println(ex);
Platform.exit();
return null;
}
}

142
142
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT MVC
SOFTWARE DEVELOPMENT MvC

public static void main(String[] args)


{
launch(args);
}
}

There
There is
is not
not much
much toto explain,
explain, but
but you
you should
should note
note how
how the
the method
method start()
start() creates
creates aa presenter
presenter
and
and aa model
model that
that is
is sent
sent as
as aa parameter
parameter for
for the
the presenter
presenter class’s
class’s constructor.
constructor. The
The architecture
architecture
of the completed program can be illustrated as follows:
of the completed program can be illustrated as follows:

143
143
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT User defined controls

6 USER DEFINED CONTROLS


It is rarely necessary to write your own controls, but the possibility exists, and it could
even be the task to developing your own user defined controls. A control must be derived
directly or indirectly from the class Node so that it can be part of a scene graph in the
same way as all other controls, but in most cases, one will write a user defined control as
a class inheriting an existing control, as it is made for the most important functionality. If
you open the program UserControlProgram, you get the following window:

Excellent Economics and Business programmes at:

“The perfect start


of a successful,
international career.”

CLICK HERE
to discover why both socially
and academically the University
of Groningen is one of the best
places for a student to be
www.rug.nl/feb/education

144
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT User
user defined
deFIned controls
Controls

which
which contains
contains 77 custom
custom controls.
controls. The The top
top three
three have
have the
the type
type LabelField,
LabelField, consisting
consisting of
of aa
Label
Label and
and aa TextField,
TextField, while
while thethe 44 lower
lower ones
ones have
have the
the type
type Spinner.
Spinner. It’s
It’s aa kind
kind of
of button
button and
and
clicking
clicking on
on the
the circle
circle itit will
will rotate
rotate the
the line
line (default
(default 22 seconds),
seconds), after
after which
which thethe component
component
will
will trigger
trigger an
an ActionEvent.
ActionEvent. The The program’s
program’s start()
start() method
method isis as
as follows:
follows:

public void start(Stage primaryStage)


{
Spinner spin1 = new Spinner(50, Color.RED, Color.WHITE);
spin1.setOnAction(e -> System.out.println("ok 1"));
Spinner spin2 = new Spinner(70);
spin2.setOnAction(e -> System.out.println("ok 2"));
Spinner spin3 = new Spinner(50, Color.RED, Color.WHITE, 1000);
spin3.setOnAction(e -> System.out.println("ok 3"));
spin3.setBackground(Color.DARKGREEN);
spin3.setForeground(Color.LIGHTGREEN);
Spinner spin4 = new Spinner(50, Color.DARKBLUE, Color.LIGHTBLUE);
spin4.setOnAction(e -> System.out.println("ok 4"));
spin4.setTime(5000);
HBox pane = new HBox(20, spin1, spin2, spin3, spin4);
LabelField field = null;
VBox root = new VBox(20, field = new LabelField("Svend", "", 100),
new LabelField("Knud", "", 100, 300), new
LabelField("Valdemar", "", 100, 400), pane);
field.textProperty().addListener((ob, ov, nv) -> System.out.println(nv));
field.setFont(Font.font("Arial", 18));
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root);
primaryStage.setTitle("Hello controls");
primaryStage.setScene(scene);
primaryStage.show();
}

Initially,
Initially, 44 Spinner
Spinner controls
controls are
are created,
created, and
and the
the goal
goal isis to
to show
show how
how toto create
create aa Spinner
Spinner (which
(which
parameters
parameters can can be be specified
specified byby the
the constructor)
constructor) and and which
which properties
properties cancan be
be subsequently
subsequently
set.
set. Here you should especially note how to associate an event handler. They are all
Here you should especially note how to associate an event handler. They are all trivial
trivial
and
and the
the goal
goal isis to
to see
see (with
(with aa text
text on
on the
the console)
console) when
when the the events
events inin question
question occurs.
occurs. The
The
44 Spinner
Spinner controls
controls are are placed
placed in
in aa HBox
HBox that
that can
can be be added
added to to the
the root
root of
of the
the window.
window. When
When
root
root isis created
created (as(as aa VBox),
VBox), first
first 33 LabelField
LabelField controls
controls are are added,
added, where
where you
you will
will primarily
primarily
observe
observe the parameters of the constructor. For the first control is associated with an
the parameters of the constructor. For the first control is associated with an event
event
handler
handler –– which
which isis trivial
trivial and
and where
where the
the goal
goal isis to
to show
show that
that you
you can
can associate
associate an
an event
event
handlers
handlers to to the
the entry
entry field.
field.

Both
Both user
user controls
controls are
are simple
simple and
and hardly
hardly have
have not
not the
the great
great pratical
pratical interest,
interest, but
but they
they show
show
something
something about
about how
how toto create
create aa user
user control.
control. In
In the
the rest
rest of
of this
this chapter
chapter II will
will describe
describe
how
how the
the two
two controls
controls are
are written.
written.

145
145
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT User
userdefined
deFInedcontrols
Controls

6.1
6.1 AA LABELFIELD
LABELFIELD
When
When writing
writing aa custom
custom control,
control, the
the two
two main
main decisions
decisions are
are what
what properties
properties should
should be be
and
and what
what events
events the
the control
control isis going
going to
to fire.
fire. The
The actual
actual control
control is,
is, in
in fact,
fact, not
not much
much moremore
than
than aa HBox
HBox with
with aa Label
Label andand aa TextField,
TextField, andand in in addition
addition toto the
the properties
properties of of aa HBox,
HBox,
you
you should
should bebe able
able to
to set
set the
the width
width ofof the
the Label
Label and
and thethe TextField,
TextField, respectively,
respectively, and
and set
set the
the
text
text for
for both
both components.
components. Finally,
Finally, there
there must
must be be aa property
property forfor the
the font
font that
that should
should apply
apply
to
to both
both thethe Label
Label and
and thethe TextField,
TextField, so
so that
that both
both components
components always
always usesuses the
the same
same font.
font.
When
When you you enter
enter text
text oror otherwise
otherwise change
change the the text
text for
for the
the TextField
TextField component,
component, itit should
should
send
send ChangeEvents,
ChangeEvents, and and inin order
order for
for these
these events
events toto be
be captured
captured from
from an an application,
application, thethe
component
component returns
returns thethe TextField
TextField component’s
component’s textProperty.
textProperty. The The component
component can can then
then be be
written
written where
where II have
have only
only included
included one
one of of 55 constructors
constructors and and two
two properties:
properties:

public class LabelField extends HBox


{
private Label label;
private TextField field = new TextField();

public LabelField(String caption, String text, double captionWidth,


double fieldWidth)
{
setAlignment(Pos.BASELINE_LEFT);
label = caption == null ? new Label() : new Label(caption);
if (text != null) field.setText(text);
if (captionWidth > 0) label.setPrefWidth(captionWidth);
if (fieldWidth > 0) field.setPrefWidth(fieldWidth);
label.setAlignment(Pos.CENTER_RIGHT);
this.setSpacing(10);
getChildren().addAll(label, field);
}

public double getCaptionWidth()


{
return captionWidthProperty().get();
}

public void setCaptionWidth(double captionWidth)


{
captionWidthProperty().set(captionWidth);
}

public DoubleProperty captionWidthProperty()


{
return label.prefWidthProperty();
}

146
146
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT User defined controls
SOFTWARE DEVELOPMENT user deFIned Controls

public String getText()


{
return textProperty().get();
}

public void setText(String text)


{
textProperty().set(text);
}

public StringProperty textProperty()


{
return field.textProperty();
}
}

In fact, there is not much to notice, and the most important code is found in the constructor,
where the two components should be placed “nicely” in the container. Note that the class
inherits HBox and therefore is a component that can be inserted into a scene graph like
all other controls.

American online
LIGS University
is currently enrolling in the
Interactive Online BBA, MBA, MSc,
DBA and PhD programs:

▶▶ enroll by September 30th, 2014 and


▶▶ save up to 16% on the tuition!
▶▶ pay in 10 installments / 2 years
▶▶ Interactive Online education
▶▶ visit www.ligsuniversity.com to
find out more!

Note: LIGS University is not accredited by any


nationally recognized accrediting agency listed
by the US Secretary of Education.
More info here.

147
147
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT User
user defined
deFIned controls
Controls

6.2
6.2 AA CANVAS
CANVAS
Before
Before II look
look at
at the
the last
last control,
control, II will
will mention
mention aa Canvas,
Canvas, which
which isis aa control
control II have
have not
not
previously
previously mentioned.
mentioned. AA Canvas
Canvas isis aa control
control consisting
consisting of
of aa drawing
drawing surface
surface where
where you
you can
can
draw
draw geometric
geometric figures
figures and
and text
text and
and insert
insert images
images using
using drawing
drawing features.
features. You
You cancan also
also
manipulate
manipulate thethe individual
individual pixels
pixels using
using aa PixelWriter.
PixelWriter.

AA Canvas
Canvas has
has attached
attached aa GraphicsContext
GraphicsContext class
class that
that represents
represents the
the graphic
graphic content
content and
and
provides
provides drawing
drawing functions
functions available.
available. You
You are
are encouraged
encouraged toto investigate
investigate which
which methods
methods
GraphicsContext
GraphicsContext makes
makes available.
available.

For
For example,
example, the
the program
program CanvasProgram
CanvasProgram opens
opens the
the following
following window:
window:

where
where aa square,
square, aa circle,
circle, aa text
text and
and aa curve
curve (a
(a parable)
parable) are
are drawn
drawn and
and aa picture
picture isis added.
added.
The
The new
new isis that
that itit has
has been
been done
done using
using aa Canvas:
Canvas:

package canvasprogram;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.canvas.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.scene.paint.*;
import javafx.scene.text.*;
import javafx.stage.Stage;

public class CanvasProgram extends Application


{
@Override
public void start(Stage stage)
{
Canvas canvas = new Canvas(520, 160);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.setLineWidth(2.0);
gc.strokeRect(20, 20, 120, 120);

148
148
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT User defined controls
SOFTWARE DEVELOPMENT user deFIned Controls

gc.setFill(Color.RED);
gc.fillOval(40, 40, 80, 80);
gc.setFont(Font.font(24));
gc.strokeText("Hello", 50, 90);
Image image = new Image("resources/images/stone.jpg");
gc.drawImage(image, 160, 20, 120, 120);
writeGraph(gc);
Pane root = new Pane();
root.getChildren().add(canvas);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Drawing on a Canvas");
stage.show();
}

private void writeGraph(GraphicsContext gc)


{
PixelWriter writer = gc.getPixelWriter();
for (double x = 300; x < 500; x += 0.25)
writer.setColor((int)x, (int)y(x), Color.BLUE);
}

private double y(double x)


{
return x * x / 100 – 8 * x + 1620;
}

public static void main(String[] args)


{
launch(args);
}
}

The code
The code is is easy
easy enough
enough to to figure
figure out.
out. In
In the
the method
method start(),
start(), aa Canvas
Canvas object
object is
is created
created of of aa
certain size,
certain size, and
and aa reference
reference is is created
created toto the
the Canvas
Canvas object’s
object’s GraphicsContext.
GraphicsContext. For For this
this object,
object,
the width
the width of of the
the pen
pen to
to bebe drawn
drawn withwith isis defined,
defined, then
then aa drawing
drawing tool tool is
is used
used toto draw
draw aa
rectangle. Since
rectangle. Since nothing
nothing is is said
said about
about the
the color,
color, it
it is
is drawn
drawn with
with aa black
black pen.
pen. Next,
Next, aa red
red
fill color
fill color isis added
added andand aa filled
filled circle
circle is
is drawn.
drawn. Note
Note specially
specially what
what the
the drawing
drawing function
function is is
called. As
called. As aa next
next step,
step, aa font
font isis defined
defined andand aa text
text is
is drawn.
drawn. Finally,
Finally, an
an image
image is is inserted
inserted
and finally
and finally the
the method
method writeGraph()
writeGraph() is is called,
called, which
which draws
draws the
the curve.
curve. The
The curve
curve isis not
not too
too
“nice” –
“nice” – is
is some
some pixelated
pixelated – – and
and there
there are
are other
other and
and better
better ways
ways toto draw
draw such
such aa graph,
graph, but
but
the example
the example should
should show
show howhow to to manipulate
manipulate the the individual
individual pixels
pixels in
in aa Canvas.
Canvas. Finally,
Finally, note
note
that aa Canvas
that Canvas is is aa node,
node, and
and therefore
therefore cancan be
be added
added to to aa scene
scene graph.
graph.

149
149
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT user defined
User deFIned controls
Controls

6.3 A
6.3 A SPINNER
SPINNER
The custom
The custom control
control can
can be
be written
written as
as follows,
follows, where
where II have
have not
not shown
shown the
the code
code for
for the
the
three properties
three properties for
for setting
setting the
the rotation
rotation speed
speed and
and color
color and
and only
only one
one constructor:
constructor:

public class Spinner extends Canvas


{
private ObjectProperty<EventHandler<ActionEvent>> onActionProperty =
new SimpleObjectProperty<EventHandler<ActionEvent>>();
private IntegerProperty time = new SimpleIntegerProperty();
private ObjectProperty<Color> background = new SimpleObjectProperty();
private ObjectProperty<Color> foreground = new SimpleObjectProperty();
private double size;
private Circle circle;
private Transition transition;

public Spinner(double size, Color background, Color foreground, int time)


{
super(size, size);
this.size = size;
setBackground(background);

150
150
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT User defined controls
SOFTWARE DEVELOPMENT user deFIned Controls

setForeground(foreground);
setTime(time);
circle = new Circle(size / 2, size / 2, size / 2);
transition = createTransition();
transition.setOnFinished(this::clicked);
draw();
this.addEventHandler(MouseEvent.MOUSE_CLICKED, new ClickHandler());
this.setEffect(new Lighting());
}

private void draw()


{
GraphicsContext gc = getGraphicsContext2D();
gc.setFill(getBackground());
gc.fillOval(0, 0, size, size);
gc.setFill(getForeground());
double s = size / 2;
gc.fillRect(s, s – 1, s, 3);
gc.fillRect(s – 2, s – 2, 5, 5);
}

public EventHandler<ActionEvent> getOnAction()


{
return onActionProperty.get();
}

public void setOnAction(EventHandler<ActionEvent> handler)


{
onActionProperty.set(handler);
}

public ObjectProperty<EventHandler<ActionEvent>> onActionProperty()


{
return onActionProperty;
}

private void clicked(ActionEvent e)


{
if (getOnAction() != null) getOnAction().handle(new ActionEvent());
}

private RotateTransition createTransition()


{
RotateTransition trans =
new RotateTransition(Duration.millis(getTime()), this);

151
151
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT User defined controls
SOFTWARE DEVELOPMENT user deFIned Controls

trans.setByAngle(360);
trans.setCycleCount(1);
return trans;
}

class ClickHandler implements EventHandler<MouseEvent>


{
public void handle(MouseEvent e)
{
if (circle.contains(e.getX(), e.getY())) transition.play();
}
}
}

Mostly happens in the constructor that initially initiates properties and creates a Transition
Mostly happens in the constructor that initially initiates properties and creates a Transition
for a rotation. You should note that an event handler is associated with an event that occurs
for a rotation. You should note that an event handler is associated with an event that occurs
when the rotation ends and that it fires an ActionEvent if there is a listener. The constructor
when the rotation ends and that it fires an ActionEvent if there is a listener. The constructor
also calls the method draw(), which draws the component on a Canvas. Note that there is
also calls the method draw(), which draws the component on a Canvas. Note that there is
no particular reason for using a Canvas (in addition to showing how), as you could achieve
no particular reason for using a Canvas (in addition to showing how), as you could achieve
the same with existing Node classes. The class also has a Circle object that is used to make
the same with existing Node classes. The class also has a Circle object that is used to make
it easy to test in the event handler for click with the mouse and if the circle is clicked.
it easy to test in the event handler for click with the mouse and if the circle is clicked.

152
152
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX and
and concurrency
ConCurrenCy

7
7 JAVAFX AND CONCURRENCY
Java
Java GUI
GUI applications
applications are
are generally
generally multi-threaded,
multi-threaded, and and similar
similar to
to Swing
Swing JavaFX
JavaFX uses
uses aa special
special
thread
thread toto update
update the
the user
user interface.
interface. This
This thread
thread isis called
called JavaFX
JavaFX Application
Application Thread.
Thread. Since
Since all
all
nodes
nodes inin aa the
the program’s
program’s scene
scene graph
graph are
are not
not thread-safe
thread-safe (for(for the
the reasons
reasons of
of performence),
performence),
there
there are
are the
the same
same challenges
challenges that
that you
you know
know from
from Swing
Swing that
that you
you can
can not
not directly
directly update
update
them
them from
from another
another thread,
thread, but
but itit should
should bebe done
done by by calling
calling aa method
method performed
performed in in the
the
JavaFX
JavaFX Application
Application Thread.
Thread. In In this
this chapter
chapter II want
want to to show
show what
what JavaFX
JavaFX makes
makes available
available to to
make
make itit simple.
simple. The
The program
program UpdateGUI
UpdateGUI opens opens thethe following
following window:
window:

If
If you
you click
click the
the Start
Start button,
button, the
the program
program starts
starts aa method
method that
that takes
takes aa long
long time
time andand after
after
the
the method
method isis completed,
completed, the the top
top label
label isis updated.
updated. Clicking
Clicking the
the Clear
Clear button
button deletes
deletes thethe
content
content of of the
the top
top label.
label. IfIf you
you try
try the
the program
program while
while the
the top
top radio
radio button
button isis pressed,
pressed, youyou
will
will find
find that
that nothing
nothing happens
happens when
when you you click
click the
the Clear
Clear button
button –– atat least
least not
not before
before the the
method started of the Start button is completed. The user experiences
method started of the Start button is completed. The user experiences that the program that the program
“hangs”.
“hangs”. Solutions
Solutions are, are, ofof course,
course, toto execute
execute thethe method
method that
that takes
takes time,
time, inin itsits own
own
thread.
thread. Pressing
Pressing the the middle
middle radio
radio button
button and and clicking
clicking Start
Start again
again executes
executes thethe method
method in in
aa background
background thread,
thread, but but now
now you
you getget an
an exception.
exception. TheThe reason
reason isis that
that the
the background
background
thread
thread tries to update the JavaFX Application Thread, which raises an exception. On
tries to update the JavaFX Application Thread, which raises an exception. On the
the
other
other hand,
hand, press
press the
the bottom
bottom radio
radio button
button andand click
click Start
Start again,
again, so
so itit runs
runs as
as itit should,
should,
where
where thethe top
top label
label isis updated
updated on on aa regular
regular basis,
basis, and
and you
you can
can delete
delete that
that label
label at
at any
any time
time
by
by clicking
clicking thethe Clear
Clear button.
button.

public class UpdateGUI extends Application


{
private Label label = new Label("Not running…");
private RadioButton cmd1 = new RadioButton("Application thread");
private RadioButton cmd2 = new RadioButton("Background thread");
private RadioButton cmd3 = new RadioButton("Platform.runLater()");
private Button cmdOk;

153
153
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX and concurrency
SOFTWARE DEVELOPMENT JavaFX and ConCurrenCy

@Override
public void start(Stage stage)
{
ToggleGroup group = new ToggleGroup();
cmd1.setToggleGroup(group);
cmd2.setToggleGroup(group);
cmd3.setToggleGroup(group);
cmd1.setSelected(true);
HBox commands = new HBox(10, createButton("Clear", e -> label.setText("")),
cmdOk = createButton("Start", this::work));
commands.setAlignment(Pos.CENTER);
VBox root = new VBox(20, label, cmd1, cmd2, cmd3, commands);
root.setPadding(new Insets(20, 20, 20, 20));
root.setAlignment(Pos.CENTER);
Scene scene = new Scene(root, 300, 250);
stage.setScene(scene);
stage.setTitle("Update GUI");
stage.show();
}

private void work(ActionEvent e)


{
cmdOk.setDisable(true);
if (cmd1.isSelected()) work1();
else
{
Thread th = cmd2.isSelected() ? new Thread(() -> work1()) :
new Thread(() -> work2());
th.setDaemon(true);
th.start();
}
}

private void work1()


{
for(int i = 1; i <= 10; i++)
{
label.setText("Start calulation " + i);
calculate();
}
label.setText("All calulations terminated");
cmdOk.setDisable(false);
}

private void work2()


{
for(int i = 1; i <= 10; i++)
{

154
154
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX and concurrency
SOFTWARE DEVELOPMENT JavaFX and ConCurrenCy

String text = "Start calulation " + i;


Platform.runLater(() -> label.setText(text));
calculate();
}
String text = "All calulations terminated";
Platform.runLater(() -> label.setText(text));
Platform.runLater(() -> cmdOk.setDisable(false));
}

private Button createButton(String text,


EventHandler<ActionEvent> handler)
{
Button cmd = new Button(text);
cmd.setOnAction(handler);
return cmd;
}

private void calculate()


{
double y = 0;
for (int i = 0; i < 10; ++i) for (int j = 0; j < 10000000; ++j)
y = Math.sin(Math.sqrt(2));
}

Join the best at Top master’s programmes


• 3
 3rd place Financial Times worldwide ranking: MSc
the Maastricht University International Business
• 1st place: MSc International Business
School of Business and • 1st place: MSc Financial Economics
• 2nd place: MSc Management of Learning

Economics! • 2nd place: MSc Economics


• 2nd place: MSc Econometrics and Operations Research
• 2nd place: MSc Global Supply Chain Management and
Change
Sources: Keuzegids Master ranking 2013; Elsevier ‘Beste Studies’ ranking 2012;
Financial Times Global Masters in Management ranking 2012

Maastricht
University is
the best specialist
university in the
Visit us and find out why we are the best! Netherlands
(Elsevier)
Master’s Open Day: 22 February 2014

www.mastersopenday.nl

155
155
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX and concurrency
SOFTWARE DEVELOPMENT JavaFX and ConCurrenCy

public static void main(String[] args)


{
launch(args);
}
}

The method to be performed is performed in work1() and work2(), which both performs
the method calculate() 10 times, respectively. Before each execution of the method, the
program’s label is updated. calculate() performs nothing interesting, but it does many
calculations that take a long time and the goal is that it is a method that constantly uses
the machine’s processor.

With regard to the user interface, there is not much to explain, and you should primarily
note the method work(), which is the event handler for the Start button. The method tests
which radio button is clicked in and if it is the top nothing else happens than the method
work1() is called. That is, it is executed in the JavaFX Application Thread with the result
that the program “hangs” until work1() is completed. For example, you will not see that the
Start button is being disabled. Is it the middle radio button that is pushed in, the method
work1() is performed again, but this time in its own thread. The result is an exception
when the method tries to update the Label component. On the other hand, if the bottom
radio button is pressed, the method work2() is performed, which is in principle is identical
to work1(), but when the user interface is to be updated, it happens with the statement:

Platform.runLater(() -> label.setText(text));

which simply means that the component label is updated in the JavaFX Application Thread.
The class Platform has two static methods that relates to the JavaFX Application Thread:

-- public static boolean isFxApplicationThread()


-- public static void runLater(Runnable runnable)

where the first returns true if the calling thread are the JavaFX Application Thread, while
the other creates a Runnable object to be executed by the JavaFX Application Thread at
some point when the thread is running.

7.1
7.1 A TASK
To support threads in GUI programming, JavaFX offers a very simple concurrency framework
based on the existing Java framework for concurrency. The framework consists of a single
enumeration, called State, that defines the states that a thread may be in, as well as a single

156
156
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT JavaFX and concurrency

event type called WorkerStateEvent, and a thread fires such an event when it switches state.
Else there are only four types of threads that constitute a simple hierarchy, the top one
being an interface, while the other three are specific types:

Precisely, an instance of the Worker interface is a task to be performed by one or more


background threads. The task’s state is observable from the JavaFX Application Thread. The
Task, Service, and ScheduledService classes are abstract classes that implement the Worker
interface and represent different kinds of tasks. The Task class represents a task that can
be performed once and a Task object can not be reused. The Service class represents a Task
that can be repeated, and finally, the ScheduledService class represents a Service that can be
performed at certain times. In the following I will show an example of a Task and a Service.

The task must be to determine prime numbers – a task you have seen many times in
previous books. The goal is to have a task that for big numbers take a long time. Running
the program PrimesProgram1 opens the following window:

157
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX and
and concurrency
ConCurrenCy

IfIf you
you click
click on
on the
the Start
Start button,
button, thethe program
program determines
determines allall the
the primes
primes within
within the
the entered
entered
interval
interval and
and inserts
inserts them
them continuously
continuously in in the
the list
list box.
box. This
This happens,
happens, of of course,
course, in
in aa secondary
secondary
thread,
thread, and
and while
while the
the thread
thread isis running,
running, the
the Clear
Clear button
button can
can delete
delete the
the content
content of of the
the list
list
box,
box, and
and with
with the
the Cancel
Cancel button,
button, youyou can
can stop
stop the
the thread,
thread, and
and finally
finally with
with the
the Exit
Exit button
button
you
you can
can terminate
terminate the
the program.
program.

To
To performe
performe the
the task
task II will
will define
define aa Task
Task object.
object. You
You should
should examine
examine the
the documentation
documentation
for
for both
both Worker<V>
Worker<V> and and Task<V>,
Task<V>, but
but in
in the
the present
present case
case II have
have defined
defined the
the following
following
Task
Task where
where II have
have not
not shown
shown the
the code
code regarding
regarding the
the class’s
class’s properties:
properties:

public class PrimesTask extends Task<ObservableList<Long>>


{
private final ObservableList<Long> list =
FXCollections.<Long>observableArrayList();
private final LongProperty from = new SimpleLongProperty();
private final LongProperty to = new SimpleLongProperty();

public void clear()


{

158
158
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT JavaFX and concurrency
SOFTWARE DEVELOPMENT JavaFX and ConCurrenCy

list.clear();
}

@Override
protected ObservableList<Long> call()
{
list.clear();
long count = getTo() – getFrom() + 1;
long counter = 1;
for (long i = getFrom(); i <= getTo(); ++i, ++counter)
{
if (this.isCancelled()) break;
updateMessage("Check " + i + " as a prime number");
if (isPrime(i))
{
long n = i;
Platform.runLater(() -> list.add(n));
updateValue(FXCollections.<Long>unmodifiableObservableList(list));
}
updateProgress(counter, count);
}
return list;
}

@Override
protected void cancelled()
{
super.cancelled();
updateMessage("The task was cancelled");
}

@Override
protected void failed()
{
super.failed();
updateMessage("The task failed");
}

@Override
public void succeeded()
{
super.succeeded();
updateMessage("The task finished successfully");
}

private boolean isPrime(long number)


{
if (number == 2 || number == 3 || number == 5 || number == 7) return true;

159
159
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
JAVA DEVELOPMENT
15: MORE ABOUT JAVAFX: JavaFX and ConCurrenCy
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX and
and concurrency
ConCurrenCy
SOFTWARE DEVELOPMENT JavaFX and ConCurrenCy

if (number < 11 || number % 2 == 0) return false;


if (number < 11 || number % 2 == 0) return false;
if (number < 11 || number % 2 == 0) return false;
for (int t = 3, m = (int)Math.sqrt(number) + 1; t <= m; t += 2)
for (int t = 3, m = (int)Math.sqrt(number) + 1; t <= m; t += 2)
for (int t = 3, m = (int)Math.sqrt(number) + 1; t <= m; t += 2)
if (number % t == 0) return false;
if (number % t == 0) return false;
if (number
return true; % t == 0) return false;
return true;
}return true;
}
}}
}
}

Note first that the class inherits Task<ObservableList<Long >>. Here the parameter type
Note first that the class inherits Task<ObservableList<Long >>. Here the parameter type
Note firstthethat
specifies thethat
type class
theinherits
abstractTask<ObservableList<Long
method call() returns. The >>.two
Here the parameter
properties from and type
to
specifies the
specifiesthe type
therange that
type within the
that the abstract
abstract method call()
methodnumbers returns.
call() returns. The two properties
Thedetermined.
two properties from and to
defines which the prime are to be Theyfrom and to
are defined
defines
defines the range
the propertieswithin
range within which
which the prime
the be
prime numbers are to be determined. They are defined
as JavaFX as they must ablenumbers
to be bound are to to
bethe
determined. They Then
user interface. are defined
there
as JavaFX properties as they must be able to be bound to the user interface. Then there
as JavaFX properties as they must be able to be bound to the user
is the method call(), which is the method that is performed in its own thread. It starts interface. Then there
is the method call(), which is the method that is performed in its own thread. It starts
is thea method
with deletioncall(),
of thewhich
list’s is the method
content (what that
is notis necessary
performedininthisits example)
own thread. andItthen
startsa
with a
with is deletion
a deletion of the list’s content (what is not necessary in this example) and then
then aa
loop executed of theis list’s
that content
iterating over(what is not range.
the current necessaryForineach
thisiteration,
example)the andmethods
loop
loop is
is executed that
that isis iterating
executed updateValue() iterating over
overifthe
the current
current range. For each iteration,
iteration, the methods
updateMessage(), (only a prime is range.
found)For andeach theare
updateProgress() methods
called.
updateMessage(), updateValue() (only if a prime is found) and updateProgress() are called.
updateMessage(), updateValue() (only if a prime is found) and updateProgress()
These are the methods defined in the class Task, representing observable properties that are called.
the
These are the methods defined in the class Task, representing observable properties that the
These are the methods
user interface can bind to. defined in the class Task, representing observable properties that the
user interface can bind
user interface can bind to. to.

Lastly, three methods are overriden, which are executed according to the state change, and
Lastly, three methods are overriden, which are executed according to the state change, and
Lastly,
the onlythree methods
thing are overriden,
that happens are thatwhich are executed
a property according
is updated on the to theobject.
Task state change, and
the only thing that happens are that a property is updated on the Task object.
the only thing that happens are that a property is updated on the Task object.
Then there is the class PrimesProgram1:
Then
Then there
there is
is the
the class
class PrimesProgram1:
PrimesProgram1:
public class PrimesProgram1 extends Application
public class PrimesProgram1 extends Application
public class PrimesProgram1 extends Application
{
{
{
private PrimesTask task = new PrimesTask();
private PrimesTask task = new PrimesTask();
private PrimesTask task = new PrimesTask();
private LabelField txtFrom = new LabelField("From");
private LabelField txtFrom = new LabelField("From");
private LabelField txtFrom = new LabelField("From");
private LabelField txtTo = new LabelField("To");
private LabelField txtTo = new LabelField("To");
private LabelField txtTo = new LabelField("To");
private ListView<Long> lstPrimes = new ListView();
private ListView<Long> lstPrimes = new ListView();
private ListView<Long> lstPrimes = new ListView();
private TextField txtMessages = new TextField();
private TextField txtMessages = new TextField();
private TextField txtMessages = new TextField();
private ProgressBar progressBar = new ProgressBar(0);
private ProgressBar progressBar = new ProgressBar(0);
private ProgressBar progressBar = new ProgressBar(0);

The class has an instance of PrimesTask that represents the task to be performed. Note that
The class has an instance of PrimesTask that represents the task to be performed. Note that
The class
the class uses
has an
theinstance
custom of PrimesTask
control from that representschapter.
the previous the taskI doto be
notperformed. Note that
want to display the
the class uses the custom control from the previous chapter. I do not want to display the
the class
full code uses
here,the
butcustom control method
the following from theis previous chapter.
called from start():I do not want to display the
full code here, but the following method is called from start():
full code here, but the following method is called from start():
public void bind(Worker<ObservableList<Long>> worker)
public void bind(Worker<ObservableList<Long>> worker)
public void bind(Worker<ObservableList<Long>> worker)
{
{
{
txtFrom.textProperty().bindBidirectional(task.fromProperty(),
txtFrom.textProperty().bindBidirectional(task.fromProperty(),
txtFrom.textProperty().bindBidirectional(task.fromProperty(),
new NumberStringConverter());
new NumberStringConverter());
new NumberStringConverter());
txtTo.textProperty().bindBidirectional(task.toProperty(),
txtTo.textProperty().bindBidirectional(task.toProperty(),
txtTo.textProperty().bindBidirectional(task.toProperty(),
new NumberStringConverter());
new NumberStringConverter());
progressBar.progressProperty().bind(worker.progressProperty());
new NumberStringConverter());
progressBar.progressProperty().bind(worker.progressProperty());
progressBar.progressProperty().bind(worker.progressProperty());
progressBar.visibleProperty().bind(worker.progressProperty().isNotEqualTo(
progressBar.visibleProperty().bind(worker.progressProperty().isNotEqualTo(
progressBar.visibleProperty().bind(worker.progressProperty().isNotEqualTo(
new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS)));
new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS)));
new SimpleDoubleProperty(ProgressBar.INDETERMINATE_PROGRESS)));

160
160
160
160
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT JavaFX and concurrency
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX and
and ConCurrenCy
ConCurrenCy

lstPrimes.itemsProperty().bind(worker.valueProperty());
lstPrimes.itemsProperty().bind(worker.valueProperty());
txtMessages.textProperty().bind(worker.messageProperty());
txtMessages.textProperty().bind(worker.messageProperty());
}
}

which
which binds
binds the
the components
components inin the
the user
user interface
interface to
to properties
properties in
in the
the Task
Task object.
object. Finally,
Finally,
there is the event handler for the Start button, which creates a background thread to execute
there is the event handler for the Start button, which creates a background thread to execute
the
the Task
Task object:
object:

private void start(ActionEvent e)


private void start(ActionEvent e)
{
{
Thread th = new Thread(task);
Thread th = new Thread(task);
th.setDaemon(true);
th.setDaemon(true);
th.start();
th.start();
}
}

When
When thethe thread
thread performs
performs the
the method
method start(),
start(), it
it is
is the
the method
method call()
call() in
in the
the class
class PrimesTask
PrimesTask
that is performed.
that is performed.

When you try out the program, it should all work as described, but click on the Start
button
button again,
again, you
you will
will find
find that
that nothing
nothing happens.
happens. As
As mentioned
mentioned above,
above, aa Task
Task object
object can
can
only be executed once and this is where a Service object is an option.
only be executed once and this is where a Service object is an option.

161
161
161
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT JavaFX
JavaFX and
and concurrency
ConCurrenCy

7.2
7.2 AA SERVICE
SERVICE
The
The program
program PrimesProgram2
PrimesProgram2 opens
opens the
the same
same window
window as
as shown
shown inin the
the previous
previous example,
example, and
and
the
the class
class PrimesTask
PrimesTask isis unchanged.
unchanged. OnOn thethe other
other hand,
hand, the
the following
following class
class has
has been
been added
added
which
which represents
represents aa Service,
Service, and
and again
again II have
have not
not shown
shown the
the code
code for
for the
the two
two properties:
properties:

public class PrimesService extends Service<ObservableList<Long>>


{
private PrimesTask task;
private final LongProperty from = new SimpleLongProperty();
private final LongProperty to = new SimpleLongProperty();

public void clear()


{
if (task != null ) task.clear();
}

@Override
protected Task<ObservableList<Long>> createTask()
{
task = new PrimesTask();
task.setFrom(from.get());
task.setTo(to.get());
return task;
}
}

AA Service
Service isis not
not much
much more
more thanthan aa wrapper
wrapper forfor aa Task,
Task, and
and then
then youyou must
must override
override the
the
method createTask()
method createTask() that
that isis performed
performed every
every time
time the
the service
service isis performed.
performed. ItIt creates
creates the
the
task to
task to be
be executed
executed and
and in
in this
this case
case initialized
initialized with
with the
the current
current values.
values.

The class
The class PrimesProgram2
PrimesProgram2 isis also
also almost
almost identical
identical to
to PrimesProgram1,
PrimesProgram1, and
and the
the main
main difference
difference
isis that
that the
the Task
Task object
object has
has been
been replaced
replaced by
by aa Service
Service object
object and
and that
that the
the event
event handler
handler for
for
the Start
the Start button
button has
has been
been changed.
changed.

162
162
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT 3D
3d Shapes
shapes

8
8 3D
3D SHAPES
SHAPES
JavaFX
JavaFX also
also supports
supports 3D
3D graphics
graphics in
in some
some degree,
degree, although
although the
the possibilities
possibilities are
are aa bit
bit limited,
limited,
but
but future
future versions
versions of
of the
the language
language will
will undoubtedly
undoubtedly offer
offer more.
more. The
The following
following isis aa brief
brief
introduction
introduction toto what
what it’s
it’s all
all about,
about, more
more than
than examples
examples ofof practical
practical applications.
applications.

There
There are
are only
only aa few
few classes,
classes, all
all derived
derived from
from Shape3D,
Shape3D, and and inin fact,
fact, there
there are
are only
only four
four
examples
examples ofof specific
specific shapes:
shapes: Box,
Box, Sphere,
Sphere, Cylinder
Cylinder and
and MeshView,
MeshView, where
where thethe latter
latter represents
represents
aa customized
customized shape.
shape. You
You can
can achieve
achieve 3D3D visualization
visualization using
using light
light and
and cameras
cameras that
that are
are also
also
nodes
nodes and
and can
can be
be included
included in in the
the scene
scene graph
graph and
and how
how aa shape
shape isis displayed
displayed isis determined
determined
by
by the
the position
position of
of the
the light
light sources
sources and
and cameras
cameras in
in the
the scene
scene graph.
graph.

However,
However, Java3D
Java3D isis not
not necessarily
necessarily supported,
supported, but
but itit will
will be
be on
on most
most modern
modern machines.
machines.
You
You can
can test
test where
where itit isis the
the case
case with
with the
the following
following program
program (or(or equivalent
equivalent statements):
statements):

package check3d;

import javafx.application.*;

public class Check3D


{
public static void main(String[] args)
{
if (Platform.isSupported(ConditionalFeature.SCENE3D))
System.out.println("3D is supported");
else System.out.println("No 3D support");
}
}

The
The starting
starting point
point for
for 3D
3D graphics
graphics isis aa 3D3D coordinate
coordinate systemsystem with
with the
the origin
origin in
in the
the upper
upper
left
left corner
corner ofof the
the screen
screen andand aa zz axis
axis that
that points
points into
into thethe screen
screen while
while the
the x-axis
x-axis and
and the
the
y-axis
y-axis are
are oriented
oriented in in the
the same
same wayway as as in
in 2D
2D graphics.
graphics. IfIf in in 2D
2D you
you add
add two
two shapes
shapes toto
the
the scene
scene graph
graph that
that overlap,
overlap, itit isis the
the figure
figure added
added last
last that
that overlaps
overlaps the
the first,
first, but
but this
this isis
not
not necessarily
necessarily in
in 3D,
3D, as as the
the depth
depth alsoalso plays
plays aa role.
role. ItIt can
can be
be illustrated
illustrated with
with the
the program
program
Rectangles3D
Rectangles3D thatthat opens
opens thethe following
following window:
window:

163
163
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT 3d Shapes
3D shapes

where you
where you should
should note
note that
that the
the green
green rectangle
rectangle isis drawn
drawn in
in front
front of
of the
the red.
red. The
The program’s
program’s
code is:
code is:

public class Rectangles3D extends Application


{
@Override
public void start(Stage stage)
{
Rectangle red = new Rectangle(100, 100);
red.setFill(Color.RED);
red.setTranslateX(100);
red.setTranslateY(100);
red.setTranslateZ(400);
Rectangle green = new Rectangle(100, 100);
green.setFill(Color.GREEN);
green.setTranslateX(150);
green.setTranslateY(150);
green.setTranslateZ(300);
Group center = new Group(green, red);
CheckBox check = new CheckBox("DepthTest for Rectangles");
check.setSelected(true);
check.selectedProperty().addListener((prop, oldValue, newValue) -> {

Need help with your


dissertation?
Get in-depth feedback & advice from experts in your
topic area. Find out what you can do to improve
the quality of your dissertation!

Get Help Now

Go to www.helpmyassignment.co.uk for more info

164
164
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

if (newValue)
{
red.setDepthTest(DepthTest.ENABLE);
green.setDepthTest(DepthTest.ENABLE);
}
else
{
red.setDepthTest(DepthTest.DISABLE);
green.setDepthTest(DepthTest.DISABLE);
}
});
BorderPane root = new BorderPane(center, check, null, null, null);
root.setStyle("-fx-background-color: transparent;");
root.setPadding(new Insets(20, 20, 20, 20));
Scene scene = new Scene(root, 300, 200, true);
scene.setCamera(new PerspectiveCamera());
stage.setScene(scene);
stage.setTitle("Depth Test");
stage.show();
}

public static void main(String[] args)


{
launch(args);
}
}

In the method start(), two rectangles, a red and a green are defined, and the new is that this
In the method start(), two rectangles, a red and a green are defined, and the new is that this
time, there is also defined a value for the z axis, that respectively is 400 and 300. That is, the
time, there is also defined a value for the z axis, that respectively is 400 and 300. That is, the
red rectangle lies farther away than the green one. The two rectangles are added to a Group
red rectangle lies farther away than the green one. The two rectangles are added to a Group
node, but so that the red is added last, and it should therefore overlap the green, but that
node, but so that the red is added last, and it should therefore overlap the green, but that
is the opposite that happens as the red is farther away. To make it happen, two more things
is the opposite that happens as the red is farther away. To make it happen, two more things
have to be done. When you create the Scene object, you must specify another parameter
have to be done. When you create the Scene object, you must specify another parameter
that tells to use 3D graphics, and you should also attach a camera to the scene graph.
that tells to use 3D graphics, and you should also attach a camera to the scene graph.

The window also has a checkbox and the meaning is that you can turn the 3D effect on or
The window also has a checkbox and the meaning is that you can turn the 3D effect on or
off and unchecking the box displays the graphics as the usual 2D graphics, where the red
off and unchecking the box displays the graphics as the usual 2D graphics, where the red
rectangle will overlap the green.
rectangle will overlap the green.

165
165
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT 3d Shapes
3D shapes

8.1 BOX,
8.1 BOX, SPHERE
SPHERE AND
AND CYLINDER
CYLINDER
Asmentioned,
As mentioned,JavaFX
JavaFXisisborn
bornwith
withthree
threeshape
shapeclasses,
classes,representing
representingrespectively
respectivelyaabox,
box,aasphere
sphere
and aa cylinder.
and cylinder. All
All classes
classes inherit
inherit from
from Shape3D
Shape3D and
and inherit
inherit here
here three
three crucial
crucial properties:
properties:

1. material
1. material
2. drawing
2. drawing mode
mode
3. cull
3. cull face
face

as all
as all are
are explained
explained later,
later, but
but the
the first
first isis used
used inin the
the following
following example,
example, and and asas the
the name
name
says, itit tells
says, tells how
how the
the surface
surface should
should be be drawn.
drawn. WhenWhen youyou createcreate aa Shape3D,
Shape3D, itit has
has its
its center
center
in the
in the starting
starting point
point of
of the
the coordinate
coordinate system,
system, butbut as
as itit isis aa node,
node, itit can
can be
be moved
moved using
using aa
transformation. Finally,
transformation. Finally, its
its position
position andand size
size are
are determined
determined by by the
the camera
camera used
used toto display
display
the figure,
the figure, and and where
where thethe camera
camera isis located
located in in the
the coordinate
coordinate system.system. The The current
current location
location
of the
of the camera
camera cancan make
make itit difficult
difficult to
to predict
predict the the actual
actual location
location of of aa figure.
figure. The
The application
application
ShapesProgram opens
ShapesProgram opens the
the following
following window
window and and shows
shows examples
examples of of the
the three
three shapes:
shapes:

The box
The box object
object hashas been
been moved
moved with
with aa translation
translation butbut isis also
also rotated.
rotated. The
The others
others are
are moved
moved
with aa translation,
with translation, but but when
when the
the cylinder
cylinder isis slightly
slightly deformed,
deformed, itit isis because
because the
the camera
camera isis
located at
located at the
the left.
left. You
You should
should also
also note
note that
that the
the color
color isis determined
determined by by the
the location
location of
of the
the
light. The
light. The code
code isis as
as follows:
follows:

package shapesprogram;

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.scene.paint.*;

public class ShapesProgram extends Application


{
@Override
public void start(Stage stage)
{

166
166
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

Scene scene = new Scene(new Group(createBox(), createSphere(),


createCylinder(), createLight()), 500, 200, true);
scene.setCamera(createCamera());
stage.setScene(scene);
stage.setTitle("3D Shapes");
stage.show();
}

private Box createBox()


{
Box b = new Box(100, 150, 300);
b.setTranslateX(150);
b.setTranslateY(200);
b.setTranslateZ(200);
b.setRotate(20);
b.setMaterial(new PhongMaterial(Color.GREEN));
return b;
}

private Sphere createSphere()


{
Sphere s = new Sphere(100);
s.setTranslateX(400);
s.setTranslateY(150);

Brain power By 2020, wind could provide one-tenth of our planet’s


electricity needs. Already today, SKF’s innovative know-
how is crucial to running a large proportion of the
world’s wind turbines.
Up to 25 % of the generating costs relate to mainte-
nance. These can be reduced dramatically thanks to our
systems for on-line condition monitoring and automatic
lubrication. We help make it more economical to create
cleaner, cheaper energy out of thin air.
By sharing our experience, expertise, and creativity,
industries can boost performance beyond expectations.
Therefore we need the best employees who can
meet this challenge!

The Power of Knowledge Engineering

Plug into The Power of Knowledge Engineering.


Visit us at www.skf.com/knowledge

167
167
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

s.setTranslateZ(300);
s.setMaterial(new PhongMaterial(Color.RED));
return s;
}

private Cylinder createCylinder()


{
Cylinder c = new Cylinder(100, 300);
c.setTranslateX(650);
c.setTranslateY(200);
c.setTranslateZ(400);
c.setMaterial(new PhongMaterial(Color.BLUE));
return c;
}

private PointLight createLight()


{
PointLight p = new PointLight();
p.setTranslateX(100);
p.setTranslateY(100);
p.setTranslateZ(-100);
return p;
}

private PerspectiveCamera createCamera()


{
PerspectiveCamera c = new PerspectiveCamera(false);
c.setTranslateX(100);
c.setTranslateY(100);
c.setTranslateZ(-100);
return c;
}

public static void main(String[] args)


{
launch(args);
}
}

The code isis actually


actually quite
quitesimple
simpleandandeasy
easyenough
enoughtoto figure
figureout, butbut
out, on on
the the
other hand,
other the
hand,
effect
the is more
effect difficult
is more to figure
difficult out.out.
to figure AllAll
of of
thisthis
happens
happens in in
thethe
lastlast
5 5methods
methodsthat
thatcreate
createa
aBox
Boxobject,
object,a aSphere
Sphereobject,
object,aaCylinder
Cylinder object,
object, aa PointLight
PointLight object
object and a PerspectiveCamera
object, respectively. With respect to the Box object, it is a box of 100 × 150 × 300 which
is displaced at the point (150, 200, 200) and thus at a point that is 200 behind the screen.
Afterwards the box is rotated 20 degrees. In particular, you should note how to assign a
color to a surface with a Material object. A Sphere and a Cylinder are, in principle, created

168
168
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT 3D
3d Shapes
shapes

in
in the the same
same way,
way, such
such that
that for
for aa Sphere
Sphere object,
object, aa radius
radius must
must be
be defined
defined while
while for
for aa cylinder
cylinder
itit isis necessary
necessary to to indicate
indicate both
both thethe radius
radius and
and the
the height.
height. The
The camera
camera isis located
located at
at the
the point
point
(100,
(100, 100, -100) and and thus
thuson onthetheleft
leftand
and slightly
slightly in in front
front of the
of the screen.
screen. NoteNote
that that the
the light
light
source source is located
is located in theinsame
the same
place,place,
whichwhich obviously
obviously does does not have
not have to betothe becase.
the case.

In
In the
the method
method start(),
start(), the
the light
light source
source isis attached
attached toto the
the scene
scene graph
graph in
in exactly
exactly the
the same
same
way
way asas any
any other
other node
node while
while the
the camera
camera isis directly
directly attached
attached toto the
the Stage
Stage object.
object.

You
You are
are encouraged
encouraged to to experiment
experiment with
with the
the program
program and
and note
note what
what happens
happens ifif you
you change
change
the
the values
values in
in the
the 55 methods.
methods. In
In particular,
particular, try
try changing
changing the
the size
size of
of the
the window.
window. Then
Then the
the
shapes
shapes are
are changed
changed as as well.
well.

8.2 MATERIAL
8.2 MATERIAL
AA Shape3D
Shape3D object
object hashas aa property
property of
of the
the type
type Material
Material that
that determines
determines how
how the
the surface
surface
appears,
appears, and
and itit can
can be
be aa color,
color, but
but can
can also
also be
be aa picture.
picture. The
The program
program BoxProgram
BoxProgram opens
opens aa
window
window with
with two
two Box
Box objects:
objects:

where
where one
one has
has aa color
color (Color.BEIGE),
(Color.BEIGE), while
while the
the surface
surface of
of the
the other
other isis aa picture.
picture.

public class BoxProgram extends Application


{
@Override
public void start(Stage stage)
{
PhongMaterial m1 = new PhongMaterial();
m1.setDiffuseColor(Color.TAN);
PhongMaterial m2 = new PhongMaterial();

169
169
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

m2.setDiffuseMap(new Image("resources/images/stone.jpg"));
Scene scene = new Scene(new Group(createBox(500, 310, 500, m1), createBox(800,
310, 500, m2), createLight()), 600, 300, true);
scene.setCamera(createCamera());
stage.setScene(scene);
stage.setTitle("Material");
stage.show();
}

private Box createBox(double x, double y, double z, Material m)


{
Box box = new Box(200, 200, 200);
box.setMaterial(m);
box.setTranslateX(x);
box.setTranslateY(y);
box.setTranslateZ(z);
return box;
}

private PointLight createLight()


{
PointLight p = new PointLight();
p.setTranslateX(200);

170
170
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

p.setTranslateY(200);
p.setTranslateZ(-600);
return p;
}

private PerspectiveCamera createCamera()


{
PerspectiveCamera c = new PerspectiveCamera(false);
c.setTranslateX(600);
c.setTranslateY(300);
c.setTranslateZ(-50);
return c;
}

public static void main(String[] args)


{
launch(args);
}
}

The two Box objects are created by the method createBox(), where the parameters are the
coordinates of a translation as well as a Material. It is an abstract class, and there is only
one specific class called PhongMaterial. It has a number of methods (such as setDiffuseColor()
and setDiffuseMap()) used to specify how the surface should be and you are encouraged
to examine the documentation. In this case, two PhongMaterial objects are created in the
start() method, where the last refers to an image.

8.3
8.3 DRAW MODE
The surface of Shape3D objects is actually drawn as a number of triangles, and you can,
with a parameter, indicate to the constructor how many there are to be. By default, these
triangles are drawn as filled, but you can also indicate that you just have to draw the
perimeter. There are thus two draw modes:

1.
1. DrawMode.FILL (default)
2.
2. DrawMode.LINE

The program SphereProgram opens the following window, which shows three Sphere objects,
and the last one is drawn with DrawMode.LINE:

171
171
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT 3D
3d Shapes
shapes

The
The code
code isis basically
basically the
the same
same as
as in
in the
the previous
previous program,
program, and
and there
there isis only
only one
one significant
significant
change
change in
in which
which the
the method
method createBox()
createBox() isis replaced
replaced by
by the
the following
following method;
method;

private Sphere createSphere(double x, double y, double z, Material m,


DrawMode mode)
{
Sphere sphere = new Sphere(150);
sphere.setMaterial(m);
sphere.setDrawMode(mode);
sphere.setTranslateX(x);
sphere.setTranslateY(y);
sphere.setTranslateZ(z);
return sphere;
}

8.4 CULL FACE


8.4 CULL FACE
When a 3D figure appears on the screen, for natural reasons, you can not see the whole
When
figure –a you
3D can
figure
notappears
see whatonlies
thebehind
screen,it.for
Whatnatural reasons,
you can you canonnot
see depends see the camera
where whole
figure – youAs
is located. canmentioned
not see whatin lies
thebehind
previousit. What youa can
section, 3D see depends
shape on where
is drawn as a the camera
number of
istriangles.
located.AAs mentioned
triangle has twoin sides
the previous
in the form section,
of theaoutside
3D shape is drawn
and the inside,asand
a number of
as a default
triangles.
one can see A triangle has two
the outside. sides in are
In general the dawn
form of thethe
only outside and the
treangles, inside,
which and as while
are visible a default
the
one
otherscanare
seesorted
the outside. In general
out. There are dawn
is a property onlyCullFace,
called the treangles,
whichwhich are visible
can assume threewhile the
values:
others are sorted out. There is a property called CullFace, which can assume three values:
1. CullFace.BACK
1.
2. CullFace.BACK
CullFace.FRONT
2.
3. CullFace.FRONT
CullFace.NONE
3. CullFace.NONE

172
172
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT 3D Shapes

where the first is default and means that you only see the triangles where you can see the
outside while the other means that you can only see the inside of the triangles which are
usually not visible. The last option means that you can see both kinds of triangles and thus
draw all the triangles. The program CylinderProgram opens the following window:

Challenge the way we run

EXPERIENCE THE POWER OF


FULL ENGAGEMENT…

RUN FASTER.
RUN LONGER.. READ MORE & PRE-ORDER TODAY
RUN EASIER… WWW.GAITEYE.COM

1349906_A6_4+0.indd 1 22-08-2014 12:56:57

173
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT 3D
3d Shapes
shapes

which
which shows
shows aa cylinder
cylinder drawn
drawn with
with DrawMode.LINE
DrawMode.LINE and
and CullFace.BACK.
CullFace.BACK. If
If you
you click
click the
the
cylinder
cylinder with
with the
the mouse,
mouse, you
you switch
switch to
to CullFace.FRONT:
CullFace.FRONT:

and
and click
click once
once to
to switch
switch to
to CullFace.NONE,
CullFace.NONE, andand then
then itit all
all repeats
repeats itself.
itself. The
The code
code is
is simple
simple
and
and similar
similar to
to the
the above
above programs,
programs, just
just an
an event
event is
is added
added for for the
the mouse:
mouse:

public class CylinderProgram extends Application


{
private CullFace[] culls = { CullFace.BACK, CullFace.FRONT, CullFace.NONE
};
private int pos = 0;
private Cylinder cylinder;

@Override
public void start(Stage stage)
{
Group root = new Group(cylinder =
createCylinder(500, 450, 600), createLight());
root.addEventHandler(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
public void handle(MouseEvent e) { pos = (pos + 1) % culls.length;
cylinder.setCullFace(culls[pos]); };
});
Scene scene = new Scene(root, 600, 300, true);
scene.setCamera(createCamera());
stage.setScene(scene);
stage.setTitle("Cull");
stage.show();
}

private Cylinder createCylinder(double x, double y, double z)


{
Cylinder c = new Cylinder(200, 400);

174
174
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

c.setMaterial(new PhongMaterial(Color.BLUE));
c.setDrawMode(DrawMode.LINE);
c.setTranslateX(x);
c.setTranslateY(y);
c.setTranslateZ(z);
return c;
}


}

8.5 CAMERA AND LIGHT


The camera is the most crucial factor in 3D graphics, but it can be difficult to predict the
8.5
effect. CAMERA
For example,ANDif you LIGHT
create a sphere with radius 50 and without any kind of transition
andcamera
The create ais camera in crucial
the most the same way,inyou
factor 3Dget the following
graphics, window:
but it can be difficult to predict the
effect. For example, if you create a sphere with radius 50 and without any kind of transition
and create a camera in the same way, you get the following window:

This corresponds to that the starting point of the coordinate system (0, 0, 0), which is the
center of the sphere. The camera is located in the same position, and if you changed the
window
This size, nothing
corresponds to thathappens with point
the starting the shape.
of theSince the sphere
coordinate has(0,
system no0,Material,
0), whicha default
is the
value of
center is given, whichThe
the sphere. is light
cameragray color, and
is located since
in the there
same is no mention
position, of changed
and if you light, a light
the
source with
window size, the same happens
nothing position with
as thethecamera
shape.isSince
used.the sphere has no Material, a default
value is given, which is light gray color, and since there is no mention of light, a light
If youwith
source movethethesame
shape 100 inaseach
position direction,
the camera the center of the sphere is shifted to (100,
is used.
100, 100) and the result is as shown below, where you should notice that the figure has
Ifbecome smaller
you move the as it is 100
shape shown 100 into
in each the screen
direction, and thus
the center away
of the from isthe
sphere viewer:
shifted to (100,
100, 100) and the result is as shown below, where you should notice that the figure has
become smaller as it is shown 100 into the screen and thus away from the viewer:

175
175
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT 3D Shapes

Note that the camera and the light are still in (0, 0, 0). If you then change the camera
-200 in the z axis direction, you will see that the figure becomes even smaller as the camera
has now moved further towards the viewer, and thus there is longer between the camera
and the figure:

The camera used above has the type PerspectiveCamera, but there is also a camera ParallelCamera,
and the difference is what kind of projection is used. A PerspectiveCamera is the most used
since, as the name says, it sees the object in perspective. A clip area is attached to a camera
so that shapes that are close to the camera do not appear and the same for shapes that are
far away.

This e-book
is made with SETASIGN
SetaPDF

PDF components for PHP developers

www.setasign.com

176
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT 3D Shapes

To show a little about the effect of some of the many options and for experimentation, I
will look at a program that I have called Options3D:

The window has a Sphere object that sits in the upper left corner, and although it is not
visible, the surface has a red Material. To the right there are 10 Slider controls that can be
used to change the following settings:

1. position of the figure – (x, y, x) coordinate


2. radius
3. location of light source – (x, y, x) coordinate
4. camera location – (x, y, x) coordinate

Below I have shown the result after moving the figure and the light source:

177
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT 3D shapes
3d Shapes

The
The program’s
program’s code
code is
is as follows:

public class Options3D extends Application


{
private Shape3D shape;
private PointLight light = new PointLight();
private PerspectiveCamera camera = new PerspectiveCamera(false);
private Label tx = new Label();
private Label ty = new Label();
private Label tz = new Label();
private Label lx = new Label();
private Label ly = new Label();
private Label lz = new Label();
private Label cx = new Label();
private Label cy = new Label();
private Label cz = new Label();
private Label ra = new Label();

@Override
public void start(Stage stage)
{
HBox root = new HBox(20, create3D(), create2D());
Scene scene = new Scene(root, 800, 400, true);
stage.setScene(scene);
stage.setTitle("3D Options");
stage.show();
}

private SubScene create3D()


{
Group root = new Group(shape = new Sphere(100), light);
shape.setMaterial(new PhongMaterial(Color.RED));
SubScene subScene = new SubScene(root, 500, 400, true,
SceneAntialiasing.BALANCED);
subScene.setCamera(camera);
return subScene;
}

private SubScene create2D()


{
VBox commands = new VBox(10,
createLabel("Translation", tx, ty, tz, shape.translateXProperty(),
shape.translateYProperty(), shape.translateZProperty()),
createSlider(-500, 500, 0, shape.translateXProperty()),
createSlider(-500, 500, 0, shape.translateYProperty()),
createSlider(-500, 500, 0, shape.translateZProperty()),
createLabel("Radius", ra, ((Sphere)shape).radiusProperty()),
createSlider(0, 250, 100, ((Sphere)shape).radiusProperty()),

178
178
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

createLabel("Light", lx, ly, lz, light.translateXProperty(),


light.translateYProperty(), light.translateZProperty()),
createSlider(-500, 500, 0, light.translateXProperty()),
createSlider(-500, 500, 0, light.translateYProperty()),
createSlider(-500, 500, 0, light.translateZProperty()),
createLabel("Camera", cx, cy, cz, camera.translateXProperty(),
camera.translateYProperty(), camera.translateZProperty()),
createSlider(-500, 500, 0, camera.translateXProperty()),
createSlider(-500, 500, 0, camera.translateYProperty()),
createSlider(-500, 500, 0, camera.translateZProperty()));
commands.setPrefWidth(280);
HBox root = new HBox(10, commands);
root.setPadding(new Insets(10, 10, 10, 0));
return new SubScene(root, 300, 380);
}

private Pane createLabel(String text, Label r, DoubleProperty p)


{
r.textProperty().bind(p.asString("%3.1f"));
HBox box = new HBox(new Label(text + ": ("), r, new Label(")"));
return box;
}

www.sylvania.com

We do not reinvent
the wheel we reinvent
light.
Fascinating lighting offers an infinite spectrum of
possibilities: Innovative technologies and new
markets provide both opportunities and challenges.
An environment in which your expertise is in high
demand. Enjoy the supportive working atmosphere
within our global group and benefit from international
career paths. Implement sustainable ideas in close
cooperation with other specialists and contribute to
influencing our future. Come and join us in reinventing
light every day.

Light is OSRAM

179
179
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT 3D Shapes
SOFTWARE DEVELOPMENT 3d shapes

private Pane createLabel(String text, Label x, Label y, Label z,


DoubleProperty px, DoubleProperty py, DoubleProperty pz)
{
x.textProperty().bind(px.asString("%3.1f"));
y.textProperty().bind(py.asString("%3.1f"));
z.textProperty().bind(pz.asString("%3.1f"));
HBox box = new HBox(new Label(text + ": ("), x, new Label(", "), y,
new Label(", "), z, new Label(")"));
return box;
}

private Slider createSlider(double min, double max, double val,


DoubleProperty property)
{
Slider slider = new Slider(min, max, val);
slider.valueProperty().bindBidirectional(property);
return slider;
}

public static void main(String[] args)


{
launch(args);
}
}

There is a lot to note in the code. There are no less than 13 instance variables, the first
There is a lot to note in the code. There are no less than 13 instance variables, the first
being a reference to the Sphere object. The two next are the light source and the camera
being a reference to the Sphere object. The two next are the light source and the camera
respectively. Finally, the 10 Label controls that are used to display the values of the 10
respectively. Finally, the 10 Label controls that are used to display the values of the 10
Slider controls.
Slider controls.

As for the method start(), there is not much to say besides placing two components in a
As for the method start(), there is not much to say besides placing two components in a
HBox. However, there is a challenge. A Scene object can generally not display both 3D and
HBox. However, there is a challenge. A Scene object can generally not display both 3D and
2D objects – at least not correct. To solve this problem, I have introduced the concept
2D objects – at least not correct. To solve this problem, I have introduced the concept
of a SubScene that allows you to have more Scene objects in a window. It can be used for
of a SubScene that allows you to have more Scene objects in a window. It can be used for
multiple purposes (primarily in 3D graphics), and it can be used to split the window into
multiple purposes (primarily in 3D graphics), and it can be used to split the window into
a part for 3D objects and a part for usual 2D objects. That is exactly what is the case in
a part for 3D objects and a part for usual 2D objects. That is exactly what is the case in
this example.
this example.

The method create3D() creates a 3D Scene, where the root is a Group with a Sphere that
The method create3D() creates a 3D Scene, where the root is a Group with a Sphere that
has a radius 100. Note that a Material is also defined. For this root, a SubScene is created.
has a radius 100. Note that a Material is also defined. For this root, a SubScene is created.
In particular, note how to specify that anti-aliasing is used and that the camera is attached
In particular, note how to specify that anti-aliasing is used and that the camera is attached
to the SubScene object. This is why the image from the start is displayed black, because the
to the SubScene object. This is why the image from the start is displayed black, because the
camera’s location in (0,0,0) corresponds to it is inside the ball.
camera’s location in (0,0,0) corresponds to it is inside the ball.

180
180
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT 3D Shapes

The method create2D() also creates a SubScene object, but this time it’s a usual 2D Scene.
The code is a part, but it is because many controls must be created, and the code does not
contain anything new in principle. When the individual controls (Slider controls) are created,
note how the value property binds to a property by either the Shape object, the Light object
or the Camera object. Similarly, the 10 Label controls are bound to the same properties,
but here with a unidirectional binding, as the values are to be converted to strings.

You are encouraged to experiment with the program.

EXERCISE 6
You must write a program similar to the program Options3D, but instead of a red Sphere,
the program must show blue Box, which is initially (100, 100, 100). The window below
shows the figure after several Slider controls have been moved. Note that two new Slider
controls (and associated Label controls) have been added so you can set both width, height
and depth of the Box. The easiest thing is to start with a copy of the Options3D program.

181
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT 3D Shapes

EXERCISE 7
Write another version of the above program, but where the Shape3D object this time is a
green Cylinder, the size from start is (50, 100). You must be able to set both the radius and
the height, and the result could be as shown below:

8.6 A LAST REMARK


As mentioned, a Shape3D shape is constructed using triangles, and it is possible – but far
from easy – to define custom shapes by defining the individual triangles. I do not want to
get closer to this in this book, and it takes a lot of practice, but the construction of custom
shapes is done using the class MeshView.

182
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Charts

9 CHARTS
In the final example of the book Java 10, I looked at a library that has classes for representation
of graphs. As mentioned, there are many such libraries, and there are actually many examples
of tasks where there is a desire for a graphical presentation of data, but in JavaFX it is
easy as there is an API directly for that purpose, which has the most common graphs. The
following is an introduction to this API, which basically include the following classes:

360°
thinking .

360°
thinking . 360°
thinking .
Discover the truth at www.deloitte.ca/careers Dis

© Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers © Deloitte & Touche LLP and affiliated entities.

Deloitte & Touche LLP and affiliated entities.

Discover the truth at www.deloitte.ca/careers


183
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Charts

In addition, there are other auxiliary classes, including classes that represents the data that
the individual graphs should illustrate, and there are classes to the axes of the coordinate
system. The API can thus show 8 different graphs divided into two categories consisting of
a PieChart and then the others. A graph is a graphical illustration of a number sequence,
and a PieChart can show a single number sequence, while the others can display more
called series in a xy-coordinate system. In the following example I would like to illustrate
the following graphs:

-- PieChart
-- BarChart (two versions)
-- StackedBarChart

For all graphs, there are of course a number of settings, and the example does not show
all settings, and the goal is to search the documentation yourself and experiment with the
different settings, including expanding the program with new graphs using other types than
the three mentioned above. It should be mentioned immediately that it is quite easy to
work with the API and that it is similarly independent of the graph type.

The program is called ChartProgram and it opens the following window:

184
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Charts

When displaying a graph (a Chart), you must have some data in the form of a number
material. What the numbers means is not so important for the current example, but the
numbers could be interpreted as revenue over the 12 months of the year and the numbers
above shows the revenue for the years 2008–2017. In order to experiment with graphs, the
numbers are generated random and you can at any time create new numbers by clicking
the Generate Data link:

You can also change the data by editing the table directly. The above dialog is called
ModelView, but I do not want to show the code here as it contains nothing new. The table
itself shows objects of the type Year and the datamodel of the table is called DataModel,
and these classes are not shown for the same reasons either.

185
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Charts

If you click on the A Pie chart link, the following events are performed:

private void pie(ActionEvent e)


{
int n = table.getSelectionModel().getSelectedIndex();
if (n >= 0)
{
Year year = model.getYears().get(n);
ObservableList<PieChart.Data> data = FXCollections. observableArrayList();
for (int i = 0; i < DataModel.names.length; ++i)
data.add(new PieChart.Data(DataModel.names[i], year.getValue(i)));
new PieView(parent, year.getYear(), data);
}
}

The method
The method determines
determines the
the index
index for
for the
the first
first row
row that
that is
is selected,
selected, and
and for
for this
this row,
row, aa
list of
list of the
the type
type ObservableList<PieChart.Data>
ObservableList<PieChart.Data> is is created.
created. You
You should
should note
note how
how this
this list
list is
is
initialized with
initialized with PieChart.Data
PieChart.Data objects,
objects, consisting
consisting ofof pairs
pairs where
where the
the first
first value
value is
is the
the month
month
name (above
name (above the
the array
array names),
names), while
while the
the other
other value
value is
is the
the numeric
numeric values
values from
from thethe row
row
that is
that is selected.
selected. Next,
Next, aa window
window will
will appear
appear showing
showing aa PieChart:
PieChart:

We will turn your CV into


an opportunity of a lifetime

Do you like cars? Would you like to be a part of a successful brand? Send us your CV on
We will appreciate and reward both your enthusiasm and talent. www.employerforlife.com
Send us your CV. You will be surprised where it can take you.

186
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Charts
Charts

The
The graph
graph uses
uses as as default
default up
up to
to 88 colors,
colors, after
after which
which they
they are
are repeated,
repeated, but
but you
you can
can specify
specify
more
more colors
colors ifif you
you wish.
wish. The
The window’s
window’s code
code isis as
as follows:
follows:

public class PieView


{
public PieView(Window owner, int year, ObservableList<PieChart.Data> data)
{
Stage stage = new Stage();
stage.initOwner(owner);
stage.initModality(Modality.APPLICATION_MODAL);
PieChart chart = new PieChart();
chart.setTitle("Sales for " + year);
chart.setLegendSide(Side.LEFT);
chart.setData(data);
addTooltips(chart);
StackPane root = new StackPane(chart);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("A Pie chart");
stage.show();
}

private void addTooltips(PieChart chart)


{
double sum = 0;
for (PieChart.Data data : chart.getData()) sum += data.getPieValue();
for (PieChart.Data data : chart.getData())
{

187
187
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
SOFTWARE MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
DEVELOPMENT Charts
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Charts
Charts

double value = data.getPieValue();


double value = data.getPieValue();
Tooltip tip = new Tooltip(data.getName() + "= " +
Tooltip tip = new Tooltip(data.getName() + "= " +
String.format("%.2f",
String.format("%.2f", value)
value) ++ "" ("
(" ++
String.format("%.2f",
String.format("%.2f", value
value // sum
sum ** 100)
100) ++ "%)");
"%)");
tip.setStyle("-fx-background-color: yellow; -fx-text-fill: black;");
tip.setStyle("-fx-background-color: yellow; -fx-text-fill: black;");
Tooltip.install(data.getNode(), tip);
Tooltip.install(data.getNode(), tip);
}}
}}
}}

and
and there
there isis not
not much
much to
to explain.
explain. The
The hardest
hardest thing
thing isis actually
actually the
the last
last method
method that
that links
links
tooltips
tooltips to
to the
the PieChart
PieChart component.
component. YouYou should
should note
note how
how toto create
create aa PieChart
PieChart component
component
and
and specifically
specifically what
what properties
properties are
are defined.
defined.

IfIf in
in the
the main
main window
window you
you marks
marks the
the numbers
numbers for
for three
three years
years and
and click
click on
on the
the link
link AA
vertical
vertical barbar chart,
chart, you
you get
get the
the following
following window:
window:

which
which isis an
an example
example of
of an
an XYChart.
XYChart. The
The event
event handler
handler isis as
as follows:
follows:

private void bar1(ActionEvent e)


private void bar1(ActionEvent e)
{{
OObservableList<Integer> indices = table.
bservableList<Integer> indices = table.
getSelectionModel().getSelectedIndices();
getSelectionModel().getSelectedIndices();
if (indices.size() > 0)
if (indices.size() > 0)
{{
ObservableList<XYChart.Series<String, Number>> data = getXYData(indices);
ObservableList<XYChart.Series<String, Number>> data = getXYData(indices);
new VBarView(parent, data);
new VBarView(parent, data);
}}
}}

188
188
188
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT Charts
Charts

First,
First, the
the indexes
indexes are
are determined
determined on on the
the rows
rows that
that are
are selected,
selected, and
and on
on that
that basis,
basis, the
the graph
graph
data
data isis created
created as
as an
an object
object of
of the
the type
type ObservableList<XHChart.Series<String,
ObservableList<XHChart.Series<String, Number>> Number>> to to
be
be used
used to to display
display the
the graph.
graph. The
The object
object isis determined
determined using
using the
the following
following method:
method:

private ObservableList<XYChart.Series<String, Number>>


getXYData(ObservableList<Integer> indices)
{
ObservableList<XYChart.Series<String, Number>> data =
FXCollections.<XYChart.Series<String, Number>>observableArrayList();
for (int i = 0; i < indices.size(); ++i)
{
Year year = model.getYears().get(indices.get(i));
XYChart.Series<String, Number> series = new XYChart.Series<>();
series.setName("" + year.getYear());
for (int j = 0; j < DataModel.names.length; ++j)
series.getData().add(new XYChart.Data(DataModel.
names[j], year.getValue(j)));
data.add(series);
}
return data;
}

�e Graduate Programme
I joined MITAS because for Engineers and Geoscientists
I wanted real responsibili� www.discovermitas.com
Maersk.com/Mitas �e G
I joined MITAS because for Engine
I wanted real responsibili� Ma

Month 16
I was a construction Mo
supervisor ina const
I was
the North Sea super
advising and the No
Real work he
helping foremen advis
International
al opportunities
Internationa
�ree wo
work
or placements ssolve problems
Real work he
helping fo
International
Internationaal opportunities
�ree wo
work
or placements ssolve pr

189
189
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Charts
Charts

The
The method
method is,is, in
in principle,
principle, simple,
simple, but
but you
you should
should note
note how
how the
the graph’s
graph’s data
data model
model isis
built
built up
up as
as objects
objects of of the
the type
type XYChart.Series<String,
XYChart.Series<String, Number>,
Number>, each
each object
object being
being aa pair
pair
consisting
consisting of
of aa name
name andand aa value.
value.

The
The code
code for
for the
the graph
graph window
window isis as
as follows:
follows:

public class VBarView


{
public VBarView(Window owner, ObservableList<XYChart.
Series<String,Number>> data)
{
Stage stage = new Stage();
stage.initOwner(owner);
stage.initModality(Modality.APPLICATION_MODAL);
CategoryAxis xAxis = new CategoryAxis();
xAxis.setLabel("Month");
NumberAxis yAxis = new NumberAxis();
yAxis.setLabel("Turnover");
BarChart<String, Number> chart = new BarChart<>(xAxis, yAxis);
chart.setTitle("Sales for several years");
chart.setData(data);
StackPane root = new StackPane(chart);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("A vertical bar chart");
stage.show();
}
}

Here you
Here you should
should note note how how to
to create
create the
the axes
axes and
and how
how to
to create
create the
the Chart
Chart object
object itself
itself as
as
aa node.
node. In
In fact,
fact, itit isis simple
simple to
to display
display aa Chart
Chart as
as aa Node
Node in
in aa scene
scene graph
graph once
once you
you have
have
created the
created the data
data model.
model. As As mentioned
mentioned in in the
the introduction
introduction to to this
this chapter,
chapter, you
you should
should
investigate what
investigate what other
other options
options exist
exist for
for aa BarChart.
BarChart.

The program
The program hashas two
two other
other links,
links, the
the first
first showing
showing aa horizontal
horizontal bar
bar chart,
chart, while
while the
the latter
latter
shows aa stacked
shows stacked barbar chart.
chart. As
As forfor the
the latter,
latter, itit isis done
done inin the
the same
same way
way asas above,
above, and and the
the
data model
data model isis created
created in
in the
the same
same way,
way, just
just the
the type
type isis StackedBarChart.
StackedBarChart. As As for
for the
the first
first one,
one,
itit isis aa BarChart
BarChart andand the
the only
only difference
difference isis that
that the the two
two axes
axes need
need to
to be
be replaced,
replaced, which
which in in
turn means
turn means that
that the
the model
model data
data must
must also
also swapped.
swapped. II do do not
not want
want to
to show
show the
the code
code for
for the
the
last two
last two graphs
graphs here,
here, as
as they
they are,
are, in
in principle,
principle, identical
identical to to the
the code
code for
for the
the first
first BarChart.
BarChart.

190
190
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

10 FINAL EXAMPLE
The final example of this book is a program where the user can enter an expression for a
mathematical function in one real variable, for example

� = 3� � − 2� + 1

and the program must then be able to draw the function’s graph. The requirements are
formulated continuously as the program is to be developed through a form of protyping, but
the main purpose of the program is that when you have drawn the graph for one or more
functions in a coordinate system, you must be able to copy the graph to the clipboard and
paste it into a word processor, for example. You can thus think of the program as a tool
that can be used by a writer of mathematical notes or books, but perhaps even by students
in daily mathematics education.

Regarding the other features of the program, there are primarily requirements for flexibility
and ease of use, as well as the types of graphs that the program can draw. Some of the
program’s features will relate to settings, including, for example, color and line thickness
settings, as well as settings for the coordinate system will be important.

More challenges are expected regarding the development, and the biggest challenge is assumed
to relate to performance, as it may take time to draw a complete graph. In particular,
expectations can be expected to change the size of the window, as it means both adjustments
of (redrawing) the graph itself, but also the coordinate system.

Another challenge is how to save the graph to a file where the graphs are not saved by
simple object serialization as it is sensitive to new versions of the program.

Regarding what a function must be (legal expressions), it is a problem that I have previously
solved, so for parsing and evaluating an expression, more or less direct code can be used,
which has previously been developed and tested.

The program is considered as a first version, and you must expect frequent changes/extensions
of the program for a period of time.

191
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

10.1 DEVELOPMENT
As mentioned above, the program is to be developed through a form of proptotype where
the following iterations are planned:

1. A simple prototype
2. Drawing the x-axis
3. Drawing the y-axis
4. Drawing the coordinat system
5. Drawing a function from a formal
6. Drawing a plot
7. Implementing other features
8. Implementing options
9. Styling the program
10. Refactoring

but there may occur several and other iterations. The result of every iteration is a complete
program that can be used with the features that are implemenrated and each iteration is
an extension of the previous iteration.

192
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

10.2 A SIMPLE PROTOTYPE


The program’s first prototype opens the following window:

The program’s functions are defined as menu items, but for the time being, are only
shown headings which all are menus that near the first are empty. The first menu defines
5 functions (as an example) but has no action. 8 functions have shortcuts in a toolbar and
are from the left:

1. New drawing
2. Open existing drawing
3. Save drawing
4. Settings for coordinate system
5. Insert new function in the drawing
6. Zoom out
7. Zoom in
8. Same division om both axes

The toolbar also contains an expression, and the idea is that the drawen functions should be
displayed as a link in the toolbar, so you can change the function’s data by clicking the link.

The cross with the frame around should illustrate a drawing drawn by a method showImage(),
and the figure consists of three Shape objects attached to a Group object. It is a preliminary
solution that may be changed later. The figure is preliminary hard-coded, but follows the
window size when it changes. There is a small problem with displaying the window in full
screen if you double-click the titlebar. Here’s a problem getting the window drawn correctly.
It is apparently a JavaFX issue (under Linux) and is fixed with a timer that updates the
window after ½ selund.

193
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT FInal Example
Final eXaMple
SOFTWARE DEVELOPMENT FInal eXaMple

10.3
10.3 DRAWING
10.3 DRAWING THE
DRAWING THE AXES
THE AXES
AXES
This
This iteration involves drawing both axes of the coordinate system and thus the two next
This iteration
iteration involves
involves drawing
drawing both both axes
axes of
of the
the coordinate
coordinate system system and
and thus
thus the
the twotwo next
next
iterations
iterations are
are combined
combined into
into aa single
single iteration.
iteration. Generally,
Generally, there
there are
are many
many challenges
challenges in
in drawing
drawing
iterations are combined into a single iteration. Generally, there are many challenges in drawing
the
the axes of the coordinate system, among other things because they have to behave nicely
the axes
axes of of the
the coordinate
coordinate system,
system, amongamong otherother things
things because
because they they have
have toto behave
behave nicely
nicely
when
when the
the size
size of
of the
the window
window changes,
changes, but
but JavaFX
JavaFX has
has in
in the
the Chart
Chart API
API classes
classes representing
representing
when the size of the window changes, but JavaFX has in the Chart API classes representing
axes to
to aaa coordinate
coordinate system, and especially the class NumberAxis. Since this class
class isis
axes actually
axes to coordinate system,
system, andand especially
especially thethe class
class NumberAxis.
NumberAxis. Since Since this
this class is actually
actually
general
general (has enough settings), it has been decided to use it instead of to write a custom
general (has
(has enough
enough settings),
settings), it
it has
has been
been decided
decided to
to use
use it
it instead
instead of
of to
to write
write aa custom
custom
component.
component. Therefore, the two iterations to the coordinate system’s axes are combined into
component. Therefore, the two iterations to the coordinate system’s axes are combined into
Therefore, the two iterations to the coordinate system’s axes are combined into
aaa single
single iteration.
iteration.
single iteration.

AA single
A single model
single model class
model class has
class has been
has been added
been added that
added that represents
that represents an
represents an axis:
an axis:
axis:

public class AxisModel


public class AxisModel
{
{
private DoubleProperty min = new SimpleDoubleProperty(-10);
private DoubleProperty min = new SimpleDoubleProperty(-10);
private DoubleProperty max = new SimpleDoubleProperty(10);
private DoubleProperty max = new SimpleDoubleProperty(10);
private IntegerProperty dec = new SimpleIntegerProperty(0);
private IntegerProperty dec = new SimpleIntegerProperty(0);
private IntegerProperty ticks = new SimpleIntegerProperty(1);
private IntegerProperty ticks = new SimpleIntegerProperty(1);
private StringProperty label = new SimpleStringProperty("");
private StringProperty label = new SimpleStringProperty("");
private DoubleProperty cross = new SimpleDoubleProperty(0);
private DoubleProperty cross = new SimpleDoubleProperty(0);
private BooleanProperty autoTicks = new SimpleBooleanProperty(false);
private BooleanProperty autoTicks = new SimpleBooleanProperty(false);
private BooleanProperty showTicks = new SimpleBooleanProperty(true);
private BooleanProperty showTicks = new SimpleBooleanProperty(true);
private BooleanProperty showGitter = new SimpleBooleanProperty(false);
private BooleanProperty showGitter = new SimpleBooleanProperty(false);
private BooleanProperty showNumbers = new SimpleBooleanProperty(true);
private BooleanProperty showNumbers = new SimpleBooleanProperty(true);

where
where the
where the meaning
meaning isis
the meaning as
is as follows:
as follows:
follows:

---- the
the lowest
the lowest value
lowest value
value onon the
on the axis
the axis
axis
---- the
the greatest
the greatest value
greatest value
value onon the
on the axis
the axis
axis
---- number
number
number of of decimals
of decimals
decimals to to be
to be used
be used to
used to display
to display the
display the axis
the axis numerical
axis numerical values
numerical values
values
---- the
the interval
the interval length
interval length between
length between
between the the points
the points of
points of the
of the axis
the axis
axis
---- label
label (name)
label (name)
(name) to to the
to the axis
the axis
axis
---- where
where
where the the axis
the axis should
axis should cross
should cross the
cross the second
the second axis
second axis
axis
---- if the
ifif the axis
the axis automatically
axis automatically determines
automatically determines the
determines the division
the division from
division from the
from the smallest
the smallest and
smallest and greatest
and greatest value
greatest value
value
---- if the
ifif the axis
the axis divisions
axis divisions
divisions areare to
are to be
to be displayed
be displayed
displayed
---- if grid
ifif grid lines
grid lines should
lines should appears
should appears
appears
---- if the
ifif the numbers
the numbers
numbers are are to
are to be
to be displayed
be displayed
displayed

The
The class
The class FDrawer
class FDrawer has
FDrawer has two
has two objects
two objects for
objects for the
for the axes:
the axes:
axes:

private AxisModel xModel = new AxisModel();


private AxisModel xModel = new AxisModel();
private AxisModel yModel = new AxisModel();
private AxisModel yModel = new AxisModel();

194
194
194
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

In addition, the class is expanded with two inner classes, one of which creates and drawes
the axes, while the other draws the graph as a Path object. These two classes will be key
and will be expanded several times. If you run the program, you get the following window
where the function is still hard-coded:

In the past 5 years we have drilled around

95,000 km
—that’s more than twice around the world.

Who are we?


We are the world’s leading provider of reservoir characterization,
drilling, production, and processing technologies to the oil and
gas industry.

Who are we looking for?


We offer countless opportunities in the following domains:
n Operations
n Research, Engineering, and Manufacturing
n Geoscience and Petrotechnical
n Commercial and Business

We’re looking for high-energy, self-motivated graduates


with vision and integrity to join our team. What will you be?

careers.slb.com

195
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

The
The important
important thing thing isis that
that the
the coordinate
coordinate systemsystem and
and the
the graph
graph follows
follows the
the window
window size.
size.
There
There isis still
still aa lack
lack of
of aa part
part about
about the
the coordinate
coordinate system,
system, including
including the
the use
use of
of above
above settings,
settings,
which
which isis only
only partly
partly used
used until
until now.
now. ItIt isis the
the subject
subject of
of the
the next
next iteration.
iteration.

10.4 SETTINGS
10.4 SETTINGS FOR
FOR THE
THE COORDINATE
COORDINATE SYSTEM
SYSTEM
In this
In this iteration
iteration II started
started with
with aa little
little architecture.
architecture. In
In the
the previous
previous iteration,
iteration, II have
have added
added
aa package
package fdrawer.models,
fdrawer.models, which
which contains
contains thethe class
class AxisModel.
AxisModel. II have
have expanded
expanded thethe model
model
with the
with the following
following class:
class:

package fdrawer.models;

public class AxesModel


{
private AxisModel xaxis = new AxisModel();
private AxisModel yaxis = new AxisModel();

public AxesModel()
{
}

public AxesModel(AxesModel axes)


{
xaxis = new AxisModel(axes.getXaxis());
yaxis = new AxisModel(axes.getYaxis());
}

public AxisModel getXaxis()


{
return xaxis;
}

public AxisModel getYaxis()


{
return yaxis;
}
}

196
196
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

which
which is
is nothing
nothing but
but an
an enclosure
enclosure of
of two
two axes.
axes. In
In addition,
addition, II have
have added
added the
the following
following class
class

package fdrawer.models;

public class Model


{
private AxesModel axes = new AxesModel();

public AxesModel getAxes()


{
return axes;
}
}

that for the time being, it is trivial, but in the future it should be the main model of the
that for the
program. time
The being,
main thingit inis the
trivial, but inis the
iteration the future it should
following dialog be
boxthe main
that model
is used of the
to set the
program. The main thing in the iteration
options for the axis of the coordinate system: is the following dialog box that is used to set the
options for the axis of the coordinate system:

It is a relatively complex dialog box that basically consists of a HBox with two GridPane
It is a relatively
nodes. The code complex dialog
is placed in box that
a package basically consists
fdrawer.views of a of
and consists HBox
two with
classestwo GridPane
AxesPresenter
nodes. The code is placed in a package fdrawer.views and consists of two classes AxesPresenter
and AxesView.
and AxesView.

197
197
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

In addition to the dialog, the main window must be updated so that the current settings
are also used, which is a relatively large work and relates to the two inner classes Axes and
Plot, but after that the coordinate system is also essentially complete. However, there are
two options that are not implemented:

1. Number of decimals, as JavaFX itself decides the number of decimals, and since it
seems sensible, the function may later be removed.
2. Auto division axis. This feature is implemented by the NumberAxis class, but as this
does not always seem appropriate, implementation of this feature is postponed to
later, and perhaps the feature should be removed.

To open the dialog, an event handler has been added to the button in the toolbar, but the
same event handler will later be added to the menu.

10.5 DRAWING A FUNCTION FROM A FORMAL


This iteration can be regarded as the most important iteration, and after the iteration
is completed, you have in principle a ready-made drawer, where you can draw a typical

198
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

mathematical
mathematical function.
function. The
The starting
starting point
point isis to
to expand
expand the
the model
model with
with two
two classes
classes Expression
Expression
and
and Tokens, which represents a mathematical expression. The classes are implemented in
Tokens, which represents a mathematical expression. The classes are implemented in the
the
final example of the book Java 3 and support a mathematical expression where
final example of the book Java 3 and support a mathematical expression where you can useyou can use
the
the four
four arithmetical
arithmetical operations
operations and
and the
the following
following functions:
functions:

Sin
Sin Cos
Cos Tan
Tan Cot
Cot Ln
Ln Log
Log

Asin
Asin Acos
Acos Atan
Atan Acot
Acot Exp
Exp Alog
Alog

Sqr
Sqr Sqrt
Sqrt Pow
Pow Root
Root Abs
Abs Floor
Floor

� �
0.25�
0.25� � +
+ 0.75�
0.75� � −
− 1.5�
1.5� −
− 22

A
A function
function depends
depends on
on one
one variable,
variable, and
and for
for example,
example, the
the function
function

can
can be
be entered
entered as
as

0.25 * pow(x, 3) + 0.75 * sqr(x) – 1.5 * x – 2

The classes
The classes Expression
Expression and
and Tokens
Tokens from
from Java
Java 33 can
can almost
almost be
be used
used unchanged,
unchanged, butbut they
they
support the
support the use
use of
of multiple
multiple variables,
variables, and
and since
since itit should
should not
not be
be an
an option
option in
in this
this program,
program,
the classes
the classes are
are modified
modified so
so that
that you
you can
can only
only use
use aa single
single variable
variable called
called x.
x.

In order
In order to
to create
create aa function,
function, the
the program
program isis expanded
expanded with
with the
the following
following dialog
dialog box
box (the
(the
classes ExpressionView
classes ExpressionView ogog ExpressionPresenter):
ExpressionPresenter):

where you
where you cancan enter
enter aa function
function (above
(above aa simple
simple linear
linear function).
function). You
You can
can also
also specify
specify the
the
color based
color based on on aa few
few fixed
fixed values,
values, and
and in in the
the same
same way
way you
you can
can specify
specify line
line thickness
thickness (also
(also
based on
based on aa few
few fixed
fixed values).
values). Below
Below isis the
the program
program window,
window, where
where two
two functions
functions are
are drawn:
drawn:

199
199
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

Since you need to be able to draw more functions in the same coordinate system (in practice
a few), the toolbar is changed where a combobox is added that shows the graph’s functions.
Additionally, a button has been added that opens the above dialog but for the function that
is selected in the combobox.

Then the program is able to display the graphs for one or more functions in a coordinate system.

10.6 THE PROGRAM ARCHITECTURE


The result of the foregoing is that a very large part of the program code is located in the
class FDrawer, and the subsequent development will, with unchanged architecture, mean
that the class becomes even bigger and probably even much larger. This means that the class
becomes irreversible, and partly because the program does not follow the MVP pattern,
and both can make it more difficult to maintain the program in the future. That’s why I’ve
put in an extra iteration with the purpose of breaking down the class FDrawer into smaller
classes and thus ensuring a better program architecture. It is therefore an iteration that does
not directly generate momentum in the project.

It would of course be better to have made these considerations earlier in the project and
from the outset have planned a better program architecture. However, it is not always that
easy, and especially if you work on a program where the goal is not completely clear and

200
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

where the requirements are determined ongoing. This may mean that you initially focus
on getting something on the screen, so partial results can be presented to the future users
to clarify the final requirements. The result will often be, as in the present case, a program
with inappropriate architecture, and you should then stop and perform a first refactoring.

In this case, the following classes have been added to fdrawer.views:

-- Axes, like the corresponding inner class in FDrawer, has been moved to its own
view class
-- Plot, like the corresponding inner class in FDrawer, has been moved to its own
view class
-- MainMenu, which is the code of the menu that has been moved to its own class
primarily to increase the clarity
-- MainView, which is the main window itself
-- MainPresenter, that is presenter for the main window

The class FDrawer has been changed accordingly and is then a class that does nothing but
instantiate a Model and a MainPresenter.

Finally, to fdrawer.views is added a class ViewTools that contains only static methods.

Excellent Economics and Business programmes at:

“The perfect start


of a successful,
international career.”

CLICK HERE
to discover why both socially
and academically the University
of Groningen is one of the best
places for a student to be
www.rug.nl/feb/education

201
JAVA
JAVA 15:
JAVA 15: MORE
15: MORE ABOUT
MORE ABOUT JAVAFX:
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
FInal eXaMple
eXaMple

10.7
10.7 DRAWING
DRAWING A
A PLOT
PLOT
By
By aa plot
plot II want
want toto understand
understand aa function
function defined
defined byby aa number
number of of points.
points. The
The program
program
must
must then
then display
display the
the function
function graph
graph asas aa corresponding
corresponding number
number of of points
points in
in the
the coordinate
coordinate
system
system and
and possibly
possibly associated
associated with
with lines.
lines. The
The coordinate
coordinate system
system must
must thus
thus bebe able
able to
to
display
display two
two types
types ofof graphs,
graphs, which
which areare either
either aa common
common function
function in in one
one real
real variable
variable as
as
already
already implemented
implemented and and aa plot
plot graph
graph implemented
implemented in in this
this iteration.
iteration. So
So far,
far, aa function
function has
has
been
been represented
represented byby the
the model
model class
class ExpressionModel,
ExpressionModel, but but in
in order
order to
to handle
handle both
both types
types of
of
functions
functions in
in the
the same
same way,
way, the
the model
model isis expanded
expanded as as follows:
follows:

The
The class
class FunctionModel
FunctionModel must
must assign
assign an
an ID
ID to
to the
the individual
individual functions
functions and
and will
will only
only keep
keep
track
track of
of the
the color
color and
and the
the line
line thickness:
thickness:

public abstract class FunctionModel


public abstract class FunctionModel
{
{
private static
private static int
int lastId
lastId =
= 0;
0;
private int id;
private int id;
private ObjectProperty<ColorWrapper> color =
private ObjectProperty<ColorWrapper> color =
new SimpleObjectProperty(Colors.list.get(0));
new SimpleObjectProperty(Colors.list.get(0));
private ObjectProperty<Double> stroke = new SimpleObjectProperty(1.0);
private ObjectProperty<Double> stroke = new SimpleObjectProperty(1.0);

public FunctionModel()
public FunctionModel()
{
{
id =
id = ++lastId;
++lastId;
}
}

Note that
Note that the
the class
class isis defined
defined abstract
abstract so
so that
that itit can
can not
not be
be instantiated.
instantiated. The
The class
class
ExpressionModel
ExpressionModel isis then
then trivial
trivial

public class ExpressionModel extends FunctionModel


public class ExpressionModel extends FunctionModel
{
{
private Expression expression;
private Expression expression;

but should
but should implement
implement equals()
equals() and
and toString().
toString(). The
The class
class PlotModel
PlotModel requires
requires aa little
little more
more as
as
there are
there are more
more settings
settings attached
attached to
to aa plot
plot chart:
chart:

202
202
202
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Final Example
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT FInal eXaMple
SOFTWARE DEVELOPMENT FInal eXaMple

public class PlotModel extends FunctionModel


public class PlotModel extends FunctionModel
{
{

p
private ObservableList<PlotPoint> points =
rivate ObservableList<PlotPoint> points =
FXCollections.observableArrayList();
FXCollections.observableArrayList();
private
private StringProperty
StringProperty name
name =
= new
new SimpleStringProperty("");
SimpleStringProperty("");
private StringProperty plotType =
private StringProperty plotType =

new SimpleStringProperty(PlotType.types.get(0));
new SimpleStringProperty(PlotType.types.get(0));
private ObjectProperty<Double> plotsize = new SimpleObjectProperty(5.0);
private ObjectProperty<Double> plotsize = new SimpleObjectProperty(5.0);
private
private BooleanProperty
BooleanProperty drawLine
drawLine =
= new
new SimpleBooleanProperty(false);
SimpleBooleanProperty(false);
private StringProperty lineType =
private StringProperty lineType =
new SimpleStringProperty(LineType.types.get(0));
new SimpleStringProperty(LineType.types.get(0));

This
This extension
This extension means
extension means some
means some minor
some minor changes
minor changes elsewhere
changes elsewhere in
elsewhere in the
in the code
the code and,
code and, among
and, among other
among other things,
other things,
things,
the
the model
the model has
model has been
has been changed
been changed to
changed to the
to the following:
the following:
following:

package
package fdrawer.models;
fdrawer.models;

import
import javafx.collections.*;
javafx.collections.*;

public class Model


public class Model
{
{
private AxesModel axes = new AxesModel();
private AxesModel axes = new AxesModel();
private ObservableList<FunctionModel> functions =
private ObservableList<FunctionModel> functions =

FXCollections.observableArrayList();
FXCollections.observableArrayList();

public AxesModel getAxes()


public AxesModel getAxes()
{
{
return
return axes;
axes;
}
}

public ObservableList<FunctionModel> getFunctions()


public ObservableList<FunctionModel> getFunctions()
{
{
return
return functions;
functions;
}
}
}
}

The
The iteration
iteration adds
adds the
the following
following dialog
dialog that
that is
is used
used to
to define
define aa plot
plot graph:
graph:
The iteration adds the following dialog that is used to define a plot graph:

203
203
203
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

In the table on the left, you can enter points and the two buttons below the table are used
to create a point and delete a point where the button Remove row deletes the row that is
selected. The following type has been added to the model:

American online
LIGS University
is currently enrolling in the
Interactive Online BBA, MBA, MSc,
DBA and PhD programs:

▶▶ enroll by September 30th, 2014 and


▶▶ save up to 16% on the tuition!
▶▶ pay in 10 installments / 2 years
▶▶ Interactive Online education
▶▶ visit www.ligsuniversity.com to
find out more!

Note: LIGS University is not accredited by any


nationally recognized accrediting agency listed
by the US Secretary of Education.
More info here.

204
JAVA 15: MORE ABOUT JAVAFX:
JAVA
JAVA 15:
15: MORE
SOFTWARE MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
DEVELOPMENT Final Example
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT FInal
FInal eXaMple
eXaMple

public class PlotPoint


{
private DoubleProperty x = new SimpleDoubleProperty(0);
private DoubleProperty y = new SimpleDoubleProperty(0);

which represents
which represents aa point
point to
to aa plot
plot graph.
graph. To
To the
the right
right you
you can
can define
define options
options for
for the
the plot
plot
graph. A
graph. A graph
graph must
must have
have aa name
name that
that can
can be
be used
used to
to identify
identify the
the graph
graph at
at the
the user
user interface.
interface.
The type
The type PlotType
PlotType isis used
used to
to specify
specify the
the geometry
geometry ofof aa point:
point:

public class PlotType


{
public static ObservableList<String> types =
FXCollections.observableArrayList();

static
{
types.addAll("Circle", "Square", "Rhombus", "Cross");
}
}

while the
while the next
next two
two comboboxes
comboboxes defines
defines the
the size
size and
and color
color of
of the
the point.
point. The
The following
following
checkbox indicates
checkbox indicates whether
whether the
the points
points should
should be
be joined
joined by
by lines
lines and,
and, ifif applicable,
applicable, there
there
are two
are two options:
options:

public class LineType


{
public static ObservableList<String> types =
FXCollections.observableArrayList();
static
{
types.addAll("Line", "Curve");
}
}

To
To implement
implement the
the dialog,
dialog, the
the view
view layer
layer isis expanded
expanded with
with two
two classes:
classes: PlotView
PlotView and
and
PlotPresenter. There was added a new button to the toolbar, but otherwise the biggest
PlotPresenter. There was added a new button to the toolbar, but otherwise the biggest change change
isis the
the extension
extension of
of the
the class
class Plot,
Plot, so
so itit can
can now
now also
also draw
draw plot
plot graphs.
graphs.

10.8
10.8 REFACTORING
REFACTORING THE
THE EXPRESSION
EXPRESSION DIALOG
DIALOG
The
The program
program has
has aa few
few missings
missings in
in drawing
drawing graphs,
graphs, as
as the
the class
class Plot
Plot does
does not
not take
take into
into account
account
the domain for a function. This may cause incorrect graphs or graphs that appear
the domain for a function. This may cause incorrect graphs or graphs that appear incorrect. incorrect.
II have
have therefore
therefore introduced
introduced an
an iteration
iteration solely
solely for
for the
the purpose
purpose ofof solving
solving this
this problem.
problem.

205
205
205
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

Basically,
Basically, itit isis important
important to
to specify
specify aa function’s
function’s domain,
domain, and
and the
the dialog
dialog ExpressionView
ExpressionView isis
therefore
therefore expanded
expanded to: to:

ItIt isis now


now possible
possible to
to add
add aa number
number of of intervals
intervals where
where thethe union
union ofof these
these intervals
intervals isis the
the
domain.
domain. IfIf you
you do
do not
not enter
enter any
any intervals,
intervals, the
the domain
domain isis perceived
perceived as
as the
the real
real axis.
axis. For
For each
each
interval
interval youyou can
can enter
enter 44 values:
values:

1.
1. AA isis the
the left
left end
end point.
point. IfIf the
the value
value isis blank,
blank, the
the left
left end
end point
point isis minus
minus infinity.
infinity.
2.
2. Start
Start indicating
indicating aa mark
mark for
for thethe starting
starting point.
point. IfIf blank,
blank, no
no mark
mark isis displayed,
displayed, but
but
otherwise
otherwise itit may may be
be Close,
Close, which
which means
means aa filled
filled circle
circle or
or Open,
Open, which
which means
means anan
open
open circle.
circle.
3.
3. B is the right
B is the right end
end point.
point. IfIf the
the value
value isis blank,
blank, thethe right
right end
end point
point isis infinite.
infinite.
4.
4. End
End thatthat indicates
indicates aa mark
mark for for the
the end
end point.
point. IfIf blank,
blank, nono mark
mark isis displayed,
displayed, but
but
otherwise
otherwise itit may may be
be Close,
Close, which
which means
means aa filled
filled circle
circle or
or Open,
Open, which
which means
means anan
open
open circle.
circle.

The
The extension
extension means
means some
some changes
changes to
to the
the model
model where
where there
there isis aa model
model class
class for
for an
an interval:
interval:

public class Interval


{
private DoubleProperty a = new
SimpleDoubleProperty(Double.NEGATIVE_INFINITY);
private StringProperty lower = new SimpleStringProperty("");

private DoubleProperty b = new SimpleDoubleProperty(Double.
POSITIVE_INFINITY);
private StringProperty upper = new SimpleStringProperty("");

206
206
JAVA
JAVA15:
15:MORE
MOREABOUT
ABOUTJAVAFX:
JAVAFX:
SOFTWARE
SOFTWAREDEVELOPMENT
DEVELOPMENT Final
FInalExample
eXaMple

and
and the
the class
class ExpressionModel
ExpressionModel isis also
also changed
changed

public class ExpressionModel extends FunctionModel


{
private Expression expression;
private ObservableList<Interval> intervals =
FXCollections.observableArrayList();

The
The most
most comprehensive
comprehensive changes
changes in in this
this iteration,
iteration, however,
however, are
are the
the class
class Plot,
Plot, since
since itit must
must
take
take into
into account
account that
that aa function
function cancan now
now have
have aa domain,
domain, andand eventually
eventually endpoints
endpoints may may
be
be drawn. Finally, the class should behave nicely if you draw a graph that is not defined on
drawn. Finally, the class should behave nicely if you draw a graph that is not defined on
the entire real axis, but fails to specify a domain. As a result, the class has gradually
the entire real axis, but fails to specify a domain. As a result, the class has gradually become become
relatively
relatively complex,
complex, andand the
the class
class may
may eventually
eventually bebe included
included inin aa refactoring.
refactoring.

10.9
10.9 IMPLEMENTING
IMPLEMENTING THE
THE FUNCTIONS
FUNCTIONS MENU
MENU
The
The next
next iteration
iteration includes,
includes, according
according to
to the
the plan,
plan, to
to implement
implement all
all functions
functions in
in the
the menu.
menu.
There
There are
are some,
some, and
and some
some ofof them
them are
are even
even quite
quite complex,
complex, so
so here
here II shared
shared the
the iteration
iteration

207
207
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

into
into multiple
multiple iterations
iterations with
with one
one iteration
iteration for
for each
each menu.
menu. In
In this
this iteration
iteration II will
will look
look at
at
the
the Functions
Functions menu
menu that
that should
should include
include the
the following
following menu
menu items:
items:

--- Create
Create new
new function
function
--- Create/modify
Create/modify tanget
tanget
--- Create/modify
Create/modify vertical
vertical lines
lines
--- Insert/modify
Insert/modify hatching
hatching
--- Create point series
Create point series
--- Modify
Modify functions
functions
--- Modify
Modify point
point series
series

The
The class
class MainMenu
MainMenu isis updated
updated accordingly.
accordingly. The
The class
class has
has an
an instance
instance variable
variable

Map<String, MenuItem> items = new HashMap();

with package visibility, where each menu item is identified by a key, and the map is used to
with package visibility, where each menu item is identified by a key, and the map is used to
allow in MainPresenter to assign event handlers to the individual menu items. The first and
allow in MainPresenter to assign event handlers to the individual menu items. The first and
third last menu items corresponds to functions (create new function and create plot) that are
third last menu items corresponds to functions (create new function and create plot) that are
already implemented as buttons in the toolbar, so nothing else than the class MainPresenter
already implemented as buttons in the toolbar, so nothing else than the class MainPresenter
has to associate the right event handler.
has to associate the right event handler.

The menu item Create/modify tangent is a new function, where it should be possible to draw
The menu item Create/modify tangent is a new function, where it should be possible to draw
a tangent to a function at a given point. If you select the function, you will receive the
a tangent to a function at a given point. If you select the function, you will receive the
following window, which at the bottom shows a summary of the functions added to the
following window, which at the bottom shows a summary of the functions added to the
drawing, and if you select one of these functions, you can add points for tangents in the
drawing, and if you select one of these functions, you can add points for tangents in the
upper table, as well as parameters for the color and thickness of the tangent:
upper table, as well as parameters for the color and thickness of the tangent:

208
208
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

When
When youyou click
click OK,
OK, the
the appropriate
appropriate tangents
tangents are
are drawn.
drawn. The
The function
function requires
requires an
an expansion
expansion
of
of the
the class
class ExpressionModel,
ExpressionModel, as
as aa function
function can
can now
now have
have associated
associated tangents:
tangents:

public class ExpressionModel extends FunctionModel


{
private Expression expression;
private ObservableList<Interval> intervals =
FXCollections.observableArrayList();

private ObservableList<LineModel> tangents =
FXCollections.observableArrayList();

Here, LineModel is a simple model class that extends the class FunctionModel with a single
Here, LineModel
property for the istangent’s
a simplefoot
model classInthat
point. extends
order the class
to draw FunctionModel
a tangent, with aclass
the Expression singleis
property
expandedfor thea tangent’s
with foot point.
method that, In order
as a limit value,tocan
draw a tangent,
calculate the Expression
the differential class in
quotient is
expanded
a point. with a method that, as a limit value, can calculate the differential quotient in
a point.
The menu item Create / Modify vertical lines should be used to inserts vertical lines into a
The menufor
drawing, item Create vertical
example, / Modifyasymptotes.
vertical linesThe
should be used
function to the
opens inserts verticalwindow:
following lines into a
drawing, for example, vertical asymptotes. The function opens the following window:

209
209
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final eXaMple
FInal Example

where
where you
you cancan add
add points
points (x-values) where the vertical line has to
to cross
cross the
the x-axis.
x-axis. The
The
function
function isis relatively
relatively simple,
simple, but requires an extension of the model:

public class Model


{
private AxesModel axes = new AxesModel();
private ObservableList<FunctionModel> functions =
FXCollections.observableArrayList();
private ObservableList<LineModel> lines = FXCollections.observableArrayList();

210
210
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

and similarly, the class Plot must be updated so that it draws the vertical lines.

The next feature Insert/Modify hatching allows you to insert hatching below or above a
function and if you selects the menu item, you get the following window:

where to choose the function. If you click OK then you get the window:

Here you can insert vertical and horizontal constraints on the area to be hatched, as well
as selecting the color for the hatching, as well as whether it should be a standard fill or
a pattern. The function is not quite simple to implement, and the class Plot should be
significantly expanded. In addition, the model class ExpressionModel must be expanded
with a new variable:

211
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Final Example
SOFTWARE DEVELOPMENT FInal eXaMple

public class ExpressionModel extends FunctionModel


{
private Expression expression;
private HatchModel hatching;
private ObservableList<Interval> intervals =
FXCollections.observableArrayList();

private ObservableList<LineModel> tangents =
FXCollections.observableArrayList();

The function
The function maymay possibly
possibly hatch
hatch an
an unintended
unintended area
area ifif restrictions
restrictions are
are set
set on
on xx and
and yy and
and
ifif the
the function’s
function’s graph
graph cross
cross through
through the
the selected
selected area.
area. The
The reason
reason isis that
that the
the hatching
hatching area
area
isis defined
defined as
as aa Path,
Path, and
and itit should
should be
be changed
changed in in aa future
future version
version of of the
the program.
program.

Thelast
The lasttwo
twofunctions
functionsof ofthe
theFunctions
Functionsmenu
menuare arein
inprinciple
principleimplemented,
implemented,as asthey
theycorrespond
correspond
to edit
to edit aa function
function or
or edit
edit aa plot
plot already
already created.
created. TheThe only
only thing
thing missing
missing isis aa way
way to
to choose
choose
the function
the function or or plot
plot to
to be
be edited,
edited, and
and itit isis done
done inin the
the same
same way
way as
as above
above with
with hatching.
hatching.

In connection
In connection with
with this
this iteration,
iteration, the
the function
function for
for drawing
drawing aa plot
plot isis expanded,
expanded, so
so the
the line
line
type to
type to connect
connect the
the points
points nownow can
can also
also can
can be
be aa regression
regression line.
line.

10.10
10.10 IMPLEMENTING THE
IMPLEMENTING THE ZOOM
ZOOM MENU
MENU
The menu
The menu must
must have
have the
the following
following features:
features:

--- Zoom out


Zoom out
--- Zoom in
Zoom in
--- Divide after
Divide after x-axis
x-axis
--- Divide after
Divide after y-axis
y-axis
--- Default
Default

Here, the
Here, the third
third and
and fourth
fourth function
function means
means that that the
the two
two axes
axes determined
determined by by the
the division
division
of the
of the x-axis
x-axis and
and the
the y-axis
y-axis respectively,
respectively, mustmust use
use the
the same
same distance
distance between
between thethe points
points
on the
on the axes.
axes. The
The last
last menu
menu itemitem must
must reset
reset the
the axes
axes to
to default.
default. The
The toolbar
toolbar initially
initially had
had
three buttons
three buttons forfor zoom,
zoom, but
but thethe latter
latter isis replaced
replaced by
by two
two other
other buttons,
buttons, so
so there
there are
are now
now
44 buttons
buttons corresponding
corresponding to to the
the top
top 44 menu
menu items.
items.

In principle,
In principle, itit isis quite
quite simple
simple to
to implement
implement these
these functions
functions and
and requires
requires only
only simple
simple
changes in
changes in the
the two
two classes
classes AxisModel
AxisModel and
and AxesModel
AxesModel and,
and, of
of course,
course, changes
changes in
in the
the class
class
MainPresenter, so
MainPresenter, so that
that event
event handlers
handlers are
are associated.
associated.

212
212
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

However, there is a single challenge to be solved. Until this place it is assumed that the two
axes intersect at the center of the window. It does not work if it’s possible to zoom, and
more generally if you change the smallest and greatest values of the axes. It is necessary to
change both in the Axes class and the class Plot, so they take into account that the coordinate
system’s origin is not necessarily centered in the window.

10.11 IMPLEMENTING THE EDIT MENU


This menu must have 4 menu items:

-- Undo
-- Redo
-- Screen clip
-- Axes

Here is the last the function for maintaining the coordinate system’s axes and thus the same
function implemented on one of the toolbar buttons. The Screen clip feature is one of the

Join the best at Top master’s programmes


• 3
 3rd place Financial Times worldwide ranking: MSc
the Maastricht University International Business
• 1st place: MSc International Business
School of Business and • 1st place: MSc Financial Economics
• 2nd place: MSc Management of Learning

Economics! • 2nd place: MSc Economics


• 2nd place: MSc Econometrics and Operations Research
• 2nd place: MSc Global Supply Chain Management and
Change
Sources: Keuzegids Master ranking 2013; Elsevier ‘Beste Studies’ ranking 2012;
Financial Times Global Masters in Management ranking 2012

Maastricht
University is
the best specialist
university in the
Visit us and find out why we are the best! Netherlands
(Elsevier)
Master’s Open Day: 22 February 2014

www.mastersopenday.nl

213
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

program’s
program’s most
most important
important functions
functions and
and isis one
one of
of the
the goals
goals of
of the
the entire
entire application.
application. The
The
function,
function, on
on the
the other
other hand,
hand, isis simple
simple to
to implement,
implement, as
as JavaFX
JavaFX offers
offers itit all:
all:

private void clipGraph(ActionEvent e)


{
WritableImage image = view.imagePane.
snapshot(new SnapshotParameters(), null);
ClipboardContent cc = new ClipboardContent();
cc.putImage(image);
Clipboard.getSystemClipboard().setContent(cc);
}

AA Node
Node –– and
and here
here itit isis aa StackPane
StackPane –– has
has aa method
method snapshot()
snapshot() which
which simply
simply takes
takes aa picture
picture
of the component. In fact, it is a PNG image and the image can be placed
of the component. In fact, it is a PNG image and the image can be placed immediately immediately
on
on the
the clipboard.
clipboard.

Then
Then there
there are
are the
the other
other two two features,
features, and
and on
on the
the other
other hand, hand, itit isis not
not simple.
simple. For
For some
some
reasons, JavaFX does not support Undo/Redo, but it must be assumed
reasons, JavaFX does not support Undo/Redo, but it must be assumed that it will be included that it will be included
in
in later
later versions
versions ofof the
the API.
API. One One can
can find
find more
more open
open source
source APIs APIs forfor Undo/Redo
Undo/Redo online,
online,
and
and it may be a good task to replace the following with one of these APIs. On the other
it may be a good task to replace the following with one of these APIs. On the other
hand, it is not entirely easy, partly because the APIs in question
hand, it is not entirely easy, partly because the APIs in question may not be comprehensive may not be comprehensive
enough,
enough, and and partly
partly because
because they they can
can be
be soso general
general that
that itit isis in
in itself
itself aa piece
piece of
of work
work toto learn
learn
how they are used. In this case, I have solved the problem
how they are used. In this case, I have solved the problem by programming the necessaryby programming the necessary
from
from scratch.
scratch. InIn fact,
fact, itit isis not
not particularly
particularly difficult,
difficult, but
but the the problem
problem isis of of course
course that
that itit isis
not
not modifiable
modifiable and and can
can notnot immediately
immediately be be used
used in
in other
other programs.
programs.

In
In principle,
principle, Undo/Redo
Undo/Redo isis about
about when
when you you perform
perform anan operation
operation inin the
the program,
program, itit isis
simultaneously
simultaneously stored
stored on
on aa stack,
stack, and
and ifif you
you executes
executes an
an Undo
Undo (keys
(keys Ctrl
Ctrl ++ Z),
Z), the
the operation
operation
must
must be rolled back and then placed on the redo stack . Redo (when keying Ctrl + Y) basically
be rolled back and then placed on the redo stack . Redo (when keying Ctrl + Y) basically
happens
happens in the same way, just do not undo the operation but instead restore it and move
in the same way, just do not undo the operation but instead restore it and move itit
over
over to
to the
the undo
undo stack.
stack. For
For soso long
long it’s
it’s all
all simple,
simple, but
but there
there are
are two
two outstanding
outstanding problems:
problems:

1.
1. What
What isis an
an operation
operation –– what
what isis itit you
you should
should be
be able
able to
to undo
undo and
and redo?
redo?
2. What should be pushed on the
2. What should be pushed on the stack? stack?

In
In this
this case,
case, itit has
has been
been decided
decided that
that the
the operations
operations to
to be
be rolled
rolled back
back are:
are:

--- Change
Change the
the coordinate
coordinate system’s
system’s settings
settings –– an
an AxesModel
AxesModel object
object
--- Add a new function – an ExpressionModel
Add a new function – an ExpressionModel object object
--- Change
Change aa function
function –– anan ExpressionModel
ExpressionModel object
object
--- Delete a function – an ExpressionModel
Delete a function – an ExpressionModel object object
--- Add
Add aa new
new plot
plot to
to the
the graph
graph –– an
an object
object of
of the
the type
type PlotModel
PlotModel

214
214
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple
SOFTWARE DEVELOPMENT FInal eXaMple

--- Changing
Changing aa plot
plot –– an
an object
object of
of the
the type
type PlotModel
PlotModel
- Changing a plot – an object of the type PlotModel
--- Delete
Delete aa plot
plot –– an
an object
object of
of the
the type
type PlotModel
PlotModel
- Delete a plot – an object of the type PlotModel
--- Change
Change a function’s tangent – an OberservableList object<LineModel>
a function’s tangent – an OberservableList object<LineModel> object
object
- Change a function’s tangent – an OberservableList object<LineModel> object
--- Changing
Changing the vertical lines of the graph – an OberservableList object<LineModel>object
the vertical lines of the graph – an OberservableList object<LineModel> object
- Changing the vertical lines of the graph – an OberservableList object<LineModel> object
--- Add
Add aa hatching
hatching to to aa function
function –– anan object
object of
of the
the type
type HatchModel
HatchModel
- Add a hatching to a function – an object of the type HatchModel
--- Change
Change aa function’s
function’s hatching
hatching –– anan object
object ofof the
the type
type HatchModel
HatchModel
- Change a function’s hatching – an object of the type HatchModel
--- Delete a function’s hatching – an object of the type
Delete a function’s hatching – an object of the type HatchModel HatchModel
- Delete a function’s hatching – an object of the type HatchModel

These
These possible
possible operations
operations (the
(the operations
operations to
to be
be saved
saved for
for undo)
undo) are
are defined
defined using
using the
the
These possible operations (the operations to be saved for undo) are defined using the
following
following enumeration:
enumeration:
following enumeration:

public enum GraphOperations { AXES, ADDFUNC, MODFUNC, DELFUNC, ADDPLOT,


public enum GraphOperations { AXES, ADDFUNC, MODFUNC, DELFUNC, ADDPLOT,
MODPLOT, DELPLOT, MODTANG, MODLINE, ADDHATCH, MODHATCH, DELHATCH }
MODPLOT, DELPLOT, MODTANG, MODLINE, ADDHATCH, MODHATCH, DELHATCH }

An Undo
An Undo / Redo operation
operation is then defined
defined as follows:
follows:
An Undo // Redo
Redo operation isis then
then defined as
as follows:

public class GraphOperation


public class GraphOperation
{
{
private GraphOperations operation;
private GraphOperations operation;
private Object value;
private Object value;

public GraphOperation(GraphOperations operation, Object value)


public GraphOperation(GraphOperations operation, Object value)
{
{
this.operation = operation;
this.operation = operation;
this.value = value;
this.value = value;
}
}

public GraphOperations getOperation()


public GraphOperations getOperation()
{
{
return operation;
return operation;
}
}

public Object getValue()


public Object getValue()
{
{
return value;
return value;
}
}

public void setValue(Object value)


public void setValue(Object value)
{
{
this.value = value;
this.value = value;
}
}
}
}

215
215
215
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

and
and you
you can
can thus
thus save
save any
any object,
object, but
but with
with an
an indication
indication ofof which
which operation
operation the
the object
object isis
about.
about. Back
Back isis the
the UndoManager
UndoManager class
class as
as the
the class
class that
that saves
saves the
the operations
operations and
and performs
performs
an
an undo()
undo() or
or aa redo():
redo():

public class UndoManager


{
private static UndoManager instance;
private Stack<GraphOperation> undoOperations = new Stack();
private Stack<GraphOperation> redoOperations = new Stack();

private UndoManager() {}

public static UndoManager getInstance() { … }

public void add(GraphOperation opr)


{
undoOperations.push(opr);
}

public void undo(Model model)


{
doOperation(model, undoOperations, redoOperations, true);
}

216
216
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Final Example
SOFTWARE DEVELOPMENT FInal eXaMple

public void redo(Model model)


{
doOperation(model, redoOperations, undoOperations, false);
}

private void doOperation(Model model, Stack<GraphOperation> stack1,


Stack<GraphOperation> stack2, boolean undo)
{
if (!stack1.empty())
{
GraphOperation opr = stack1.pop();
try
{
switch (opr.getOperation())
{
case AXES:
AxesModel axes = model.getAxes();
model.setAxes((AxesModel)opr.getValue());
opr.setValue(axes);
break;

}
stack2.push(opr);
}
catch (Exception ex)
{
}
}
}
}

The class
The class is
is written
written as
as aa singleton,
singleton, and
and the
the entire
entire work
work is
is in
in the
the private
private method
method doOperation(),
doOperation(),
where there
where there is
is aa case
case entry
entry for
for every
every possible
possible operation.
operation.

Each time
Each time the
the program
program performs
performs an
an operation,
operation, itit must
must be
be saved
saved and
and thus
thus the
the method
method add()
add()
above must
above must bebe performed.
performed. ItIt happens
happens in
in the
the presenter
presenter classes
classes of
of the
the individual
individual dialog
dialog boxes,
boxes,
where copies
where copies of
of the
the individual
individual operations
operations are
are wrapped
wrapped inin GraphOperation
GraphOperation objects
objects that
that are
are
then pushed
then pushed on on the
the undo
undo stack.
stack. When
When youyou want
want to
to perform
perform anan undo
undo or
or redo
redo either
either by
by
clicking the
clicking the menu
menu oror by
by pressing
pressing Ctrl+Z
Ctrl+Z oror Ctrl+Y,
Ctrl+Y, the
the corresponding
corresponding method
method isis executed
executed
in the
in the class
class UndoManager.
UndoManager.

217
217
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

10.12 IMPLEMENTING THE CALCULATIONS MENU


It’s a very simple iteration as this menu only should have a single function:

-- Function table

The idea is that the menu will later be expanded with other calculation functions. The
current function opens a window for a particular function, where you can create a table of
function values within an interval:

Implementation of the function simply means writing the code for the above dialog box:
FuncTableView and FuncTablePresenter, as well as for other functions in the menu, a simple
dialog for selecting the function.

10.13 IMPLEMENTING THE FILE MENU


This iteration includes the last menu that must have 5 functions:

-- New
-- Open
-- Save
-- Save as
-- Exit

218
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

Here is the last trivial, while the top three are also assigned to buttons in the toolbar. The
goal is that it should be possible to save a drawing and later re-load the drawing. Since the
program is a tool that should be easy to install, drawings must not be saved in a database,
but in ordinary files. Here are four options:

1. to save drawings as JSON documents


2. to save drawings as XML documents
3. to save the drawings by conventional object serialization
4. to save drawings in a custom format

Here is the first the most obvious, as JSON does not fill up much, is a standard and is text
and can therefore be read by everyone and thus other programs. It requires that a Model
object can be converted to JSON, and that the JSON text loading again can create a Java
object. There are open source APIs that can do that and examples are GSON and Jackson,
which are both excellent products. Unfortunately, they do not work in the current case,
and the reason is that it is a deep and complex object structure, but primarily that JavaFX
is causing problems. Both products outline solutions that more or less directly solve the
problems. It is apparently not quite simple, but one expects that future versions can be
used directly. Because of that, I have abandoned using JSON.

219
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

As for XML, it’s a bit the same, and the benefits are the same except that XML fills a lot.
Also here are finished products that can be used, and JAXB is even an integral part of Java.
If you often need to work with XML documents, it may be worth learning JAXB, and it
would be a good job to replace the following with XML.

Storing drawings using object serialization is not appropriate in this case. Among other
things, at the start of the project, I mentioned that it was not desirable, but in fact it also
gives a problem to JavaFX, as properties and other JavaFX types are not serializable. At
least, serialization of objects would require some extra work.

I will therefore choose the last of the above options and save drawings as text files, but in a
custom format. In practice, it may sometimes be of interest, and it is also not very difficult,
but in turn, there are a few significant disadvantages. Since it is a custom and non-transparent
format, it is difficult to apply the files in other contexts than in the current application.
The contents of the files do not follow any standard. That in itself will often mean that a
method like the following is rejected. Secondly, a custom format like the following is not
easy to maintain, and if the model is changed, the code to save drawings and read them
again must be changed accordingly, which means it is very expensive to change the model.
The question is then whether there are any benefits and that’s hardly, but should I imply
two, it should be that the format is very compact and saved drawings do not fill up much,
which may be important if drawings should send over a network, and second as an example
of what it takes to build an object hierarchy from a text (it is by default what parsing either
JSON or XML does).

So to the specific solution. There are generally two things to do:

1. a Model object must be converted into a text which can be saved in a file
2. the content of a file (a saved drawing) must be split into values to be used to
construct a Model object identical to the object that has been saved.

To solve these problems, it is necessary to use some separators that can be used to separate
values, and the only requirement is that it should be characters that can not occur in the
individual data elements. In this case, I need three, and I want to apply line breaks, carrige
return and tabs, and thus \n, \r and \t. As the next step, each model class, whose objects
are to be saved as part of the drawing, are expanded with a method asText(), which returns
the object’s data elements separated with the separators. As an example, the class AxisModel
is expanded with the following method:

220
JAVA 15:
JAVA 15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
JAVA 15: MORE
SOFTWARE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT
DEVELOPMENT FInal Example
Final eXaMple
SOFTWARE DEVELOPMENT FInal eXaMple

public String asText()


public String asText()
{
{
StringBuilder builder = new StringBuilder();
StringBuilder builder = new StringBuilder();
builder.append(getMin());
builder.append(getMin());
builder.append('\t');
builder.append('\t');
builder.append(getMax());
builder.append(getMax());
builder.append('\t');
builder.append('\t');
builder.append(getDec());
builder.append(getDec());
builder.append('\t');
builder.append('\t');
builder.append(getTicks());
builder.append(getTicks());
builder.append('\t');
builder.append('\t');
builder.append(getLabel());
builder.append(getLabel());
builder.append('\t');
builder.append('\t');
builder.append(getCross());
builder.append(getCross());
builder.append('\t');
builder.append('\t');
builder.append(isAutoTicks());
builder.append(isAutoTicks());
builder.append('\t');
builder.append('\t');
builder.append(isShowTicks());
builder.append(isShowTicks());
builder.append('\t');
builder.append('\t');
builder.append(isShowGitter());
builder.append(isShowGitter());
builder.append('\t');
builder.append('\t');
builder.append(isShowNumbers());
builder.append(isShowNumbers());
return builder.toString();
return builder.toString();
}
}

That is,
That is, the
the method
method returns
returns all
all settings
settings for
for aa number
number axis
axis as
as aa string
string where
where the
the individual
individual
That is, the method returns all settings for a number axis as a string where the individual
values are
values are separated
separated by
by the
the tab
tab character.
character. Similarly,
Similarly, the
the class
class AxesModel
AxesModel isis expanded
expanded using
using
values are separated by the tab character. Similarly, the class AxesModel is expanded using
the following
the following method:
method:
the following method:
public String asText()
public String asText()
{
{
return xaxis.asText() + '\r' + yaxis.asText();
return xaxis.asText() + '\r' + yaxis.asText();
}
}

which
which returns
returns data
data for
for the
the x-axis
x-axis and
and y-axis,
y-axis, respectively,
respectively, separated
separated by
by aa carrige
carrige return.
return. The
The
which returns data for the x-axis and y-axis, respectively, separated by a carrige return. The
same
same applies
applies to
to the
the other
other model
model classes:
classes:
same applies to the other model classes:

--- ColorWrapper
ColorWrapper
- ColorWrapper
--- PlotPoint
PlotPoint
- PlotPoint
--- PlotModel
PlotModel
- PlotModel
--- LineModel
LineModel
- LineModel
--- Interval
Interval
- Interval
--- HatchModel
HatchModel
- HatchModel
--- ExpressionModel
ExpressionModel
- ExpressionModel
--- Model
Model
- Model

221
221
221
JAVA
JAVA 15:
15: MORE
MORE ABOUT
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
eXaMple

where
where some
some of
of course
course are
are more
more complex
complex than
than the
the above.
above. AsAs an
an example,
example, below
below isis shown
shown
asText()
asText() from
from the
the class
class Model,
Model, which
which returns
returns the
the text
text to
to be
be saved:
saved:

public String asText()


{
StringBuilder builder = new StringBuilder();
builder.append(axes.asText());
for (FunctionModel fm : functions)
{
builder.append('\n');
builder.append(fm.asText());
}
if (lines.size() > 0)
{
for (LineModel lm : lines)
{
builder.append('\n');
builder.append(lm.asText());
}
}
return builder.toString();
}

Need help with your


dissertation?
Get in-depth feedback & advice from experts in your
topic area. Find out what you can do to improve
the quality of your dissertation!

Get Help Now

Go to www.helpmyassignment.co.uk for more info

222
222
JAVA
JAVA 15:
JAVA 15: MORE
15: MORE ABOUT
MORE ABOUT JAVAFX:
ABOUT JAVAFX:
JAVAFX:
SOFTWARE
SOFTWARE DEVELOPMENT
SOFTWARE DEVELOPMENT
DEVELOPMENT Final
FInal Example
FInal eXaMple
eXaMple

where
where the
where the result
the result technically
result technically isis
technically is aaa text
text divided
text divided into
divided into lines.
into lines. Then
lines. Then an
Then an event
an event handler
event handler in
handler in MainPresenter
in MainPresenter
MainPresenter
can
can write
write the
the text
text of
of a
a file:
file:
can write the text of a file:

try (FileWriter writer = new FileWriter(filename))


try (FileWriter writer = new FileWriter(filename))
{
{
writer.write(model.asText());
writer.write(model.asText());
}
}
catch (IOException ex)
catch (IOException ex)
{
{


}
}

It
It isis
It then
is then easy
then easy to
easy to read
to read the
read the content
the content of
content of the
of the file
the file again:
file again:
again:

try (FileReader reader = new FileReader(filename))


try (FileReader reader = new FileReader(filename))
{
{
char[]
char[] buffer
buffer == new
new char[2048];
char[2048];
StringBuilder
StringBuilder builder =
builder = new
new StringBuilder();
StringBuilder();
for
for (int count = reader.read(buffer, 0,
(int count = reader.read(buffer, 0, buffer.length);
buffer.length); count != -1;
count != -1;
count = reader.read(buffer, 0, buffer.length))
count = reader.read(buffer, 0, buffer.length))
builder.append(buffer,
builder.append(buffer, 0,0, count);
count);
if (!model.parse(builder.toString())) throw new Exception();
if (!model.parse(builder.toString())) throw new Exception();
}
}
catch (Exception ex)
catch (Exception ex)
{
{


}
}

where
where aaa string
where string with
string with the
with the file’s
the file’s content
file’s content isis
content is built,
built, which
built, which isis
which is parsed
parsed by
parsed by aaa method
by method parse()
method parse() in
parse() in the
in the class
the class
class
Model.
Model. It
It is
is this
this method
method that
that is
is responsible
responsible for
for splitting
splitting the
the content
content of
of
Model. It is this method that is responsible for splitting the content of the file into valuesthe
the file
file into
into values
values
and
and using
and using these
using these to
these to initialize
to initialize the
initialize the Model
the Model object.
Model object. The
object. The code
The code of
code of the
of the method
the method parse()
method parse() isis
parse() is asas follows:
as follows:
follows:

public
public boolean
boolean parse(String
parse(String text)
text)
{
{
try
try
{
{
String[]
String[] elems
elems =
= text.split("\n");
text.split("\n");
if (elems.length == 0) throw new Exception();
if (elems.length == 0) throw new Exception();

AxesModel am = parseAxes(elems[0]);
AxesModel am = parseAxes(elems[0]);

O
ObservableList<FunctionModel> functions =
bservableList<FunctionModel> functions =
FXCollections.observableArrayList();
FXCollections.observableArrayList();

ObservableList<LineModel> lines = FXCollections.observableArrayList();
ObservableList<LineModel> lines = FXCollections.observableArrayList();
for
for (int
(int i
i =
= 1;
1; ii <
< elems.length;
elems.length; ++i)
++i)
{
{

if (elems[i].charAt(0) == 'E') functions.add(parseExpression(elems[i]));
if (elems[i].charAt(0) == 'E') functions.add(parseExpression(elems[i]));

else if (elems[i].charAt(0) == 'P') functions.add(parsePlot(elems[i]));
else if (elems[i].charAt(0) == 'P') functions.add(parsePlot(elems[i]));
else if (elems[i].charAt(0) == 'L') lines.add(parseLine(elems[i]));
else if (elems[i].charAt(0) == 'L') lines.add(parseLine(elems[i]));
}
}

223
223
223
JAVA 15: MORE ABOUT JAVAFX:
JAVA 15: MORE
SOFTWARE ABOUT JAVAFX:
DEVELOPMENT Final Example
SOFTWARE DEVELOPMENT FInal eXaMple

this.axes = am;
this.functions = functions;
this.lines = lines;
return true;
}
catch (Exception ex)
{
}
return false;
}

but
but it
it uses
uses several
several auxiliary
auxiliary methods.
methods. However,
However, the
the above
above can
can give
give an
an impression
impression of
of how
how
the
the method
method works:
works:

1.
1. the
the string
string that
that is
is read
read in
in the
the file
file is
is split
split into
into lines
lines (the
(the separator
separator character
character \n)
\n)
2. the first line is parsed to an AxesModel
2. the first line is parsed to an AxesModel object object
3.
3. then
then iterates
iterates over
over the
the remaining
remaining lines
lines (in
(in principle,
principle, there
there only
only have
have to
to be
be the
the one
one
for
for axes)
axes) and
and each
each element
element isis parsed
parsed as
as either
either an
an ExpressionModel,
ExpressionModel, aa PlotModel
PlotModel oror
aa LineModel
LineModel object
object

If
If an
an exception
exception occurs
occurs during
during the
the process,
process, the
the parsing
parsing is
is interrupted
interrupted and
and the
the method
method returns
returns
false,
false, but if all goes well, the current Model object is initialized with the values parsed and
but if all goes well, the current Model object is initialized with the values parsed and
the
the method
method returns
returns true.
true.

The
The Iteration
Iteration includes
includes aa little
little more
more than
than what
what is
is shown
shown above,
above, but
but it
it is
is nothing
nothing but
but what
what
is
is shown
shown inin other
other programs.
programs. YouYou have
have to
to keep
keep track
track of
of when
when aa drawing
drawing has has been
been changed,
changed,
and
and before
before itit should
should be
be deleted
deleted you
you should
should get
get aa warning.
warning. It
It is
is aa task
task left
left for
for the
the class
class
UndoHandler, although the task because of cohesion probably not should be
UndoHandler, although the task because of cohesion probably not should be located there. located there.

10.14
10.14 A
A FINAL
FINAL ITERATION
ITERATION
According
According toto the
the plan,
plan, there
there should
should now
now bebe two
two iterations
iterations left,
left, but
but it
it has
has been
been merged
merged into
into
one.
one. The program is in principle complete and can be used for what was the purpose. In the
The program is in principle complete and can be used for what was the purpose. In the
following, I will review the program’s classes to remove inconvenience and adjust
following, I will review the program’s classes to remove inconvenience and adjust the user the user
interface
interface in
in some
some places.
places. Below
Below II have
have briefly
briefly mentioned
mentioned thethe most
most important
important adjustments.
adjustments.

--- A
A style
style sheet
sheet has
has been
been added
added toto the
the application
application that
that primarily
primarily contains
contains empty
empty style
style
classes
classes that
that are
are used
used in
in the
the application’s
application’s dialogs
dialogs for
for later
later styling
styling of
of the
the program.
program.
--- MainView
MainView has changed slightly where some icons have been replaced and
has changed slightly where some icons have been replaced and the
the
background color has been changed using a style. An icon has been
background color has been changed using a style. An icon has been added to the added to the
toolbar
toolbar to to copy
copy aa drawing
drawing to to the
the clipboard,
clipboard, and
and tooltips
tooltips have
have been
been added
added to
to all
all
toolbar
toolbar icons.
icons.

224
224
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

-- MainPresenter has been updated in several areas. There are removed two event
handlers (axes() and func()), which have been replaced by a call to the method
openDialog(). This method was previously found as a static method in the class
ViewTools and as a private method in MainPresenter. Here is the last removed, so
the class MainPresenter now also uses the static method in ViewTools. Finally, all
calls to Alert are replaced by static methods in the class MessageDialogs. The result
is that unnecessary code has been removed.
-- AxesView has two fields (number of decimals and auto tickmarks) on both axes that
are not used. These four fields have been removed. Fields for entering numbers
use a converter called ValueConverter. It’s an inner class, but it is moved to a class
with the package visibility in a file Converters.java. More dialogs uses converters,
and the goal is to gather these converters somewhere.
-- Three of the functions in the Functions menu and the function in Calculations
menu opens a simple dialog box for selecting a function. The respective views are
FuncSelectView, FuncTableSelectView, HatchSelectView and TangentSelectView. These
four classes are actually the same and are replaced by a single view called SelectView.
The corresponding presenter classes are also almost the same, but not entirely, and
instead of replacing them with a new one, I have kept the old ones as they are,
since they are small and quite simple.

Brain power By 2020, wind could provide one-tenth of our planet’s


electricity needs. Already today, SKF’s innovative know-
how is crucial to running a large proportion of the
world’s wind turbines.
Up to 25 % of the generating costs relate to mainte-
nance. These can be reduced dramatically thanks to our
systems for on-line condition monitoring and automatic
lubrication. We help make it more economical to create
cleaner, cheaper energy out of thin air.
By sharing our experience, expertise, and creativity,
industries can boost performance beyond expectations.
Therefore we need the best employees who can
meet this challenge!

The Power of Knowledge Engineering

Plug into The Power of Knowledge Engineering.


Visit us at www.skf.com/knowledge

225
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

-- In general, I have been through all dialogs and assigned styles to all controls.
-- The model classes are generally unchanged, but two of the classes use converters,
and they are as in the same way as in the view layer moved into their own file
called Converters.java. However, the classes Model and UndoManager are modified
as follows.
-- The class UndoManager actually encapsulates two concepts, namely undo/redo, and
to keep track of whether the model has been changed. In principle, it is unfortunate,
and the last functionality regarding the state of the model has therefore been moved
to its own class called ChangedManager. The class is written as a singleton and is
very simple.
-- The class Model was expanded in the previous iteration with the method parse()
used to parse the text read in a file. The disadvantage is that the class Model now
fills a lot, and so I have moved the parse() method into its own class called Parser.
The class has no other methods, and the only advantage is that the model class
becomes simpler and more manageable, but it may also make it easier to replace
how drawings are saved with something else.

After that, the program is complete and ready for use and as the last, I have written an
installation script so that the program can be easily installed on the machine.

10.15 A LAST REMARK


As mentioned in the introduction to this chapter, the FDrawer program is developed by a
form of prototyping. The term prototyping is sometimes used for a development as above,
although the word is not correctly used. By the term prototyping one understands the
development of a program, which is intended to illustrate the ideas of an application, and
after the prototype has been developed and presented, the actual system development begins
from the beginning, but not as a further development of the prototype. The prototype
is itself a model that is not used as part of the final system development. It is therefore
more correct to say that the program FDrawer is developed by a form of iterative system
development through very small iterations, sometimes referred to as sprints.

Today, all just a bit bigger programs are developed through a number of iterations, and
the difference is primarily how large these iterations are. In the present case they have been
very small and it has its pros and cons. The advantage is that you often observe progress in
the work and that the future users through presentations seeing frequently experience and
something is happening and thus maintain the interest for the program. It also supports
the fact that the requirements are determined continuously throughout the development
period, and thus the situation that, from the start, it is not entirely clear where it all will

226
JAVA 15: MORE ABOUT JAVAFX:
SOFTWARE DEVELOPMENT Final Example

end. It is also an advantage that you can quickly detect malicious decisions and unfortunate
solutions and thus quickly correct before you reach too far in the development of a particular
feature. A system development with many and very small iterations opens up a very close
course with the upcoming users and helps to end with a solution that meets the users’
requirements for the completed program. However, there are also disadvantages, and in
particular there is a risk that you will always have to change the code that has been made.
When you build on iteration on iteration, there is a great chance that you have to go back
and change something that has been programmed in previous iterations, among other things
because there are always new demands and wishes. That is precisely why traditional system
development speaks of analysis and design, which defines the requirements for the finished
program through the analysis, and under the design, it will be decided how to write the
program before doing the programming itself.

Now, it’s not a either or and you can perfectly combine iterative system development with
more traditional system development and will even always do. Today, it has been acknowledged
that by simply a slightly larger program it is impossible to carry out an analysis where all
requirements are identified and determined. All experience shows that if you do it, it still
does not meets the requirements. It’s simply impossible to think about it all and there will
certainly be new demands of requirements over the development period, and if there is no
user interaction at the development, one can almost be sure that the end of a program has
so many shortcomings and inconveniences that the user does not bother using it. Therefore,
in iterative system development, an iteration is a system development in its own, but not
necessarily as small iterations as the current example suggests. An iteration will generally have
a limited amount in time, and must lead the program from one stable state to another. The
result of an iteration is a milestone in system development, where the state of the program
can be presented and assessed by the upcoming users or the customer and possibly lead to
something being corrected and new requirements to be set. Typically, an iteration will be a
system development process in itself, including analysis, design, programming and testing,
but so that the weight changes over time, with the emphasis on analysis and design in the
first iterations, but in later iterations the analysis and design fill less as the requirements
are now established and the most important decisions regarding the design of the program
are also in place.

There are (many) guidelines for how many iterations there should be, but the truth is
that there are no golden rules. In general, experiments in system development, where the
goals are not clear, and where you experience is gained along the way, speak for very short
sprints, and perhaps something towards that illustrated in the current example, while tasks
where the goals are clearer speaks for a little longer iterations involving traditional system
development to ensure stable and secure progress in the development.

227

Vous aimerez peut-être aussi