Buscar

(Coding in JavaFX Step by Step Build Graphics Toolkit Book 1) (English Edition) Shufen Kuo, Bing Chao Huang IMAGE VIEWER in Java 8 JavaFX 8 Tutorial (2016)

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 196 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 196 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 196 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Offers	Reusable	Classes	and	Graphics	Applications
Including	Complete	Source	Codes
Coding	in	JavaFX
Step	by	Step
Build	Graphics	Toolkit
VOLUME	Ⅰ
IMAGE	VIEWER
in	Java	8	(JDK	8u66)
Shufen	Kuo
Bing-Chao	Huang
Copyright©	2016	Shufen	Kuo	&	Bing-Chao	Huang.
All	rights	reserved.
No	part	of	this	book	may	be	reproduced	or	distributed	in	any	form	or	by	any	means,	or
stored	in	a	database	or	retrieval	system,	without	the	prior	written	permission	from	the
authors	(Shufen	Kuo	&	Bing-Chao	Huang),	with	the	exception	that	the	source	codes	that
come	with	the	book	may	be	entered	and	executed	in	a	computer	system	for	learning
purpose,	but	they	may	not	be	reproduced	or	modified	for	publication	or	commercial	use
without	prior	written	permission	from	the	authors.
TABLE	OF	CONTENTS
ABOUT	THE	AUTHORS
ACKNOWLEDGMENT
PREFACE
How	this	book	is	organized
Why	Choose	This	Book
What	You	Need	for	This	Book
INTRODUCTION
VOLUME	Ⅰ:	DEVELOPING	IMAGE	VIEWING	COMPONENTS
Chapter	1:	Basic	Image	Viewer
1.1	Create	ImageViewer	Class	as	Subclass	of	Application
1.1.1	JavaFX	Application	Thread	vs.	Java	Launcher	Thread
1.1.2	Catch	Resize	Event	of	Image	Rendering	Area
1.2	Create	Menu	Bar
1.2.1	Add	File	Menu	to	Menu	Bar
1.2.2	Select	Image	File	from	File	Open	Dialog	and	Display	Image	on
StackPane
1.3	Create	Option	Menu	and	View	Submenu
1.3.1	Create	Toggle	Group,	Radio	Menu	Items	and	Add	Listener	for
selectedToggle	Property
1.4	Implement	Fit	Width,	Fit	Height	and	Original	Size	Viewing	Options
1.4.1	Approach	One:	Bind	ImageView‘s	fitWidth/fitHeight
Properties	to	Scene‘s	width/height	Properties	Respectively
1.4.1.1	Implement	Fit	Width	Viewing	Option
1.4.1.2	Implement	Fit	Height	Viewing	Option
1.4.1.3	Implement	Original	Size	Viewing	Option
1.4.1.4	Complete	Source	Codes	of	ImageViewer	Class
1.4.2	Approach	Two:	Change	Values	for	fitWidth	Property	and
fitHeight	property
1.4.2.1	Catch	Resize	Event	of	Scene	to	Adjust	Viewing	Size	of
Image
1.4.2.2	Complete	Source	Codes	of	ImageViewer	Class
1.5	Summary
Chapter	2:	Enhanced	Image	Viewer	with	Browsing	Buttons
2.1	Add	Next	Button
2.1.1	Use	Group	as	Parent	Container
2.1.2	Use	Shape	Class	for	Rendering	2D	Geometric	Primitives
2.1.3	Use	Rectangle	Shape	as	Bounding	Box	of	Custom-Made
Button
2.1.4	Paint	Background	and	Border	of	Shape
2.1.5	Set	Value	of	arcHeight	and	arcWidth	Properties	to	Render
Rounded	Rectangle
2.1.6	Use	Polygon	Shape	as	Visual	Sign	of	Next	Icon
2.1.7	Set	Value	of	Cursor	Property	for	Node
2.1.8	Use	Convenience	Methods	to	Register	Event	Handlers	to	Handle
Mouse	Events
2.1.9	Complete	Source	Codes	of	createNextButton()	Method
2.1.10	Install	Tooltip	for	Node
2.2	Adjust	Next	Button’s	Default	Position	in	StackPane
2.3	Add	Previous	Button	and	Adjust	Its	Position	in	StackPane
2.4	Implement	On	Mouse	Clicked	Event	Handlers
2.4.1	Configure	FileChooser
2.4.2	Create	List	Iterator	to	Iterate	Existing	Files	in	the	Current
Directory
2.4.3	Define	Properties	in	ImageViewer	Class
2.5	Complete	Source	Codes	of	Image	Viewer	V1.1
2.5.1	Complete	Source	Codes	of	FileUtils	Class
2.5.2	Complete	Source	Codes	of	ImageViewer	Class
2.6	Summary
Chapter	3:	Enhanced	Image	Viewer	with	Slide	Show	Capacity
3.1	Add	Status	Bar	at	the	Bottom	of	BorderPane
3.1.1	Create	HBox	Pane	as	Status	Bar	and	Text	Node	to	Show	Image
Name
3.1.2	Set	Value	of	imageName	Property
3.2	Improve	Button’s	Reaction	Aspect
3.2.1	Disable	Button	to	Indicate	No	More	Image	to	Open
3.2.2	Change	Button	Appearance	When	Mouse	Is	Pressed
3.3	Add	Slide	Show	Capabilities
3.3.1	Add	Start	Slideshow	and	Stop	Slideshow	Menu	Items
3.3.1.2	Bind	Disable	Property	of	Menu	Item
3.3.2	Execute	Slide	Show	on	Another	Thread
3.3.2.1	Create	SlideshowService	Class	that	Extends	Service
Class
3.3.2.2	Configure	Slide	Show	Service	Object
3.3.2.3	Implement	Event	Handlers	of	Action	Events	for	Start
Slideshow	and	Stop	Slideshow	Menu	Items
3.3.3	The	Complete	start(Stage	stage)	Method	of	ImageViewer
Application
3.3.4	Coordinate	with	Event	Handlers	of	Load	Menu	Item	and
Previous	Button
3.4	Add	Fade	Transition	between	Slides
3.4.1	Complete	Source	Codes	of	SlideshowService	Class
3.5	Complete	Source	Codes	of	Image	Viewer	V1.2
3.6	Summary
EPILOGUE
ABOUT	THE	AUTHORS
Shufen	Kuo
Shufen	Kuo	relocated	to	San	Francisco	Bay	Area	in	summer	of	1988,	and	has	been	a
software	engineer	ever	since.	She	has	extensive	hands-on	experience	with	various
platforms,	from	PC	DOS	to	numerous	Unix/Linux	workstations,	and	from	PC	Linux	to	PC
Windows.
She	started	writing	Java	programs	in	2001.	She	has	been	using	Abstract	Windowing
Toolkit	(AWT)	and	Swing,	the	GUI	Components	of	Java	Foundation	Classes	(JFC),	to
develop	GUIs	for	her	Java	projects	for	years.	And	since	2012,	she	has	immersed	herself	in
JavaFX;	exploring	its	essence	inspires	her	to	write	books	publicizing	the	strength	of
JavaFX.
Before	developing	Java	applications,	she	had	more	than	12	years	experience	in	the
development	of	C/C++	applications	on	UNIX/Linux/Solaris	running	X	Window	system.
Shufen	Kuo	got	her	M.S.	in	Computer	Science	from	Washington	State	University	in	1987.
Currently,	she	is	developing	Java	applications	with	rich	GUIs	using	JavaFX,	as	well	as
writing	tutorials	about	coding	in	JavaFX,	utilizing	her	expertise	on	designing	and
developing	object	oriented	graphics	tools.
Her	publications	include:
“A	Two-Step	String	Matching	Procedure,”	Pattern	Recognition,	24(7),	711-716,
1991.
“An	Improved	Algorithm	to	Find	the	Length	of	the	Longest	Common	Subsequence
of	Two	Strings,”	ACM	SIGIR	Forum,	Spring/Summer	1989,	Volume	23,	Numbers	3-
4,	89-99
Bing-Chao	Huang
Dr.	Bing-Chao	Huang	received	his	Ph.D.	in	Computer	Science	from	Washington	State
University	in	1987.	He	completed	an	M.S.	degree	in	Computer	Science	from	Stanford
University	in	1984.
His	publications	include:
Algorithm	I	in	D.E.	Knuth*s	book	“The	Art	of	Computer	Programming,”	Volume	1
Fundamental	Algorithms,	Third	Edition	(1997),	176-177
“Fast	Stable	Merging	and	Sorting	in	Constant	Extra	Space,”	The	Computer	Journal
35(1992),	643-650
“Stable	Set	and	Multiset	Operations	in	Optimal	Time	and	Space,”	Information
Processing	Letters	16(1991),	131-136
“Stable	Duplicate-Key	Extraction	with	Optimal	Time	and	Space	Bounds,”	Acta
Informatica	26(1989),	473-484
“Practical	In-Place	Merging,”	CACM	31(1988),	348-352
“Stable	Set	and	Multiset	Operations	in	Optimal	Time	and	Space,”	Seventh	ACM
SIGACT-SIGMOD-SIGART	Symposium	on	Principles	of	Database	Systems	(1988)
“Practical	In-Place	Merging,”	ACM-IEEE/CS	Fall	Joint	Computer	Conference
(1987)
“A	One-Way,	Stackless	Quicksort	Algorithm,”	BIT	26(1986),	127-130,	with	D.E.
Knuth
“An	Algorithm	for	Inverting	A	Permutation,”	Information	Processing	Letters
12(1981),	237-238
Special	thanks	to:	
Dr.	Tan	and	his	family,	
my	brother-in-law	Dr.	Jacob	Chung,	
my	sister	Dr.	Shuching	Chung,	
my	two	cats	Mimi	&	Maomao.
—Shufen	Kuo
ACKNOWLEDGMENT
PREFACE
How	this	book	is	organized
This	book	is	VOLUME	Ⅰ	of	the	book	series,	Coding	in	JavaFX	Step	by	Step	Build
Graphics	Toolkit.	Since	contents	are	abundant	and	unfeasible	to	be	managed	into	one
book,	chapters	are	organized	among	volumes:
1.	 VOLUME	Ⅰ:	DEVELOPING	IMAGE	VIEWING	COMPONENTS
Chapter	1:	Basic	Image	Viewer
Chapter	2:	Enhanced	Image	Viewer	with	Browsing	Buttons
Chapter	3:	Enhanced	Image	Viewer	with	Slide	Show	Capacity
2.	 VOLUME	Ⅱ:	DEVELOPING	INTERACTIVE	SHAPE	DRAWING	TOOLS
Chapter	1:	Line	Drawer
Draw	lines	from	mouse	events	on	a	drawing	board.
Chapter	2:	Polyline	Drawer
Draw	polylines	from	mouse	events	on	a	drawing	board.
Chapter	3:	Polygon	Drawer
Draw	polygons	from	mouse	events	on	a	drawing	board.
Chapter	4:	Path	Drawer
Draw	paths	from	mouse	events	on	a	drawing	board.
Chapter	5:	Quadratic	Bézier	Curve	Drawer
Draw	paths	composed	of	quadratic	Bézier	curves	from	mouse	events	on	a
drawing	board.Chapter	6:	Basic	Draw	Tool
Create	integral	classes	in	a	package	named	drawtool	to	facilitate
developments	of	various	shape	drawers	—	Rectangle	Drawer,	Circle	Drawer
and	Ellipse	Drawer.
Chapter	7:	Enhanced	Draw	Tool	with	Predefined	Drawers
Enhance	drawtool	package	and	implement	a	variety	of	drawers,	reside	in
drawtool.drawer	package,	containing	these	predefined	shape	drawers	—
LineDrawer,	PolylineDrawer,	PolygonDrawer,	PathDrawer,
BazierCurveDrawer,	RectangleDrawer,	CircleDrawer,	EllipseDrawer,	and
ShapeMover	—	which	are	subclasses	of	ShapeDrawer.
Chapter	8:	Initial	JFXDrawTools	Application
Develop	initial	version	of	JFXDrawTools	by	integrating	with	all	predefined
shape	drawers	as	well	as	utilizing	enhanced	shape	drawing	APIs.
3.	 VOLUME	Ⅲ:	DEVELOPING	INTERACTIVE	REGULAR	POLYGON	DRAWING
TOOLS
Chapter	1:	Enhanced	Draw	Tool	with	Regular	Polygon	Shape	Capacity
Introduce	RegularPolygon	class,	derived	from	Shape	class	and	resides	in
drawtool.shape	package.
Chapter	2:	Enhanced	Draw	Tool	with	Regular	Polygon	Drawer	Capacity
Implement	RegularPolygonDrawer,	a	direct	subclass	of	ShapeDrawer,
resides	in	drawtool.drawer	package,	to	draw	N-sided	regular	polygons
from	mouse	events	on	a	drawing	board,	featuring	usages	of
RegularPolygon	shape.
Chapter	3:	Enhanced	JFXDrawTools	with	Regular	Polygon	Drawer
Capacity
Integrate	N-sided	regular	polygon	drawer	into	JFXDrawTools	application.
4.	 VOLUME	Ⅳ:	DEVELOPING	SKETCH	SAVING	AND	LOADING	APIS
Chapter	1:	Enhanced	Draw	Tool	with	Draw	Writer	Capacity
Introduce	DrawWriter	class,	resides	in	drawtool.io	package,	to	save
sketches	that	are	interactively	drawn	on	a	drawing	board,	a	Pane	object,	to
files	in	JavaFXML	format.	A	sketch	can	be	either	a	Shape	object	or	an
ImageView	object.	Besides	JavaFXML	format,	it	also	provides	API	to	save
the	image	of	an	ImageView	object	to	an	image	file.
Chapter	2:	Enhanced	Draw	Tool	with	Draw	Loader	Capacity
Introduce	DrawLoader	class,	which	resides	in	drawtool.io	package,	to
load	FXML	files	as	well	as	image	files	to	a	drawing	board.
Chapter	3:	Enhanced	JFXDrawTools	with	Draw	Writer	and	Draw
Loader	Capacities
Integrate	sketch	saving	and	loading	capabilities	into	JFXDrawTools
application.
5.	 AND	THE	OTHERS…
A	useful	Summary	section	is	available	at	the	end	of	each	chapter;	it	lists	all	the	key
aspects	of	JavaFX	library	featured	in	the	chapter.	It	helps	you	to	look	up	fundamental
capabilities	of	JavaFX	engaged	in	this	book	series.	Here	are	some	of	essentials	among
others:
Shape	class	in	javafx.scene.shape	package	for	2D	geometric	primitives.
FXML,	a	markup	language	which	complies	with	the	XML	(Extensible	Markup
Language)	format,	to	build	GUIs.
Properties	and	binding	mechanism.
Image	class	and	ImageView	class	to	load	and	display	images.
Concurrency	capacity	in	javafx.concurrent	package.
FadeTransition	and	ParallelTransition	applied	onto	image	objects	in	a	slide
show	function.
Build-in	layout	panes	in	javafx.scene.layout	package.
And	more…
Reusable	Classes	with	Applications	and	Complete	Source	Codes
Complete	source	codes	of	a	set	of	packages	with	reusable	classes	as	well	as	embeddable
JavaFX	applications	are	included	in	the	book	series.
The	following	tables	list	all	the	source	codes	offered	in	the	prior	four	volumes	of	the	book
series:
Drawing	Tools
Package	Name Source	Code	File	Name
drawtool ShapeDrawer.javaDrawPane.java
drawtool.drawer
BezierCurveDrawer.java
CircleDrawer.java
EllipseDrawer.java
LineDrawer.java	
PathDrawer.java
PolygonDrawer.java
PolylineDrawer.java
RectangleDrawer.java	
RegularPolygonDrawer.java
RubberBander.java
ShapeMover.java
drawtool.shape RegularPolygon.java
drawtool.io
DrawClipper.java
DrawLoader.java
DrawWriter.java
Graphics	Applications
Package	Name Source	Code	File	Name
imageviewer
FileUtils.java
ImageViewer.java
SlideshowService.java
jfxdrawtools JFXDrawTools.java
Contents	of	VOLUME	Ⅰ
Let’s	glance	at	the	contents	of	VOLUME	Ⅰ:
Chapter	1:	Basic	Image	Viewer
1.1	Create	ImageViewer	Class	as	Subclass	of	Application
1.2	Create	Menu	Bar
1.3	Create	Option	Menu	and	View	Submenu
1.4	Implement	Fit	Width,	Fit	Height	and	Original	Size	Viewing	Options
1.5	Summary
Chapter	2:	Enhanced	Image	Viewer	with	Browsing	Buttons
2.1	Add	Next	Button
2.2	Adjust	Next	Button’s	Default	Position	in	StackPane
2.3	Add	Previous	Button	and	Adjust	Its	Position	in	StackPane
2.4	Implement	On	Mouse	Clicked	Event	Handlers
2.5	Complete	Source	Codes	of	Image	Viewer	V1.1
2.6	Summary
Chapter	3:	Enhanced	Image	Viewer	with	Slide	Show	Capacity
3.1	Add	Status	Bar	at	the	Bottom	of	BorderPane
3.2	Improve	Button’s	Reaction	Aspect
3.3	Add	Slide	Show	Capabilities
3.4	Add	Fade	Transition	between	Slides
3.5	Complete	Source	Codes	of	Image	Viewer	V1.2
3.6	Summary
Figure	1.	Snapshot	of	The	Image	Viewer	in	JavaFX	8.
Why	Choose	This	Book
This	book	is	for	software	developers	who	are	interested	in	developing	GUIs	using	JavaFX
library	for	rich	client	applications.
Important	features	in	JavaFX	are	illustrated	by	step-by-step	development	of	real	world
Java	applications.
Instructive	diagrams	are	used	to	help	readers	capture	abstract	concepts	instantly.	And	all
diagrams	used	in	each	chapter	are	created	using	the	graphics	tools	developed	in	this	book
series.
This	book	is	for	you	if	you	are:
A	Java	GUI	programmer,	novice	or	professional,	who	is	new	to	JavaFX.
A	Java	programmer	who	has	preliminary	knowledge	of	JavaFX	and	would	like	to
learn	how	to	develop	interactive	sketch	drawing	tools.
A	professional	software	engineer	who	is	interested	in	the	development	of	object
oriented	JavaFX	graphics	tools	and	practical	applications,	along	with	complete	and
well-documented	source	codes.
What	You	Need	for	This	Book
If	you	want	to	compile	and	run	applications	included	in	this	book,	you	need	to	download
and	install	JDK.	Here’s	the	website	to	download	JDK	8,
http://www.oracle.com/technetwork/java/javase/downloads/index.html.
To	copy	the	complete	source	codes	from	this	kindle	e-Book,	Here’s	a	suggestion:
1.	 Install	Calibre,	a	free	and	open	source	E	book	Management	software,	to	your	PC.
2.	 Use	Add	books	function	in	Calibre	to	add	the	.mobi	file	of	the	e-Book	to	Calibre
library.
3.	 Open	the	book	from	Calibre	and	copy	the	source	codes	to	Java	files.
INTRODUCTION
This	book	series	is	a	tutorial	for	software	developers	to	build	GUIs	of	Java	applications
using	JavaFX	8	which	has	become	a	part	of	Java™	SE	Development	Kit	8	(JDK	8).
The	primary	objective	of	this	book	series	is	to	provide	a	comprehensive	handbook,	which
brings	forward	the	frequently	used	features	and	the	essence	of	JavaFX.	The	usages	of
APIs	provided	in	JavaFX	packages	are	illustrated	through	the	step-by-step	development	of
a	sophisticated	graphics	toolkit.
Complete	source	codes	of	the	graphics	toolkit,	a	set	of	packages	with	reusable	classes	as
well	as	embeddable	JavaFX	applications,	are	included	in	the	book	series.	Download	and
install	JDK	8	before	you	compile	and	run	these	applications.	Here’s	the	website	to
download	the	latest	version	of	JDK,
http://www.oracle.com/technetwork/java/javase/downloads/index.html.
JavaFX	History
Now	let	us	glance	through	the	timeline	of	JavaFX	evolving	history	and	obtain	glimpses	of
the	predecessor	of	JavaFX:
Chris	Oliver	of	SeeBeyond	Technology	Corporation	developed	a	script	language	called
F3,	the	acronym	for	Form	Follows	Function;	it	allows	developers	accessing	Swing	classes
and	creating	graphics	user	interfaces	(GUIs)	for	rapid	development	of	rich	internet
applications.
Sun	Microsystems	acquired	SeeBeyond	in	September	2005,	F3	renamed	to	JavaFX	Script
in	May	2007.
In	December	2008,	JavaFX	1.0	released,	developers	had	relied	on	JavaFX	Script	to
develop	JavaFX	applications	until	three	years	later	when	JavaFX	2.0	released.
In	January	2010,	Oracle	completed	the	acquisition	of	Sun	Microsystems,	and	continuedmaintaining	JavaFX.
In	September	2010	JavaOne	conference,	Oracle	announced	JavaFX	Script	would	be
discontinued.
In	October	2011,	JavaFX	2.0	released,	developers	began	to	engage	in	standard	Java
language,	instead	of	JavaFX	Script,	to	access	APIs	of	JavaFX	library.	However,	JavaFX
SDK	and	JavaFX	Runtime,	in	addition	to	Java	SE	JDK	and	JRE,	must	be	installed	for
developing	and	executing	applications	compiled	with	JavaFX	2.0.
In	February	2013,	JavaFX	2.2.7	released,	JavaFX	SDK	and	JavaFX	Runtime	are	included
within	JDK/JRE	7.	The	integration	of	JavaFX	and	JDK	results	in	great	conveniency	for
JavaFX	developers.	No	additional	installations	are	needed	for	JavaFX	applications
compiled	with	JDK	7	and	later	releases.
On	March	18,	2014,	JavaFX	8	released	as	part	of	Java™	SE	Development	Kit	8	(JDK	8),
a	major	feature	release.
As	of	the	publishing	of	this	book	on	March,	2016,	the	latest	JDK	releases	are:
JDK	8u66	on	October	20,	2015,	and	JDK	8u72	on	January	2016.
The	schedule	of	general	availability	(GA)	for	JDK	9	is	March	23rd,	2017.
Prerequisite
JavaFX	applications	presented	in	this	book	using	APIs	provided	in	JavaFX	packages	to
build	GUIs.	Knowledge	of	Swing	packages	is	not	a	must,	however,	readers	must	be
familiar	with	the	basics	of	Java	programming	language.	If	you	are	new	to	Java,	visit	this
website,	
http://docs.oracle.com/javase/tutorial/index.html,	to	obtain	preliminary	knowledge	of	Java
technologies.	Read	Oracle	Java	online	documentation	in	this	order:
1.	 Getting	Started	with	Simple	Java	Application	“Hello	World!”	and	Installations:	
Visit	http://docs.oracle.com/javase/tutorial/getStarted/index.html
2.	 Concepts	and	features	of	the	Java	Programming	Language:	
Visit	http://docs.oracle.com/javase/tutorial/java/index.html
3.	 Java	Collections	Framework:	
Visit	http://docs.oracle.com/javase/tutorial/collections/index.html
4.	 Essential	Java	Classes:	
Visit	http://docs.oracle.com/javase/tutorial/essential/index.html
A	Glimpse	of	JavaFX	Applications
The	following	example	is	for	readers	who	are	new	to	JavaFX	to	have	a	quick	preview	of
how	to	create	a	JavaFX	application.
To	get	started,	you	create	a	class	that	extends	javafx.application.Application,	the
entry	point	of	JavaFX	applications,	and	override	the	start	method	that	is	abstract	must	be
overridden.	Here’s	what	a	typical	start	method	looks	like:
package	imageviewer;
import	javafx.application.Application;
import	javafx.scene.Scene;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*
	*	@author	Shufen	Kuo
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				StackPane	imageArea	=	new	StackPane();
				rootPane.getChildren().add(imageArea);
				Scene	scene	=	new	Scene(rootPane,	600,	400);	
				stage.setTitle("ImageViewer	V1.0");
				stage.setScene(scene);
				stage.show();
		}
		public	static	void	main(String[]	args)	{
				launch(args);
		}
}
Scene	and	Stage
There	are	two	important	classes,	Scene	and	Stage,	appears	within	the	start	method.	In
general,	the	main	task	is	to	create	graphical	user	interfaces	(GUIs)	managed	in	hierarchical
tree	structure	called	a	scene	graph,	associate	the	root	node	of	the	scene	graph	to	a	Scene
object,	then	place	the	scene	on	a	Stage	object	which	stands	for	the	top-level	container	of
the	FavaFX	application,	acting	as	the	window	of	the	scene	graph	to	interact	with
application	users.
Following	snapshot	gives	you	an	initial	idea	of	how	the	GUIs	of	a	JavaFX	application	we
are	going	to	build	looks	like:
Figure	1.	Snapshot	of	a	JavaFX	application.
Nodes
JavaFX	introduces	a	basic	class,	javafx.scene.Node	which	extends
java.lang.Object	and	provides	common	properties	and	methods	useful	to	all	available
user	interfaces.	Very	often	we	are	using	the	term	nodes	to	reference	GUIs.
A	scene	graph	may	contain	nodes	of	sorts.	A	node	is	either	a	parent	(a	node	with	children)
or	a	leaf	(a	node	without	children);	each	node	can	have	only	one	parent,	and	the	root	node
has	no	parent.	All	nodes	in	a	scene	graph	are	derived	from	javafx.scene.Node	class.
For	quickly	catch	the	essential	about	the	types	of	nodes	in	a	scene	graph,	we’ll
differentiate	them	by	the	ability	to	add	children	or	not.
You	may	add	children	to	these	nodes:
The	following	classes	are	frequently	employed	as	parent	nodes:	Group,	Pane,
and	build-in	layout	panes	(they	are	direct	subclasses	of	Pane).	Typically,	you	call
the	getChildren()	method	to	obtain	a	list	of	type	ObservableList<Node>	(it
is	a	subinterface	of	java.util.List),	then	you	use	the	basic	utilities,	defined	in
Collection	interface,	which	java	developers	are	familiar	with,	to	manipulate	the
content	of	the	list.
You	may	not	add	children	to	these	nodes:
The	following	classes	are	always	employed	as	leaf	nodes:	Canvas,	ImageView,
MediaView,	and	all	direct	subclasses	of	Shape	such	as	Rectangle,	Circle,
Ellipse,	etc.
JavaFX	and	Swing
Now,	here	is	an	intriguing	issue.	For	years	Java	developers	have	been	building	GUIs	of
Java	applications	using	Swing	APIs,	the	GUI	Components	of	Java	Foundation	Classes
(JFC),	why	do	we	need	JavaFX	in	addition	to	Swing?
If	you	possess	multitudes	of	legacy	codes	written	in	Swing	and	would	like	to	incorporate
JavaFX	features	into	Swing	codes,	JDK	8	provides	mechanism	to	do	so,	and	vice	versa,
you	can	include	Swing	components	in	JavaFX	applications.
The	topic	of	JavaFX-Swing	Interoperability	is	not	covered	in	this	book.	If	you	are
interested	in	this	topic,	visit	Oracle	Online	Documentation	“JavaFX:	Interoperability	—
JavaFX-Swing	Interoperability”	at	here:	
http://docs.oracle.com/javase/8/javafx/interoperability-tutorial/fx_swing.htm
JavaFX	is	the	next	generation	of	Java	GUIs.	To	account	for	the	benefits	of	employing
JavaFX	capabilities,	besides	the	Interoperability	between	JavaFX	and	Swing,	we	present
the	significant	features	of	JavaFX	in	the	section	below.
Essence	of	JavaFX
JavaFX	not	only	allows	you	to	create	applications	with	visual	user	interfaces	rapidly,	but
also	contains	enticing	and	distinctive	abilities.	They	are	enumerated	as	follows:
Build-in	Layout	Panes
JavaFX’s	layout	panes	are	containers	that	automatically	perform	various	types	of
placement	on	nodes.	You	can	place	any	number	of	nodes	in	a	layout	pane,	which	is	a	node
itself	and	thus	can	be	nested	in	another	layout	pane	as	well.	The	major	advantage	of	using
layout	panes	is	to	avoid	the	tediousness	of	manually	specifying	size	and	location	of	each
node.	As	these	nodes	in	a	scene	graph	are	managed	in	a	tree	structure,	the	layout	algorithm
recursively	computes	size	and	location	of	each	node	based	on	its	layout	type	and	specified
layout	properties,	and	the	re-calculation	is	set	off	dynamically	as	the	window’s	resize
event	happens.
There	are	8	types	of	built-in	layout	panes,	located	in	javafx.scene.layout	package:
BorderPane
A	BorderPane	places	nodes	in	five	locations	respectively	to	create	a	classic	look-
and-feel	of	main	windows,	typically	the	top	region	for	a	menu	bar	or	a	tool	bar,	the
bottom	region	for	a	status	bar,	left	and	right	regions	for	navigation	panels,	and	the
center	region	for	a	working	area.
HBox
An	HBox	places	nodes	in	one	row	(horizontally).
VBox
A	VBox	places	nodes	in	one	column	(vertically).
GridPane
A	GridPane	places	nodes	in	a	grid	with	multiple	rows	and	columns.	This	is	a
handy	user	interface	for	displaying	a	series	of	name-value	pair	properties.
StackPane
A	StackPane	places	all	nodes	in	a	stack	with	center	as	default	alignment.	All
children	overlap	each	other	in	the	center	of	the	container,	with	the	later	created
node	placed	on	the	top	of	previous	ones.	But	you	can	use	static	methods,
StackPane.setAlignment(Node	child,	Pos	value)	and
StackPane.setMargin(Node	child,	Insets	value),	toadjust	the	mandatory
position	of	each	node.
FlowPane
You	can	specify	orientation	property	of	a	FlowPane.	For	a	horizontal	FlowPane,
nodes	are	placed	in	rows,	from	left	to	right,	wrapping	at	the	boundary	of	its
container’s	width.	For	a	vertical	FlowPane,	nodes	are	placed	in	columns,	from	top
to	bottom,	wrapping	at	the	boundary	of	its	container’s	height.
TilePane
A	TilePane	is	similar	to	a	FlowPane	except	each	cell	in	the	grid	of	a	TilePane
has	the	same	size.
AnchorPane
An	AnchorPane	places	nodes	relative	to	their	specified	anchor	points,	there	are
four	of	them:	topAnchor,	rightAnchor,	bottomAnchor	and	leftAnchor.
Reference	to	Oracle	Online	Documentation	“Working	with	Layouts	in	JavaFX”:	
http://docs.oracle.com/javase/8/javafx/layout-tutorial/index.html
Customization	using	CSS
JavaFX	allows	the	usage	of	CSS	(Cascading	Style	Sheet)	to	describe	the	presentation
styles	of	application’s	user	interfaces.	Defining	the	presentation	attributes—such	as	color,
font,	margins,	padding,	width,	height,	lines,	background	images,	etc.,	using	CSS,
separated	from	application	codes,	reveals	significant	conveniency	in	many	ways:
Customization	from	software	provider’s	side:
Applications	compiled	from	the	same	set	of	codes	can	bear	a	variety	of
presentation	styles,	each	of	them	complying	with	different	customer’s
requirements.
Customization	from	application	user’s	side:
Even	after	the	software	has	been	released,	in	case	application	users	have
preferences	for	the	look	of	UIs,	it	is	also	applicable	to	modify	the	presentation
attributes,	defined	in	CSS	files,	at	customer	site.
Benefits	for	designers	of	presentation	styles:
The	separation	of	application	codes	from	definitions	of	presentation	styles
improves	readability	of	codes	and	simplifies	the	tasks	for	graphics	designers	by
focusing	on	dealing	with	CSS	only.
Benefits	for	software	developers:
During	the	course	of	testing,	developers	may	frequently	change	style	attributes
defined	in	CSS	file	in	order	to	evaluate	the	variety	looks	of	GUIs.	If	the	application
has	to	quit	and	restart	again	for	each	change,	it	is	a	very	tiresome	task.	To	facilitate
this	evaluation	process,	the	best	strategy	is	to	design	a	makeshift	Load	button,	and
whenever	any	style	attribute	is	changed,	simply	click	on	the	button	to	re-load	the
CSS,	there	is	no	need	to	quit	the	application	and	restart	it,	thus	saving	tremendous
time	spending	on	testing.
Similarity	between	CSS	in	JavaFX	and	CSS	in	HTML:
The	syntax	of	CSS	in	JavaFX	is	same	as	that	of	CSS	in	HTML,	thus	any	designer
has	experience	on	CSS	for	browsers	can	do	the	styling	for	JavaFX	application’s
UIs	with	little	learning	effort.
Reference	to	Oracle	Online	Documentation	“Skinning	JavaFX	Applications	with	CSS”:
http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/css_tutorial.htm
Creating	User	Interfaces	using	FXML
FXML	is	a	markup	language	which	complies	with	the	XML	(Extensible	Markup
Language)	format,	with	additional	rules,	for	creating	user	interfaces	of	JavaFX
applications.	Considering	hand	coding	FXML	is	error	prone,	a	feasible	approach	is	to
generate	FXML	codes	by	means	of	GUI	builders.
In	this	book	series,	we	present	a	useful	application	JFXDrawTools,	it’s	sort	of	a	GUI
builder	specifically	for	creating	instances	of	subclasses	derived	from	Shape.	Users	can
interactively	create	a	sketch,	either	a	Shape	or	an	ImageView,	manipulate	its
properties	and	save	the	editing	results	to	files	in	FXML	format,	the	files	can	later	be
loaded	back	to	continue	the	editing	process,	or	be	loaded	by	other	JavaFX	applications
dynamically.
It	is	considered	a	good	programming	practice	to	separate	application’s	GUIs	(the	View)
from	its	business	logic	(the	Model).	The	FXML	file	represents	the	view,	while	controller	is
a	java	class	which	passes	information	between	view	and	model.	Constructing	GUIs	using
FXML	enables	application	developers	to	adopt	the	MVC	(Model-View-Controller)
architecture	effectively.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Mastering	FXML”:
http://docs.oracle.com/javase/8/javafx/fxml-tutorial/index.html
Appealing	Capacities	of	Properties	and	Binding
The	concept	of	Properties	featured	in	JavaFX	follows	the	design	conventions	introduced
in	the	JavaBeans	component,	it	usually	works	in	connection	with	Binding	mechanism,	as	a
whole	providing	powerful	yet	sleek	and	succinct	solutions	to	a	variety	of	programming
needs.
In	the	JFXDrawTools	application	presented	in	this	book	series,	we	demonstrate	the
usage	of	Properties	and	Binding	considerably.	In	the	implementation	of	Properties
Window,	suitable	UI	controls,	such	as	text	field,	choice	box,	combo	box,	etc.,	are	used	for
viewing	the	properties	of	a	concerned	object.	Binding	mechanism	is	employed	to	bi-
directionally	link	the	UI	controls	to	their	respective	properties	of	the	object,	the
relationship	is	set	up	as	the	Properties	Window	is	about	to	show.	When	users	changed	data
displayed	in	UI	controls,	the	changes	instantly	reflect	to	the	corresponding	properties	of
the	related	object.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Properties	and	Binding	Tutorial”:	
http://docs.oracle.com/javase/8/javafx/properties-binding-tutorial/index.html
Sophisticated	Mechanism	of	Transformations	and	Transitions
The	JavaFX	build-in	capacity	of	transformations	for	nodes	are	so	convenient	for
developing	graphics	packages	such	as	graphics	editors,	drawing	tools,	image	viewing
applications,	GUI	builders,	etc.
Here	are	the	classes	that	have	dealings	with	transformations:	Translate,	Rotate,	Scale
and	Shear.	They	are	all	derived	from	Transform	class	and	located	in
javafx.scene.transform	package.
The	JavaFX	transitions	provide	concise	approaches	for	creating	animations.	There	are	a
host	of	applications	in	need	of	animation	features,	here	are	some	cases:	to	draw	attention
in	an	alert	situation,	to	throw	objects	into	recycle	bin	during	the	removing	operation,	to
indicate	intermediate	state	during	a	data	loading,…
In	the	ImageViewer	application	presented	in	this	book	series,	we	apply
FadeTransition	and	ParallelTransition	onto	image	objects	in	a	slideshow	function	to
fade	in	the	new	image	and	fade	out	the	old	image	simultaneously.
Here	are	the	classes	that	have	dealings	with	transitions:	FadeTransition,
RotateTransition,	ScaleTransition,	TranslateTransition,	FillTransition,
StrokeTransition,	PathTransition,	ParallelTransition,	SequentialTransition,
PauseTransition.	They	are	all	derived	from	Transition	class,	an	abstract	class	defines
basic	functionality	of	animations,	and	located	in	javafx.animation	package.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Transformations,	Animations,	and	Visual	Effects”:	
http://docs.oracle.com/javase/8/javafx/visual-effects-tutorial/index.html
2D	Geometric	Primitives	and	Text	Are	JavaFX	Nodes
JavaFX	provides	a	Shape	class	which	extends	javafx.scene.Node	class	and	is	the
superclass	of	basic	forms	of	2D	geometry.	The	object-oriented	concept	imposed	on	the
geometric	primitives	facilitates	the	development	of	graphics	applications.
Here	are	classes	derived	from	Shape	class:	Arc,	Circle,	CubicCurve,	Ellipse,	Line,
Path,	Polygon,	Polyline,	QuadCurve,	Rectangle,	SVGPath,	Text.	Except	the
Text	class,	all	the	others	are	located	in	javafx.scene.shape	package.
Please	note	that	Text	class,	located	in	javafx.scene.text	package,	considered	a	shape
as	well,	powers	the	development	of	text	drawing	tools.	All	features	common	to	JavaFX
nodes	can	be	applied	to	text	objects.	You	handle	it	just	like	any	geometric	form.	Text
objects	can	be	placed	in	a	layout	pane	to	utilize	the	automatic	placement	abilities,	applying
transformations	and	transitions,	as	well	as	customizing	the	presentation	style	using	CSS,
etc.
Reference	to	Oracle	Online	Documentation	“Using	Text	in	JavaFX”:	
http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/text-settings.htm
Other	Prominent	Capabilities	That	Carry	OutMany	Complex	Issues	to
Shorten	Development	Time
ImageView	Class	for	Loading	and	Displaying	Images
The	ImageView	class	which	extends	javafx.scene.Node	is	used	along	with
Image	class	to	load	and	display	images.	JavaFX	also	provides	APIs	for
performing	operations	over	bitmap	images,	PixelReader	is	the	interface	defines
methods	to	read	pixels	from	an	Image	object,	while	PixelWriter	defines
methods	to	write	pixels	to	an	Image	object.	All	of	these	are	located	in
javafx.scene.image	package.
Reference	to	Oracle	Online	Documentation	“Using	the	Image	Ops	API”:	
http://docs.oracle.com/javase/8/javafx/graphics-tutorial/image_ops.htm
WebView	Class	for	Managing	Web	Pages
There	is	a	web	engine	component	embedded	in	JavaFX	architecture	and	providing
a	set	of	APIs,	located	in	javafx.scene.web	package,	for	developing	applications
with	functionality	of	a	web	browser.	To	view	a	web	page,	first	you	create	a
WebView	object	which	extends	javafx.scene.Parent	and	inherits	all	the
features	of	a	node,	then	obtain	the	WebEngine	that	associates	with	it.	The
WebEngine	provides	methods	relevant	to	manipulating	a	web	page,	such	as:
loading/displaying	the	web	page,	either	by	given	a	url	or	content	of	the	page,
accessing	the	Document	Object	Model	(DOM)	created	by	WebEngine	for	the
loaded	web	page,	handling	a	variety	of	events	initiated	from	JavaScript,…etc.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Adding	HTML	Content	to	JavaFX	Applications”:	
http://docs.oracle.com/javase/8/javafx/embedded-browser-tutorial/index.html
HTMLEditor	Class	for	Editing	HTML	Pages
The	full	support	of	HTML	editing	ability	comes	from	HTMLEditor	class,	extends
javafx.scene.control.Control,	resides	in	javafx.scene.web	package.	To
embed	a	HTML	editor	into	your	JavaFX	application,	you	simply	create	an	instance
of	HTMLEditor,	add	it	to	a	scene	graph,	then	it	is	ready	to	interact	with	users.	The
following	two	methods	are	useful	to	get	and	set	the	HTML	content	of	the	editor:
getHtmlText(),	setHtmlText(java.lang.String	htmlText).
Unlike	the	similar	control	TextArea	that	handles	multiple	lines	of	plain	text,	the
HTMLEditor	formats	text	that	complies	with	HTML	syntax.
The	usage	of	the	HTML	editor	are	widely	required	in	various	fields	of	software,
For	example,	bloggers	writing	articles	to	post	(content	management	system),	users
of	an	Email	System	composing	messages	(messaging	system),	online	sellers
preparing	product	descriptions	for	listing	(e-commence	management	system),…etc.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Working	with	JavaFX	UI	Components	—	HTML
Editor”:	
http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/editor.htm
Chart	Components	for	Rendering	Data
The	following	classes	are	located	in	javafx.scene.chart	packages	for	drawing
various	types	of	charts:
AreaChart,	StackedAreaChart
BarChart,	StackedBarChart
BubbleChart
LineChart
PieChart
ScatterChart
Chart	class,	the	base	class	for	all	chart	components,	extends
javafx.scene.layout.Region	class,	and	thus	inherits	all	applicable	features
from	javafx.scene.Node	class.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Working	with	JavaFX	UI	Components	—	Working	with
JavaFX	Charts”:	
http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/charts.htm
MediaView	Class	for	Playing	Media
The	MediaView	class	which	extends	javafx.scene.Node	is	used	along	with
MediaPlayer	and	Media	classes	to	play	media	in	your	JavaFX	applications.	All
media	related	classes	are	resides	in	javafx.scene.media	package.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Incorporating	Media	Assets	Into	JavaFX	Applications”:	
http://docs.oracle.com/javase/8/javafx/media-tutorial/
JavaFX	Fundamental	UI	Components
In	addition	to	the	Essence	of	JavaFx	described	above,	JavaFX	provides	fundamental	UI
components,	reside	in	javafx.scene.control	package,	and	are	derived	from
javafx.scene.control.Control	class;	they	are	called	UI	controls	often.
Here	are	available	UI	controls,	the	ones	that	are	not	marked	with	asterisk	(*)	have	their
resemblant	counterparts	in	Swing:
Label,	Button,	RadioButton,	ToggleButton,
CheckBox,	ChoiceBox,
ComboBox,	ListView,	TableView,
TextField,	TextArea,	PasswordField,	HTMLEditor(*)
ScrollBar,	ScrollPane,	Slider,	ProgressBar,	ProgressIndicator(*),
ToolBar,
MenuBar,	MenuButton,	SplitMenuButton(*),
ColorPicker,	DatePicker(*),	Separator,	Pagination(*),	SplitPane,
TabPane,	TitledPane(*),	Accordion(*),	TreeView,	TreeTableView(*),
Hyperlink(*).
The	following	UI	components	are	usually	described	in	the	same	category	with	the	above
UI	controls.
Tooltip
resides	in	javafx.scene.control	package,	but	is	derived	from
javafx.scene.control.PopupControl	class.
MenuItem,	Menu,	CheckMenuItem,	RadioMenuItem
resides	in	javafx.scene.control	package.	The	MenuItem	which	extends
java.lang.Object	is	the	base	class	of	the	rest	three.
FileChooser
resides	in	javafx.stage	package	and	extends	java.lang.Object.
Reference	to	Oracle	Online	Documentation	“JavaFX:	Working	with	JavaFX	UI	Components”:	
http://docs.oracle.com/javase/8/javafx/user-interface-tutorial/ui_controls.htm
Chapter	1	
Basic	Image	Viewer	
—Developing	Image	Viewer	V1.0
Preface
In	this	chapter,	we’ll	illustrate	usages	of	JavaFX	APIs	by	means	of	step-by-step
development	of	an	image	viewing	application,	ImageViewer	V1.0.	From	detailed
descriptions	and	well-documented	example	codes	excerpted	from	ImageViewer	V1.0x,
you	will	become	familiar	with	fundamental	capabilities	of	JavaFX	library	recounted	in	the
Summary	section.
The	complete	development	process	of	ImageViewer	V1.0	is	characterized	by	the
following	steps:
1.1	Create	ImageViewer	Class	as	Subclass	of	Application
1.1.1	JavaFX	Application	Thread	vs.	Java	Launcher	Thread
1.1.2	Catch	Resize	Event	of	Image	Rendering	Area
1.2	Create	Menu	Bar
1.2.1	Add	File	Menu	to	Menu	Bar
1.2.2	Select	Image	File	from	File	Open	Dialog	and	Display	Image	on
StackPane
1.3	Create	Option	Menu	and	View	Submenu
1.3.1	Create	Toggle	Group,	Radio	Menu	Items	and	Add	Listener	for
selectedToggle	Property
1.4	Implement	Fit	Width,	Fit	Height	and	Original	Size	Viewing	Options
1.4.1	Approach	One:	Bind	ImageView‘s	fitWidth/fitHeight	Properties	to
Scene‘s	width/height	Properties	Respectively
1.4.1.1	Implement	Fit	Width	Viewing	Option
1.4.1.2	Implement	Fit	Height	Viewing	Option
1.4.1.3	Implement	Original	Size	Viewing	Option
1.4.1.4	Complete	Source	Codes	of	ImageViewer	Class
1.4.2	Approach	Two:	Change	Values	for	fitWidth	Property	and	fitHeight
property
1.4.2.1	Catch	Resize	Event	of	Scene	to	Adjust	Viewing	Size	of	Image
1.4.2.2	Complete	Source	Codes	of	ImageViewer	Class
1.5	Summary
1.1	Create	ImageViewer	Class	as	Subclass	of
Application
The	graphical	user	interfaces	of	a	JavaFX	application	are	managed	in	hierarchical	tree
structure,	called	a	scene	graph.	In	ImageViewer	application,	we	employ	a
BorderPane	as	the	root	node	of	a	scene	graph,	and	place	a	StackPane	in	the	center	of
BorderPane	as	image	rendering	area.	Both	BorderPane	and	StackPane	are	among
build-in	layout	panes,	reside	in	javafx.scene.layout	package	and	are	direct	subclasses
of	javafx.scene.layout.Pane	class.
BorderPane	class	allows	you	to	create	graphical	user	interfaces	featuring	classic	look-
and-feel	of	main	windows.	In	the	next	section	you’ll	see	a	menu	bar	added	at	the	top	of
BorderPane,	and	in	the	later	chapter	a	status	bar	added	at	the	bottom.
StackPane	class	lays	out	its	children	in	a	stack,	placing	the	later	created	child	at	the	top
of	previous	one.	In	ImageViewer	application,	since	only	one	image	is	viewed	at	one
time,	the	StackPane	has	only	one	child.	If	the	size	of	an	image	is	smaller	than	the	size	of
StackPane,	the	image	is	placed	in	the	center	of	StackPane.	If	the	size	of	an	image	is
larger	than	that	of	StackPane,	StackPane	is	expanded	automatically	to	accommodate
the	whole	image,	and	if	the	viewing	space	in	the	application	windowis	not	larger	enough,
only	center	portion	of	the	image	is	visible	by	default.	In	later	section,	we’ll	demonstrate
how	to	avoid	a	StackPane	being	resized	by	its	content,	see	here.
A	Scene	object	is	created	as	the	container	of	a	scene	graph,	given	a	root	node	as
parameter.	In	ImageViewer	application,	the	root	node	is	a	BorderPane,	and	initial
width	and	height	of	the	Scene	object	is	set	to	600	pixels	and	400	pixels.	Both
BorderPane	and	StackPane	are	resizable	layout	panes;	therefore,	if	the	application
window	is	dynamically	resized	by	a	user,	the	scene	is	resized	and	a	resize	event	is	passed
on	to	its	root	node,	resulting	in	re-calculation	of	the	size	of	image	rendering	area
accordingly.
You	place	a	scene	on	a	Stage	to	make	it	alive,	using	the	setScene	method	defined	in
Stage	class.	Stage	is	a	direct	subclass	of	javafx.stage.Window;	it	is	the	top-level
window	of	a	JavaFX	application.
JavaFX	system	creates	a	Stage	object,	referred	as	primary	stage,	and	passed	to	the	start
method,	an	abstract	method	defined	in	Application	class.	Developers	can	construct
additional	Stage	objects	as	needed	for	their	applications.
The	following	codes	demonstrate	how	to	create	ImageViewer	class	as	a	direct	subclass
of	Application,	and	override	the	start	method.	Here	are	codes:
Listing	1-1.	Create	ImageViewer	class	which	extends	Application	class,	override
start	method,	create	BorderPane	as	the	root	node	of	a	scene,	and	place	StackPane	in
the	center	of	BorderPane	as	image	rendering	area:
package	imageviewer;
import	javafx.application.Application;
import	javafx.scene.Scene;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*
	*	This	application	creates	a	BorderPane	as	root	node	of	a	scene,	and
	*	add	a	StackPane	in	the	center	of	BorderPane
	*	The	initial	size	of	the	scene	is	set	to	600	by	400
	*	The	size	of	StackPane	will	be	automatically	set	to	fit	the	size	of	scene.
	*	StackPane	will	be	resized	when	window	size	is	adjusted	by	a	user
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				StackPane	imageArea	=	new	StackPane();
				rootPane.setCenter(imageArea);
				Scene	scene	=	new	Scene(rootPane,	600,	400);	
				stage.setTitle("ImageViewer	V1.0");
				stage.setScene(scene);
				stage.show();
		}
		public	static	void	main(String[]	args)	{
				launch(args);
		}
}
1.1.1	JavaFX	Application	Thread	vs.	Java	Launcher	Thread
Application	class	is	the	entry	point	of	a	JavaFX	application.	It	defines	the	following
significant	methods:
public	void	init()	throws	Exception
public	abstract	void	start(Stage	primaryStage)	throws	Exception
public	void	stop()	throws	Exception
The	init	method,	which	does	nothing,	is	called	from	Java	launcher	thread.	While	the
start	method,	an	abstract	and	must	be	overridden,	is	called	from	JavaFX	Application
Thread	after	init	method	has	returned.	If	you	need	do	some	initial	works	before	start
method,	you	can	do	that	by	overriding	init	method;	however	it	is	crucial	to	notice	that
nodes	that	are	members	of	a	live	scene	must	be	accessed	from	JavaFX	Application
Thread.	And	the	construction	of	a	Scene	object	or	a	Stage	object	must	be	accessed
from	JavaFX	Application	Thread	as	well.
1.1.2	Catch	Resize	Event	of	Image	Rendering	Area
For	debugging	and	testing	purpose	at	this	point,	we	register	a	ChangeListener
providing	a	changed	method	to	be	notified	whenever	width	or	height	of	image	rendering
area	is	changed.	Width	or	height	of	image	rendering	area	is	changed	when	a	user	resizes
the	application	window.
To	register	a	ChangeListener	to	observe	change	of	value	for	a	property,	we	use	this
method:
					void	addListener(ChangeListener<?	super	T>	listener)
					
defined	in	javafx.beans.value.ObservableValue	interface,	providing
implementation	of	changed(ObservableValue<?	extends	T>	observable,	T
oldValue,	T	newValue)	method,	to	be	invoked	when	this	property’s	value	is	changed.
The	same	ChangeListener	is	allowed	to	be	registered	to	multiple
ObservableValues.	To	avoid	memory	leak	problem,	it	is	a	good	programming	practice
to	un-register	a	listener	whenever	the	value	no	longer	need	be	observed,	using
removeListener(ChangeListener<?	super	T>	listener)	method,	which	removes
the	link	between	an	observable	value	and	a	listener.
StackPane	class	inherits	width	and	height	properties	from
javafx.scene.layout.Region	class.	Both	properties	are	type	of
ReadOnlyDoubleProperty,	an	abstract	class	that	implements	ObservableValue
interface.	As	the	name	reveals,	an	ObservableValue	holds	a	value	that	are	observable,
you	can	listen	to	the	change	of	value	and	take	actions	as	necessary.
The	following	codes	demonstrate	how	to	watch	the	resize	event	of	image	rendering	area,	a
StackPane	placed	in	the	center	of	a	BorderPane.
Import	Statements:
import	javafx.beans.value.ChangeListener;
import	javafx.beans.value.ObservableValue;
Listing	1-2.	Add	listeners	to	width	property	and	height	property	of	image	rendering	area:
imageArea.widthProperty().addListener(new	ChangeListener<Object>()	{
		public	void	changed(ObservableValue	o,	Object	oldVal,
				Object	newVal)	{
				System.out.format("imageArea	width	changed	from	%.1f	to	%.1f%n",
						oldVal,	newVal);
		}
});
imageArea.heightProperty().addListener(new	ChangeListener<Object>()	{
		public	void	changed(ObservableValue	o,	Object	oldVal,
				Object	newVal)	{
				System.out.format("imageArea	height	changed	from	%.1f	to	%.1f%n",
						oldVal,	newVal);
		}
});
Listing	1-3.	Complete	source	codes	of	ImageViewer	class	become	like	this:
package	imageviewer;
import	javafx.application.Application;
import	javafx.beans.value.ChangeListener;
import	javafx.beans.value.ObservableValue;
import	javafx.scene.Scene;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*	(in	directory:	ImageViewer1.0/src/example1/imageviewer/)
	*	This	application	creates	a	BorderPane	as	root	node	of	a	scene,	and
	*	add	a	StackPane	in	the	center	of	BorderPane
	*	The	initial	size	of	the	scene	is	set	to	600	by	400
	*	The	size	of	StackPane	will	be	automatically	set	to	fit	the	size	of	scene.
	*	StackPane	will	be	resized	when	window	size	is	adjusted	by	a	user
	*
	*	@author	Shufen	Kuo
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				StackPane	imageArea	=	new	StackPane();
				rootPane.setCenter(imageArea);
				Scene	scene	=	new	Scene(rootPane,	600,	400);
				imageArea.widthProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
								Object	newVal)	{
								System.out.format("imageArea	width	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
						}
				});
				imageArea.heightProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
								Object	newVal)	{
								System.out.format("imageArea	height	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
					}
				});
				stage.setTitle("ImageViewer	V1.0");
				stage.setScene(scene);
				stage.show();
		}
		public	static	void	main(String[]	args)	{
				launch(args);
		}
}
Figure	1-1.	Snapshot	of	initial	appearance	of	ImageViewer	V1.0
Compile	and	run	the	application.
Output	from	Compiling	and	Running	ImageViewer	in	command	line:
Microsoft	Windows	[Version	6.3.9600]
(c)	2013	Microsoft	Corporation.	All	rights	reserved.
F:\My	Documents\DocRoot\SHUFEN_JAVA\MyBookJFX\VolumeOne\ImageViewer1.0\src\example1>
javac	-encoding	utf-8	-Xlint:unchecked	imageviewer\*.java
jar	cf	imageviewer.jar	imageviewer
java	-cp	imageviewer.jar	imageviewer.ImageViewer
imageArea	width	changedfrom	0.0	to	600.0
imageArea	height	changed	from	0.0	to	400.0
Now,	change	the	size	of	scene	by	dragging	the	edge	or	corner	of	the	application	window,
you	will	see	output	similar	as	follows:
imageArea	width	changed	from	600.0	to	437.0
imageArea	height	changed	from	400.0	to	263.0
imageArea	width	changed	from	437.0	to	636.0
imageArea	height	changed	from	263.0	to	384.0
imageArea	width	changed	from	636.0	to	587.0
imageArea	height	changed	from	384.0	to	448.0
1.2	Create	Menu	Bar
In	this	section,	we	are	creating	a	MenuBar,	adding	it	at	the	top	of	BorderPane	which	is
the	root	node	of	a	scene	graph.
Generally	a	MenuBar	object	contains	multiple	Menus	laying	out	horizontally,	and	each
Menu	contains	multiple	MenuItems.	Since	Menu	class	extends	MenuItem	class,	you
can	place	a	Menu	within	a	Menu,	the	nested	one	is	called	a	submenu.	As	a	MenuBar	is
rendered	on	a	window,	what	a	user	sees	is	names	of	menus	only,	the	content	of	each	menu
is	hidden	until	the	mouse’s	left	button	clicked	on	a	menu	name,	or	the	mnemonic	key
combination	which	defined	as	shortcut	keys	for	the	menu	is	hit.
The	benefits	for	employing	menu	user	interface	include	the	followings:
Require	less	space
A	menu	only	occupies	the	space	for	its	name	when	it	is	not	in	need	by	a	user.
Organizable	capability
To	facilitate	the	accessibility,	you	organize	menu	items	in	a	tree	structure	according
to	functionality,	grouping	the	menu	items	that	are	alike	in	a	same	menu,	avoiding
overcrowding	one	menu	by	means	of	submenus,	and	placing	the	more	frequently
requested	menu	items	in	upper	levels.	Usually	the	most	important	ones	are	placed
on	the	top	level	of	the	tree.
Invoke	action	by	one	keystroke
You	can	use	mnemonic	mechanism	to	navigate	menus	within	a	MenuBar	and
define	shortcut	keys	to	enable	users	to	invoke	the	action	of	a	MenuItem	by	one
keystroke.	For	example,	press	Alt	and	F	keys	at	the	same	time	to	show	File	menu
and	press	Ctrl	and	S	keys	at	the	same	time	to	perform	save	file	action.
To	add	a	Menu	to	a	MenuBar,	first	we	call	the	getMenus()	method,	which	returns	an
ObservableList	of	Menus.	The	ObservableList	is	a	subinterface	of	java.util.List,
thus	we	can	use	the	add	method,	one	of	the	basic	utilities	defined	in	Java	Collection
interface,	to	append	a	menu	to	the	list.	The	codes	are	as	follows:
Listing	1-4.	Add	a	Menu	to	a	MenuBar:
MenuBar	menuBar	=	new	MenuBar();
Menu	menuFile	=	new	Menu("File");
menuBar.getMenus().add(menuFile);
To	add	a	MenuItem	to	a	Menu,	we	use	getItems()	method,	which	returns	an
ObservableList	of	MenuItems.	The	rest	of	circumstances	are	similar	to	what	we	have
described	above.	The	codes	are	as	follows:
Listing	1-5.	Add	a	MenuItem	to	a	Menu:
MenuItem	load	=	new	MenuItem("Load");
MenuItem	exit	=	new	MenuItem("Exit");
menuFile.getItems().addAll(load,	exit);
1.2.1	Add	File	Menu	to	Menu	Bar
In	this	application	at	this	point,	MenuBar	contains	a	File	menu.	The	File	menu	contains
two	menu	items:	Load	and	Exit.	The	following	snippets	of	codes	show	how	to
accomplish	these	tasks.
Import	Statements:
import	javafx.application.Platform;	
import	javafx.scene.control.Menu;
import	javafx.scene.control.MenuBar;
import	javafx.scene.control.MenuItem;
import	javafx.event.ActionEvent;
import	javafx.event.EventHandler;
Listing	1-6.	Add	a	menu	bar	to	ImageViewer	application,	place	it	at	the	top	of	root
node	which	is	a	BorderPane:
//	Add	menu	bar
MenuBar	menuBar	=	new	MenuBar();
Menu	menuFile	=	new	Menu("File");
MenuItem	load	=	new	MenuItem("Load");
MenuItem	exit	=	new	MenuItem("Exit");
menuFile.getItems().addAll(load,	exit);
menuBar.getMenus().add(menuFile);
rootPane.setTop(menuBar);
//	Add	action	for	exit	menu	item
exit.setOnAction(new	EventHandler<ActionEvent>()	{
		@Override
		public	void	handle(ActionEvent	e)	{
				Platform.exit();
		}
});
1.2.2	Select	Image	File	from	File	Open	Dialog	and	Display	Image	on
StackPane
To	navigate	a	file	system,	we	use	FileChooser	class	which	provides	a	convenient
method,	showOpenDialog(Window	ownerWindow)	for	choosing	a	file	to	open.
The	action	of	Load	menu	item	is	to	browse	a	local	file	system,	select	an	image	file	and
display	the	image	on	image	rendering	area.
The	setOnAction(EventHandler<ActionEvent>	value)	method,	provided	in
MenuItem	class,	is	used	to	add	an	event	handler	to	handle	ActionEvent	of	Load
menu	item.
In	order	to	load	and	display	images,	we	use	ImageView	class	in	association	with
Image	class.	Image	class	loads	an	image	given	a	url	in	type	of	String,	and
ImageView	class	displays	the	image	on	an	image	rendering	area.
First,	we	create	an	ImageView	added	as	a	child	of	a	StackPane.	Later,	when	an	image
file	is	obtained,	we’ll	create	an	Image	object	to	load	the	image	file	and	call	the
setImage(Image	value)	method	provided	in	ImageView	class	to	view	the	image.
The	situation	is	elaborated	as	follows:	When	the	showOpenDialog	method	of	a
FileChooser	is	executed,	a	file	open	dialog	is	popped	up.	When	a	user	selects	a	file	and
clicks	Open	button	in	the	file	open	dialog,	the	showOpenDialog	method	returns	the
selected	file,	type	of	File,	to	caller,	it	is	converted	to	a	url	of	String	representation,	and
an	Image	object	is	created	given	the	url	as	parameter,	at	this	point,	the	image	is	loaded
into	memory,	yet	not	showing	on	screen,	the	selected	image	is	shown	as	soon	as	the
setImage	method	of	an	ImageView	is	executed.	For	the	sake	of	efficiency,	we	create
ImageView	object	only	once,	and	update	its	Image	property	each	time	a	new	image
file	is	selected	and	opened.
The	following	snippets	of	codes	accomplish	these	tasks:
Import	Statements:
import	java.io.File;
import	javafx.scene.image.Image;
import	javafx.scene.image.ImageView;
import	javafx.stage.FileChooser;
Listing	1-7.	Create	FileChooser	Object,	ImageView	Object	and	add	EventHandler
for	Load	menu	Item	to	load	an	image:
//	Create	a	file	chooser
final	FileChooser	fileChooser	=	new	FileChooser();
fileChooser.setTitle("Open	an	Image	File");
//	Create	image	view,	add	to	image	area
final	ImageView	imageView	=	new	ImageView();
imageArea.getChildren().add(imageView);
//	Add	action	for	menu	item	Load
load.setOnAction(new	EventHandler<ActionEvent>()	{
		@Override
		public	void	handle(ActionEvent	e)	{
				//	Open	FileChooser	dialog
				File	file	=	fileChooser.showOpenDialog(stage);
				if	(file	!=	null)	{
						String	url	=	file.toURI().toString();
						Image	image	=	new	Image(url);
						imageView.setImage(image);
				}
		}
});
Please	remember	to	declare	the	variable	stage	as	final	since	it	is	accessed	within	inner
class,	the	anonymous	EventHandler	class	of	Load	menu	item.
Now,	we	need	to	deal	with	a	significant	matter	regarding	the	resizability	of	image
rendering	area,	the	StakePane.	To	avoid	resizing	the	StakePane	when	displaying	an
image	of	larger	size,	we	need	to	set	minimum	size	for	the	StakePane.	Here’s	the	code	to
do	this:
				imageArea.setMinSize(0,	0);
Without	adding	the	above	line	of	code,	the	size	of	StakePane	is	changeable	when
loading	an	image	with	size	larger	than	the	current	size	of	StakePane.	Here’s	an
example:
Suppose	the	current	size	of	StakePane	is	600	by	375;	after	displaying	an	image	of	size
1280	by	960,	the	size	of	StakePane	is	enlarged	to	become	1280	by	960;	however,	the
viewable	portion	is	still	600	by	375.
Setting	minimum	size	for	the	StakePane	results	in	no	size	changing	event	occurred
whenever	a	new	image	is	opened,	and	also	simplify	the	codes	to	be	developed	in	the
following	chapters.
Listing	1-8.	Complete	source	codes	of	ImageViewer	class	become	like	this:
package	imageviewer;
import	java.io.File;
import	javafx.application.Application;
import	javafx.application.Platform;	
import	javafx.beans.value.ChangeListener;
import	javafx.beans.value.ObservableValue;
import	javafx.event.ActionEvent;
import	javafx.event.EventHandler;
import	javafx.scene.Scene;
import	javafx.scene.control.Menu;
import	javafx.scene.control.MenuBar;import	javafx.scene.control.MenuItem;
import	javafx.scene.image.Image;
import	javafx.scene.image.ImageView;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.FileChooser;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*	(in	directory:	ImageViewer1.0/src/example2/imageviewer/)
	*	This	application	creates	a	BorderPane	as	root	node	of	a	scene,	and
	*	add	a	StackPane	in	the	center	of	BorderPane
	*	The	initial	size	of	the	scene	is	set	to	600	by	400
	*	The	size	of	StackPane	will	be	automatically	set	to	fit	the	size	of	scene.
	*	StackPane	will	be	resized	when	window	size	is	adjusted	by	a	user
	*
	*	Add	a	menu	bar	in	the	top	of	BorderPane
	*	Create	File	Menu,	and	using	FileChooser's	Open	Dialog	to
	*	select	an	image	file,	load	and	display	the	image	in	image	rendering	area.
	*
	*	@author	Shufen	Kuo
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(final	Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				StackPane	imageArea	=	new	StackPane();
				//	Set	min	size	for	StackPane	to	avoid	resizing
				//	when	loading	large	size	image
				imageArea.setMinSize(0,	0);
				rootPane.setCenter(imageArea);
				Scene	scene	=	new	Scene(rootPane,	600,	400);
				
				imageArea.widthProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	width	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
						}
				});
				imageArea.heightProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	height	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
						}
				});
				//	Add	menu	bar
				MenuBar	menuBar	=	new	MenuBar();
				Menu	menuFile	=	new	Menu("File");
				MenuItem	load	=	new	MenuItem("Load");
				MenuItem	exit	=	new	MenuItem("Exit");
				menuFile.getItems().addAll(load,	exit);
				menuBar.getMenus().add(menuFile);
				rootPane.setTop(menuBar);
				//	Add	action	for	exit	menu	item
				exit.setOnAction(new	EventHandler<ActionEvent>()	{
						@Override
						public	void	handle(ActionEvent	e)	{
								Platform.exit();
						}
				});
				//	Create	a	file	chooser
				final	FileChooser	fileChooser	=	new	FileChooser();
				fileChooser.setTitle("Open	an	Image	File");
				//	Create	image	view,	add	to	image	area
				final	ImageView	imageView	=	new	ImageView();
				imageArea.getChildren().add(imageView);
				//	Add	action	for	menu	item	Load
				load.setOnAction(new	EventHandler<ActionEvent>()	{
						@Override
						public	void	handle(ActionEvent	e)	{
								//	Open	FileChooser	dialog
								File	file	=	fileChooser.showOpenDialog(stage);
								if	(file	!=	null)	{
										String	url	=	file.toURI().toString();
										Image	image	=	new	Image(url);
										imageView.setImage(image);
								}
						}
				});	
				stage.setTitle("ImageViewer	V1.0");
				stage.setScene(scene);
				stage.show();
		}
		public	static	void	main(String[]	args)	{
				launch(args);
		}
}
Compile	and	run	the	application.	Click	Load	menu	item	in	File	menu,	navigate	to	a
directory	that	contains	image	files,	select	an	image	file,	click	Open	button	in
FileChooser‘s	Open	Dialog,	the	image	file	will	be	loaded	and	displayed	in	the	center	of
application	window.
Figure	1-2.	Snapshot	of	menu	bar	with	File	menu	when	it	is	clicked
Figure	1-3.	Snapshot	of	selecting	an	image	file	from	file	chooser
Figure	1-4.	Snapshot	of	displaying	a	small	size	image	in	the	center
Figure	1-5.	Snapshot	of	displaying	a	large	size	image	in	the	center
1.3	Create	Option	Menu	and	View	Submenu
We	need	an	Option	menu	allowing	a	user	to	choose	preferred	viewing	criteria.	The
Option	Menu	contains	a	View	submenu	which	contains	three	mutually	exclusive
choices,	they	are	as	follows:
Fit	Width
Render	an	image	on	an	area	by	scaling	fitWidth	property	of	an	ImageView,
while	preserving	original	width/height	ratio,	to	fit	the	width	of	current	available
image	viewing	space.
Fit	Height
Render	an	image	on	an	area	by	scaling	fitHeight	property	of	an	ImageView,
while	preserving	original	width/height	ratio,	to	fit	the	height	of	current	available
image	viewing	space.
Original	Size
Render	an	image	in	its	original	size,	the	outer	portion	of	image	that	exceeds	the
boundary	of	current	available	viewing	space	will	be	blocked.	This	is	set	as	the
initial	viewing	option.
Please	note	that	the	available	image	viewing	space	is	determined	by	current	width	and
height	of	the	application	window,	called	a	Stage,	which	subsequently	is	subject	to	the
current	size	of	a	Scene,	the	container	of	a	scene	graph.	Initially	the	scene	is	set	to	600
pixels	by	400	pixels,	thus,	the	size	of	available	image	rendering	space	will	be	same	as	the
size	of	the	scene.	After	we	added	a	menu	bar	at	the	top	of	BorderPane,	which	is	the	root
node	of	the	scene,	the	height	of	available	image	rendering	space	becomes	height	of	scene
minus	height	of	menu	bar,	while	the	width	remains	the	same.
1.3.1	Create	Toggle	Group,	Radio	Menu	Items	and	Add	Listener	for
selectedToggle	Property
To	implement	mutually	exclusive	choices	in	a	menu,	we	create	RadioMenuItem	objects
and	a	single	ToggleGroup	object,	then	associate	each	RadioMenuItem	to	the	same
ToggleGroup.
To	watch	the	change	of	selected	radio	menu	item,	we	use:
					void	addListener(ChangeListener<?	super	T>	listener)
					
to	register	a	ChangeListener	for	selectedToggle	property	of	ToggleGroup	object.
The	following	snippets	of	codes	show	how	to	accomplish	these	tasks.
Import	Statements:
import	javafx.scene.control.RadioMenuItem;
import	javafx.scene.control.Toggle;
import	javafx.scene.control.ToggleGroup;
Listing	1-9.	Create	Option	menu,	ToggleGroup,	RadioMenuItems,	View	submenu
and	add	a	listener	for	selectedToggle	property	of	the	ToggleGroup:
//	Create	Option	menu
Menu	menuOption	=	new	Menu("Option");
//	Create	toggle	group
final	ToggleGroup	groupOption	=	new	ToggleGroup();
//	Create	radio	menu	items
final	RadioMenuItem	fitWidth	=	new	RadioMenuItem("Fit	Width");
fitWidth.setToggleGroup(groupOption);
final	RadioMenuItem	fitHeight	=	new	RadioMenuItem("Fit	Height");
fitHeight.setToggleGroup(groupOption);
final	RadioMenuItem	original	=	new	RadioMenuItem("Original	Size");
original.setToggleGroup(groupOption);
//	Add	listener	for	toggle	group
groupOption.selectedToggleProperty().addListener(new	ChangeListener<Toggle>()	{
		public	void	changed(ObservableValue<?	extends	Toggle>	ov,
																						Toggle	old_toggle,	Toggle	new_toggle)	{
				if	(groupOption.getSelectedToggle()	!=	null)	{
						RadioMenuItem	choiceItem	=	(RadioMenuItem)	groupOption.getSelectedToggle();
						if	(choiceItem	==	fitWidth)	{
								System.out.println("fitwidth");
						}	else	if	(choiceItem	==	fitHeight)	{
								System.out.println("fitheight");
						}	else	{
								System.out.println("original	size");
						}
				}	
		}
});
//	Create	View	submenu	for	Option	menu
Menu	menuView	=	new	Menu("View");
menuView.getItems().addAll(fitWidth,	fitHeight,	original);
				
//	Set	Original	Size	as	default	choice
original.setSelected(true);
//	Add	option	menu	to	menu	bar
menuOption.getItems().add(menuView);
menuBar.getMenus().add(menuOption);
Listing	1-10.	Complete	source	codes	of	ImageViewer	class	become	like	this:
package	imageviewer;
import	java.io.File;
import	javafx.application.Application;
import	javafx.application.Platform;	
import	javafx.beans.value.ChangeListener;
import	javafx.beans.value.ObservableValue;
import	javafx.event.ActionEvent;
import	javafx.event.EventHandler;
import	javafx.scene.Scene;
import	javafx.scene.control.Menu;
import	javafx.scene.control.MenuBar;
import	javafx.scene.control.MenuItem;import	javafx.scene.control.RadioMenuItem;
import	javafx.scene.control.Toggle;
import	javafx.scene.control.ToggleGroup;
import	javafx.scene.image.Image;
import	javafx.scene.image.ImageView;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.FileChooser;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*	(in	directory:	ImageViewer1.0/src/example3/imageviewer/)
	*	This	application	creates	a	BorderPane	as	root	node	of	a	scene,	and
	*	add	a	StackPane	in	the	center	of	BorderPane
	*	The	initial	size	of	the	scene	is	set	to	600	by	400
	*	The	size	of	StackPane	will	be	automatically	set	to	fit	the	size	of	scene.
	*	StackPane	will	be	resized	when	window	size	is	adjusted	by	a	user
	*
	*	Add	a	menu	bar	in	the	top	of	BorderPane
	*	Create	File	Menu,	and	using	FileChooser's	Open	Dialog	to
	*	select	an	image	file,	load	and	display	the	image	in	image	rendering	area.
	*	
	*	Create	Option	menu	contains	View	submenu,	let	a	user	chooses	image	viewing
	*	criteria:	Fit	Width,	Fit	Height,	or	the	default	option	Original	Size.
	*
	*	@author	Shufen	Kuo
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(final	Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				StackPane	imageArea	=	new	StackPane();
				//	Set	min	size	for	StackPane	to	avoid	resizing
				//	when	loading	large	size	image
				imageArea.setMinSize(0,	0);
				rootPane.setCenter(imageArea);
				Scene	scene	=	new	Scene(rootPane,	600,	400);
				imageArea.widthProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	width	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
						}
				});
				imageArea.heightProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	height	changed	from	%.1f	to	%.1f%n",
										oldVal,	newVal);
						}
				});
				
				//	Add	menu	bar
				MenuBar	menuBar	=	new	MenuBar();
				Menu	menuFile	=	new	Menu("File");
				MenuItem	load	=	new	MenuItem("Load");
				MenuItem	exit	=	new	MenuItem("Exit");
				menuFile.getItems().addAll(load,	exit);
				menuBar.getMenus().add(menuFile);
				rootPane.setTop(menuBar);
				//	Add	action	for	exit	menu	item
				exit.setOnAction(new	EventHandler<ActionEvent>()	{
						@Override
						public	void	handle(ActionEvent	e)	{
								Platform.exit();
						}
				});
				//	Create	a	file	chooser
				final	FileChooser	fileChooser	=	new	FileChooser();
				fileChooser.setTitle("Open	an	Image	File");
				//	Create	image	view,	add	to	image	area
				final	ImageView	imageView	=	new	ImageView();
				imageArea.getChildren().add(imageView);
				//	Add	action	for	menu	item	Load
				load.setOnAction(new	EventHandler<ActionEvent>()	{
						@Override
						public	void	handle(ActionEvent	e)	{
								//	Open	FileChooser	dialog
								File	file	=	fileChooser.showOpenDialog(stage);
								if	(file	!=	null)	{
										String	url	=	file.toURI().toString();
										Image	image	=	new	Image(url);
										imageView.setImage(image);
								}
						}
				});
				
				//	Create	Option	menu
				Menu	menuOption	=	new	Menu("Option");
				//	Create	toggle	group
				final	ToggleGroup	groupOption	=	new	ToggleGroup();
				//	Create	radio	menu	items
				final	RadioMenuItem	fitWidth	=	new	RadioMenuItem("Fit	Width");
				fitWidth.setToggleGroup(groupOption);
				final	RadioMenuItem	fitHeight	=	new	RadioMenuItem("Fit	Height");
				fitHeight.setToggleGroup(groupOption);
				final	RadioMenuItem	original	=	new	RadioMenuItem("Original	Size");
				original.setToggleGroup(groupOption);
				
				//	Add	listener	for	toggle	group
				groupOption.selectedToggleProperty().addListener(new	ChangeListener<Toggle>()	{
						public	void	changed(ObservableValue<?	extends	Toggle>	ov,
										Toggle	old_toggle,	Toggle	new_toggle)	{
								if	(groupOption.getSelectedToggle()	!=	null)	{
										RadioMenuItem	choiceItem	=	(RadioMenuItem)	groupOption.getSelectedToggle();
										if	(choiceItem	==	fitWidth)	{
												System.out.println("fitwidth");
										}	else	if	(choiceItem	==	fitHeight)	{
												System.out.println("fitheight");
										}	else	{
												System.out.println("original	size");
										}
								}	
						}
				});
				//	Create	View	submenu	for	Option	menu
				Menu	menuView	=	new	Menu("View");
				menuView.getItems().addAll(fitWidth,	fitHeight,	original);
				
				//	Set	Original	Size	as	default	choice
				original.setSelected(true);
				//	Add	option	menu	to	menu	bar
				menuOption.getItems().add(menuView);
				menuBar.getMenus().add(menuOption);
				stage.setTitle("ImageViewer	V1.0");
				stage.setScene(scene);
				stage.show();
		}
		public	static	void	main(String[]	args)	{
				launch(args);
		}
}
Figure	1-6.	Snapshot	of	Option	menu	contains	View	submenu
Compile	and	run	the	application.	Selecting	different	radio	menu	items	in	View	submenu,
you	will	see	output	similar	as	follows:
Output	from	Running	the	Program	in	Command	Line:
Microsoft	Windows	[Version	6.3.9600]
(c)	2013	Microsoft	Corporation.	All	rights	reserved.
F:\My	Documents\DocRoot\SHUFEN_JAVA\MyBookJFX\VolumeOne\ImageViewer1.0\src\example3>
javac	-encoding	utf-8	-Xlint:unchecked	imageviewer\*.java
jar	cf	imageviewer.jar	imageviewer
java	-cp	imageviewer.jar	imageviewer.ImageViewer
original	size
imageArea	width	changed	from	0.0	to	600.0
imageArea	height	changed	from	0.0	to	375.0
fitheight
fitwidth
1.4	Implement	Fit	Width,	Fit	Height	and	Original	Size
Viewing	Options
In	this	section,	we	demonstrate	how	to	adjust	viewing	size	of	an	image	to	fit	the
application	window.	The	ImageView	is	created	as	a	child	of	a	StackPane,	and
according	to	StackPane	default	layout	strategy,	an	image	is	positioned	in	the	center	of
StackPane;	therefore,	if	the	size	of	an	image	is	larger	than	the	current	available	viewing
space,	which	is	subject	to	the	size	of	a	scene,	outer	portion	of	the	image	will	be	blocked,
thus	a	user	won’t	be	able	to	view	the	whole	image.
In	last	section,	we	created	an	Option	menu	containing	three	viewing	choices:	Fit	Width,
Fit	Height,	and	Original	Size.	An	image	is	rendered	based	on	the	viewing	option
currently	selected,	initially	it	is	set	to	Original	Size.	By	default,	we’d	like	to	preserve
the	original	width	to	height	ratio	of	an	image	when	scaling	is	in	action.	To	do	so,	we	set
value	of	preserveRatio	property	to	true	as	follows:
Listing	1-11.	Set	value	of	preserveRatio	property	to	true:
final	ImageView	imageView	=	new	ImageView();
imageView.setPreserveRatio(true);
Now,	let’s	explore	two	approaches	to	render	image	according	to	the	viewing	option
currently	selected.
1.4.1	Approach	One:	Bind	ImageView‘s	fitWidth/fitHeight
Properties	to	Scene’s	width/height	Properties	Respectively
We	use	bind	and	unbind	methods	defined	in	Property	interface	to	implement	Fit
Width,	Fit	Height,	and	Original	Size	viewing	options.
What	enticing	here	is	that,	once	the	binding	becomes	effective,	an	image’s	viewing	width
and/or	height	will	be	changed	accordingly	whenever	width	and/or	height	of	Scene	is
changed	dynamically.
1.4.1.1	Implement	Fit	Width	Viewing	Option
If	a	user	selects	Fit	Width	as	viewing	option,	we’ll	have	fitWidth	property	of
ImageView	bind	with	width	property	of	Scene,	and	unbind	fitHeight	property.	Here
are	codes:
Listing	1-12.	Bind	fitWidth	property	of	ImageView	object	with	width	property	of
Scene:
imageView.fitWidthProperty().bind(scene.widthProperty());
imageView.fitHeightProperty().unbind();
//	Besides	unbind,	must	also	set	fit	height	to	0
imageView.setFitHeight(0);
1.4.1.2	Implement	Fit	Height	Viewing	Option
If	Fit	Height	is	selected	as	viewing	option,we’ll	have	fitHeight	property	of
ImageView	bind	with	height	property	of	Scene,	subtracting	height	of	menu	bar,	and
unbind	fitHeight	property.
We	are	using	subtract	method	to	calculate	the	available	viewing	height	for	an	image.
The	subtract(double	other)	method,	which	inherited	from	DoubleExpression	class
by	DoubleProperty	class,	returns	a	new	NumberBinding	object	that	calculates	the
difference	of	this	NumberExpression	and	the	given	constant	value.	Here	are	codes:
Listing	1-13.	Bind	fitHeight	property	of	ImageView	with	height	Property	of	scene,
subtracting	height	of	menu	bar:
//	Available	height	for	rendering	image	is
//	subtract	menubar's	height	from	scene	height
imageView.fitHeightProperty().bind(
			scene.heightProperty().subtract(menuBar.getHeight()));
imageView.fitWidthProperty().unbind();
//	Besides	unbind,	must	also	set	fit	width	to	0	
imageView.setFitWidth(0);	
1.4.1.3	Implement	Original	Size	Viewing	Option
If	Original	Size	is	selected	as	viewing	option,	we’ll	have	fitWeight	property	as	well	as
fitHeight	property	of	the	ImageView	object	unbind.	Here	are	codes:
Listing	1-14.	Unbind	fitWidth	property	as	well	as	fitHeight	property	of	the
ImageView	object:
imageView.fitWidthProperty().unbind();
imageView.fitHeightProperty().unbind();
//	Besides	unbind,	must	also	set	fit	height/height	to	0
imageView.setFitWidth(0);
imageView.setFitHeight(0);
Please	note	that,	changing	values	of	fitWidth/fitHeight	properties	of	an	ImageView
object	doesn’t	affect	width/height	properties	of	the	underlying	Image	object.
Properties	of	the	Image	object,	such	as	width	and	height,	are	staying	intact	while
properties	relevant	to	viewing	options	of	the	ImageView	are	altering	dynamically	by	a
user.
The	advantage	of	approach	one	is	that	you	don’t	need	to	register	an	event	handler	to
response	to	resizing	event	of	a	Scene.	When	the	application	window	is	resized
dynamically,	the	Scene	is	resized,	accordingly	the	corresponding	properties	of	the
ImageView	is	changed,	and	the	size	of	image	rendering	area,	a	StackPane	object,	will
be	re-computed	automatically.
The	following	snippets	of	codes	show	the	implementation	of	approach	one.
Listing	1-15.	Listen	to	the	change	of	selection	for	radio	menu	items	and	use	bind	and
unbind	methods	to	adjust	fitWidth	and	fitHHeight	of	an	image	view.
final	StackPane	imageArea	=	new	StackPane();
			...
final	Scene	scene	=	new	Scene(rootPane,	600,	400);	
			
			...
final	MenuBar	menuBar	=	new	MenuBar();
			...
//	Create	toggle	group
final	ToggleGroup	groupOption	=	new	ToggleGroup();
//	Create	radio	menu	items	and	add	to	the	toggle	group
final	RadioMenuItem	fitWidth	=	new	RadioMenuItem("Fit	Width");
fitWidth.setToggleGroup(groupOption);
final	RadioMenuItem	fitHeight	=	new	RadioMenuItem("Fit	Height");
fitHeight.setToggleGroup(groupOption);
final	RadioMenuItem	original	=	new	RadioMenuItem("Original	Size");
original.setToggleGroup(groupOption);
groupOption.selectedToggleProperty().addListener(new	ChangeListener<Toggle>()	{
		public	void	changed(ObservableValue<?	extends	Toggle>	ov,
										Toggle	old_toggle,	Toggle	new_toggle)	{
				if	(groupOption.getSelectedToggle()	!=	null)	{
						RadioMenuItem	choiceItem	=	(RadioMenuItem)	groupOption.getSelectedToggle();
						if	(choiceItem	==	fitWidth)	{
								System.out.println("fitwidth");
								imageView.fitWidthProperty().bind(scene.widthProperty());
								imageView.fitHeightProperty().unbind();
								//	Besides	unbind,	must	also	set	fit	height	to	0
								imageView.setFitHeight(0);
						}	else	if	(choiceItem	==	fitHeight)	{
								System.out.println("fitheight");
								//	Available	height	for	rendering	image	is
								//	subtract	menubar's	height	from	scene	height
								imageView.fitHeightProperty().bind(
										scene.heightProperty().subtract(menuBar.getHeight()));
								imageView.fitWidthProperty().unbind();
								//	Besides	unbind,	must	also	set	fit	width	to	0	
								imageView.setFitWidth(0);	
						}	else	{
								System.out.println("original	size");
								imageView.fitWidthProperty().unbind();
								imageView.fitHeightProperty().unbind();
								//	Besides	unbind,	must	also	set	fit	height/height	to	0
								imageView.setFitWidth(0);
								imageView.setFitHeight(0);
						}
				}	
		}
});
1.4.1.4	Complete	Source	Codes	of	ImageViewer	Class
Complete	source	codes	of	ImageViewer	class	for	Approach	One	become	these:
Listing	1-16.	Complete	source	codes	of	ImageViewer	class	become	like	this:
package	imageviewer;
import	java.io.File;
import	javafx.application.Application;
import	javafx.application.Platform;	
import	javafx.beans.value.ChangeListener;
import	javafx.beans.value.ObservableValue;
import	javafx.event.ActionEvent;
import	javafx.event.EventHandler;
import	javafx.scene.Scene;
import	javafx.scene.control.Menu;
import	javafx.scene.control.MenuBar;
import	javafx.scene.control.MenuItem;
import	javafx.scene.control.RadioMenuItem;
import	javafx.scene.control.Toggle;
import	javafx.scene.control.ToggleGroup;
import	javafx.scene.image.Image;
import	javafx.scene.image.ImageView;
import	javafx.scene.layout.BorderPane;
import	javafx.scene.layout.StackPane;
import	javafx.stage.FileChooser;
import	javafx.stage.Stage;
/**
	*	File	Name:	ImageViewer.java
	*	(in	directory:	ImageViewer1.0/src/example4/imageviewer/)
	*	This	application	creates	a	BorderPane	as	root	node	of	a	scene,	and
	*	add	a	StackPane	in	the	center	of	BorderPane
	*	The	initial	size	of	the	scene	is	set	to	600	by	400
	*	The	size	of	StackPane	will	be	automatically	set	to	fit	the	size	of	scene.
	*	StackPane	will	be	resized	when	window	size	is	adjusted	by	a	user
	*
	*	Add	a	menu	bar	in	the	top	of	BorderPane
	*	Create	File	Menu,	and	using	FileChooser's	Open	Dialog	to
	*	select	an	image	file,	load	and	display	the	image	in	image	rendering	area.
	*	
	*	Create	Option	menu	contains	View	submenu,	let	a	user	chooses	image	viewing
	*	criteria:	Fit	Width,	Fit	Height,	or	the	default	option	Original	Size.
	*
	*	Adjust	image	viewing	size	using	bind	and	unbind	methods:
	*	Bind	fitWidth/fitHeight	of	image	view	to	width/height	of	scene,
	*	so	that,	size	of	image	view	will	be	changed	automatically
	*	whenever	scene	is	resized
	*
	*	@author	Shufen	Kuo
	*/
public	class	ImageViewer	extends	Application	{
		@Override
		public	void	start(final	Stage	stage)	{
				BorderPane	rootPane	=	new	BorderPane();
				final	StackPane	imageArea	=	new	StackPane();
				//	Set	min	size	for	StackPane	to	avoid	resizing
				//	when	loading	large	size	image
				imageArea.setMinSize(0,	0);
				rootPane.setCenter(imageArea);
				
				//	Create	image	view,	add	to	image	area
				final	ImageView	imageView	=	new	ImageView();
				imageView.setPreserveRatio(true);
				imageArea.getChildren().add(imageView);
				final	Scene	scene	=	new	Scene(rootPane,	600,	400);
				imageArea.widthProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	width	changed	from	%.1f	to	%.1f%n",
												oldVal,	newVal);
						}
				});
				imageArea.heightProperty().addListener(new	ChangeListener<Object>()	{
						public	void	changed(ObservableValue	o,	Object	oldVal,
										Object	newVal)	{
								System.out.format("imageArea	height	changed	from	%.1f	to	%.1f%n",
												oldVal,	newVal);
						}
				});
				
				//	Add	menu	bar
				final	MenuBar	menuBar	=	new	MenuBar();
				Menu	menuFile	=	new	Menu("File");
				MenuItem	load	=	new	MenuItem("Load");
				MenuItem	exit	=	new	MenuItem("Exit");
				menuFile.getItems().addAll(load,	exit);
				menuBar.getMenus().add(menuFile);
				rootPane.setTop(menuBar);
				//	Add	action	for	exit	menu	item
				exit.setOnAction(new	EventHandler<ActionEvent>()	{
						@Override
						public	void	handle(ActionEvent	e)	{
								Platform.exit();
						}