/**
* Copyright (C) 2022 by Martin Robillard. See https://codesample.info/about.html
*/
package e2.chapter8;
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Slider;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
* Class to demonstrate the Observer design pattern
* in Java. Note that there are many ways to apply the
* Observer design pattern, and that this is just one of them.
* This code requires JavaFX to run.
*/
public class LuckyNumber extends {
public static final int WIDTH = 200;
private static final int GAP = 10;
private static final int MARGIN = 20;
/**
* Launches the application.
* @param pArgs This program takes no argument.
*/
public static void main(String[] pArgs) {
(pArgs);
}
@Override
public void start(Stage pPrimaryStage) {
Model = new Model();
GridPane root = createPane(); // The root of the GUI component graph
root.add(new SliderPanel(model), 0, 0, 1, 1);
root.add(new IntegerPanel(model), 0, 1, 1, 1);
root.add(new TextPanel(model), 0, 2, 1, 1);
pPrimaryStage.setTitle("Lucky Number");
pPrimaryStage.setResizable(false);
pPrimaryStage.setScene(new Scene(root));
pPrimaryStage.show();
}
/*
* Helper method to hide the details of creating
* a nice looking grid.
*/
private static GridPane createPane() {
GridPane root = new GridPane();
root.setHgap(GAP);
root.setVgap(GAP);
root.setPadding(new Insets(MARGIN));
return root;
}
}
/**
* Concrete observer that displays the model
* data in a slider.
*/
class SliderPanel extends implements Observer {
private Slider aSlider = createSlider();
private Model aModel;
/**
* @param pModel The model observed by this panel.
*/
SliderPanel(Model pModel)
{
aModel = pModel;
aModel.addObserver(this);
aSlider.setValue(aModel.getNumber());
getChildren().add();
aSlider.valueProperty().addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> pValue, Number pOld, Number pNew) {
aModel.setNumber(pNew.intValue());
}
});
}
@Override
public void (int pNumber) {
aSlider.setValue(pNumber);
}
private static Slider createSlider() {
// CSOFF:
Slider slider = new Slider(1, 10, 5);
slider.setShowTickMarks(true);
slider.setShowTickLabels(true);
slider.setMinWidth(LuckyNumber.WIDTH);
slider.setMajorTickUnit(1);
slider.setBlockIncrement(1);
slider.setMinorTickCount(0);
slider.setSnapToTicks(true);
// CSON:
return slider;
}
}
/**
* Concrete observer that displays the model data
* as a integer in a text field.
*/
class IntegerPanel extends Parent implements Observer, <ActionEvent> {
private TextField aText = new TextField();
private Model aModel;
/**
* @param pModel The model observed by this panel.
*/
IntegerPanel(Model pModel) {
aModel = pModel;
aModel.addObserver(this);
aText.setMinWidth(LuckyNumber.WIDTH);
aText.setText(Integer.valueOf(aModel.getNumber()).toString());
getChildren().add(aText);
aText.setOnAction(this);
}
@Override
public void (ActionEvent pEvent) {
int lInteger = 1;
try {
lInteger = Integer.parseInt(aText.getText());
}
catch(NumberFormatException pException ) {
// Just ignore. We'll use 1 instead.
}
aModel.setNumber(lInteger);
}
@Override
public void newNumber(int pNumber) {
aText.setText(Integer.valueOf(pNumber).toString());
}
}
/**
* Concrete observer that displays the model data
* as a written-out number in a text field.
*/
class TextPanel extends HBox implements Observer {
private static final String[] LABELS = {"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"};
private TextField aText = new TextField();
private Model aModel;
/**
* @param pModel The model observed by this panel.
*/
TextPanel(Model pModel) {
aModel = pModel;
aModel.addObserver(this);
aText.setMinWidth(LuckyNumber.WIDTH);
aText.setText(LABELS[aModel.getNumber()]);
getChildren().add(aText);
aText.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent pEvent) {
int lIndex = 0;
for( int i = 0; i < LABELS.length; i++) {
if(aText.getText().equalsIgnoreCase(LABELS[i])) {
lIndex = i;
break;
}
}
aModel.setNumber(lIndex);
}
});
}
@Override
public void newNumber(int pNumber) {
aText.setText(LABELS[pNumber]);
}
}
/**
* The observable object.
*/
class Model {
private static final int DEFAULT = 5;
private static final int MAX = 10;
private List<Observer> aObservers = new ArrayList<>();
private int aNumber = DEFAULT;
public void addObserver(Observer pObserver) {
assert pObserver != null;
aObservers.add(pObserver);
}
void notifyObservers() {
for(Observer observer : aObservers) {
observer.newNumber(aNumber);
}
}
public void setNumber(int pNumber) {
if( pNumber < 0 ) {
aNumber = 0;
}
else if( pNumber > MAX ) {
aNumber = MAX;
}
else {
aNumber = pNumber;
}
notifyObservers();
}
public int getNumber() {
return aNumber;
}
}
/**
* Abstract observer role for the model.
*/
interface Observer {
void newNumber(int pNumber);
}
Or no declared constructor, in which case Java automatically creates a public no-arg constructor for the class.
Or no declared constructor, in which case Java automatically creates a public no-arg constructor for the class.
Before the JavaFX framework is started (i.e., before calling
the launch method), it's not possible to construct many of the
widgets. For this reason, the GUI elements are constructed in the
start(Stage)
method, rather than, e.g., in static fields.
Before the JavaFX framework is started (i.e., before calling
the launch method), it's not possible to construct many of the
widgets. For this reason, the GUI elements are constructed in the
start(Stage)
method, rather than, e.g., in static fields.
Using advanced reflection! Note that launch
is static, and
called in the static main
method, so there isn't any implicit
argument. To know which class to instantiate, the framework
looks at the stack trace at the start of the launch
method,
and identifies the method that called launch
. It then constructs
an instance of the class where that method (usually main
) is
located.
Using advanced reflection! Note that launch
is static, and
called in the static main
method, so there isn't any implicit
argument. To know which class to instantiate, the framework
looks at the stack trace at the start of the launch
method,
and identifies the method that called launch
. It then constructs
an instance of the class where that method (usually main
) is
located.
The model does not need to be stored in a field of the application class because a reference to it is injected directly into the components of the JavaFX scene graph.
The model does not need to be stored in a field of the application class because a reference to it is injected directly into the components of the JavaFX scene graph.
This code is an example of self-registration as an observer.
When the object is constructed, it registers itself (via the
this
keyword), as an observer of the model passed as
argument to the constructor.
This code is an example of self-registration as an observer.
When the object is constructed, it registers itself (via the
this
keyword), as an observer of the model passed as
argument to the constructor.
Adds the slider GUI component as a child node of this
node. This action is possible because getChildren()
is
inherited from the supertype (Parent
).
Adds the slider GUI component as a child node of this
node. This action is possible because getChildren()
is
inherited from the supertype (Parent
).
Adds a listener (meaning a concrete observer) to a different type of model, this time the value property of the slider. This property is observable so we can add observers to it. It is of the Observer pattern in this code. The callback takes three argument, the value reference, the old value, and the newly set value.
Adds a listener (meaning a concrete observer) to a different type of model, this time the value property of the slider. This property is observable so we can add observers to it. It is of the Observer pattern in this code. The callback takes three argument, the value reference, the old value, and the newly set value.
This means there are 2 observer-subject relations at play here, that shouldn't be confused:
SliderPanel
is an observer of Model
ChangeListener
is an observer of the value of aSlider
This means there are 2 observer-subject relations at play here, that shouldn't be confused:
SliderPanel
is an observer of Model
ChangeListener
is an observer of the value of aSlider
This statement illustrates how containers can serve as event
handlers for their own children components. An alternative
design is illustrated in class TextPanel
.
This statement illustrates how containers can serve as event
handlers for their own children components. An alternative
design is illustrated in class TextPanel
.
This statement illustrates how the object is both an observer and a controller. Here, in response to a GUI event, we control the model, which then sends further notifications to observers. It's important to be careful about call sequences in such situations to avoid .
This statement illustrates how the object is both an observer and a controller. Here, in response to a GUI event, we control the model, which then sends further notifications to observers. It's important to be careful about call sequences in such situations to avoid .
Here, the callback method handle
calls
setNumber
on aModel
, which then calls the other
callback method newNumber
, which changes the text of
aText
. Because that last operation (changing the value of
aText
) doesn't cause TextField
to notify the observer,
the chain of calls stops here. If this wasn't the case (e.g.,
TextField
notifies the observer after every change to the
value), then we would have an infinite recursion.
Here, the callback method handle
calls
setNumber
on aModel
, which then calls the other
callback method newNumber
, which changes the text of
aText
. Because that last operation (changing the value of
aText
) doesn't cause TextField
to notify the observer,
the chain of calls stops here. If this wasn't the case (e.g.,
TextField
notifies the observer after every change to the
value), then we would have an infinite recursion.
We can use anonymous classes to declare observers.
This anonymous class declaration provides the implementation
of the EventHandler
abstract observer. Contrast this
approach with the one used for IntegerPanel
.
We can use anonymous classes to declare observers.
This anonymous class declaration provides the implementation
of the EventHandler
abstract observer. Contrast this
approach with the one used for IntegerPanel
.
It's important not to have any null references
in the list of observers, otherwise any notification
will cause a NullPointerException
.
It's important not to have any null references
in the list of observers, otherwise any notification
will cause a NullPointerException
.
If the notification helper method is private, client cannot independently trigger observer notification: this must instead be programmed directly into the state-changing methods. By making the method public, we give more flexibility to the clients, at the cost of a more complex interface.
If the notification helper method is private, client cannot independently trigger observer notification: this must instead be programmed directly into the state-changing methods. By making the method public, we give more flexibility to the clients, at the cost of a more complex interface.
The three fundamental variables of the slider are min
,
max
, and value
. The value
should always
be a number within the range defined by min
and
max
. min
should always be less than or equal to
max
(although a slider whose min
and
max
are equal is a degenerate case that makes no sense).
min
defaults to 0, whereas max
defaults to 100.
This first example creates a slider whose range, or span, goes from 0 to 1, and whose value defaults to .5:
Slider slider = new Slider(0, 1, 0.5);
This next example shows a slider with customized tick marks and tick mark labels, which also spans from 0 to 1:
Slider slider = new Slider(0, 1, 0.5); slider.setShowTickMarks(true); slider.setShowTickLabels(true); slider.setMajorTickUnit(0.25f); slider.setBlockIncrement(0.1f);
This class is an observer for two models. By implementing interface
Observer
, it can observer an instance of Model
. By implementing
EventHandler
, it can observe any object that accepts this type of observer.
In our design, this is an instance of class TextField
used to enter
the lucky number in numeric form.
This class is an observer for two models. By implementing interface
Observer
, it can observer an instance of Model
. By implementing
EventHandler
, it can observe any object that accepts this type of observer.
In our design, this is an instance of class TextField
used to enter
the lucky number in numeric form.
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextField
with empty text content.
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextField supports the notion of showing prompt text
to the user when there is no text
already in the
TextField (either via the user, or set programmatically). This is a useful
way of informing the user as to what is expected in the text field, without
having to resort to tooltips
or on-screen labels
.
Example:
var textField = new TextField("Hello World!");
This method is the callback from EventHandler
, called
by TextField aText
.
Chapter 8, insight #9
Callback methods can be thought of as events to support a type of event-based programming. In this case, models are the event source and observers are the event handlers
This method is the callback from EventHandler
, called
by TextField aText
.
Chapter 8, insight #9
Callback methods can be thought of as events to support a type of event-based programming. In this case, models are the event source and observers are the event handlers
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextField
with empty text content.
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextField supports the notion of showing prompt text
to the user when there is no text
already in the
TextField (either via the user, or set programmatically). This is a useful
way of informing the user as to what is expected in the text field, without
having to resort to tooltips
or on-screen labels
.
Example:
var textField = new TextField("Hello World!");
List
interface. Implements all optional list operations, and permits all elements, including null
. In addition to implementing the List
interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector
, except that it is unsynchronized.)
List
interface. Implements all optional list operations, and permits all elements, including null
. In addition to implementing the List
interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector
, except that it is unsynchronized.)
The size
, isEmpty
, get
, set
, iterator
, and listIterator
operations run in constant time. The add
operation runs in amortized constant time, that is, adding n elements requires O(n) time. All of the other operations run in linear time (roughly speaking). The constant factor is low compared to that for the LinkedList
implementation.
Each ArrayList
instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
An application can increase the capacity of an ArrayList
instance before adding a large number of elements using the ensureCapacity
operation. This may reduce the amount of incremental reallocation.
Note that this implementation is not synchronized. If multiple threads access an ArrayList
instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more elements, or explicitly resizes the backing array; merely setting the value of an element is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the list. If no such object exists, the list should be "wrapped" using the Collections.synchronizedList
method. This is best done at creation time, to prevent accidental unsynchronized access to the list:
List list = Collections.synchronizedList(new ArrayList(...));
The iterators returned by this class's iterator
and listIterator
methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove
or add
methods, the iterator will throw a ConcurrentModificationException
. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException
on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
This class is a member of the Java Collections Framework.
To launch the JavaFX GUI application framework, it is necessary to
public
class thatApplication
class andTo launch the JavaFX GUI application framework, it is necessary to
public
class thatApplication
class andLife-cycle
The entry point for JavaFX applications is the Application class. The JavaFX runtime does the following, in order, whenever an application is launched:
Platform.startup(Runnable)
for more information)init()
methodstart(javafx.stage.Stage)
methodPlatform.exit()
implicitExit
attribute on Platform
is truestop()
methodNote that the start
method is abstract and must be overridden.
The init
and stop
methods have concrete implementations
that do nothing.
The Application
subclass must be declared public and must have a
public no-argument constructor.
Calling Platform.exit()
is the preferred way to explicitly terminate
a JavaFX Application. Directly calling System.exit(int)
is
an acceptable alternative, but doesn't allow the Application stop()
method to run.
A JavaFX Application should not attempt to use JavaFX after the
FX toolkit has terminated or from a ShutdownHook, that is, after the
stop()
method returns or System.exit(int)
is called.
Note: The JavaFX classes must be loaded from a set of
named javafx.*
modules on the module path.
Loading the JavaFX classes from the classpath is not supported.
See Platform.startup
for more information.
Deploying an Application as a Module
If the Application
subclass is in a named module then that class
must be accessible to the javafx.graphics
module.
Otherwise, an exception will be thrown when the application is launched.
This means that
in addition to the class itself being declared public, the module must
export
(or open
) the containing package to
at least the javafx.graphics
module.
For example, if com.foo.MyApplication
is in the foo.app
module, the module-info.java
might look like this:
module foo.app {
exports com.foo to javafx.graphics;
}
Parameters
Application parameters are available by calling the getParameters()
method from the init()
method, or any time after the init
method has been called.
Threading
JavaFX creates an application thread for running the application start
method, processing input events, and running animation timelines. Creation
of JavaFX Scene
and Stage
objects as well as modification of
scene graph operations to live objects (those objects already
attached to a scene) must be done on the JavaFX application thread.
The Java launcher loads and initializes the specified Application class on the JavaFX Application Thread. If there is no main method in the Application class, or if the main method calls Application.launch(), then an instance of the Application is then constructed on the JavaFX Application Thread.
The init
method is called on the launcher thread, not on the
JavaFX Application Thread.
This means that an application must not construct a Scene
or a Stage
in the init
method.
An application may construct other JavaFX objects in the init
method.
All the unhandled exceptions on the JavaFX application thread that occur during
event dispatching, running animation timelines, or any other code, are forwarded
to the thread's uncaught
exception handler
.
Example
The following example will illustrate a simple JavaFX application.
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
public class MyApp extends Application {
public void start(Stage stage) {
Circle circ = new Circle(40, 40, 30);
Group root = new Group(circ);
Scene scene = new Scene(root, 400, 300);
stage.setTitle("My JavaFX Application");
stage.setScene(scene);
stage.show();
}
}
The above example will produce the following:
The call to the launch
method (inherited from the
Application
class), and
then call the method start(Stage)
. Calling the start
method, and the Application
subclass before that, is all done by the framework.
main
method. It must not be called more than once or an exception will be thrown. This is equivalent to launch(TheClass.class, args)
where TheClass
is the immediately enclosing class of the method that called launch. It must be a public subclass of Application
with a public no-argument constructor, in a package that is exported
(or open
) to at least the javafx.graphics
module, or a RuntimeException will be thrown.
The call to the launch
method (inherited from the
Application
class), and
then call the method start(Stage)
. Calling the start
method, and the Application
subclass before that, is all done by the framework.
main
method. It must not be called more than once or an exception will be thrown. This is equivalent to launch(TheClass.class, args)
where TheClass
is the immediately enclosing class of the method that called launch. It must be a public subclass of Application
with a public no-argument constructor, in a package that is exported
(or open
) to at least the javafx.graphics
module, or a RuntimeException will be thrown.
The launch method does not return until the application has exited, either via a call to Platform.exit()
or all of the application windows have been closed.
Typical usage is:
public static void main(String[] args) { Application.launch(args); }
args
- the command line arguments passed to the application. An application may get these parameters using the getParameters()
method.
IllegalStateException
- if this method is called more than once.
IllegalStateException
- if this method is called from the JavaFX application thread.
RuntimeException
- if there is an error launching the JavaFX runtime, or if the application class cannot be constructed (e.g., if the class is not public or is not in an exported package), or if an Exception or Error is thrown by the Application constructor, init method, start method, or stop method.
Scene
class is the container for all content in a scene graph.
The background of the scene is filled as specified by the fill
property.
Scene
class is the container for all content in a scene graph.
The background of the scene is filled as specified by the fill
property.
The application must specify the root Node
for the scene graph by setting
the root
property. If a Group
is used as the root, the
contents of the scene graph will be clipped by the scene's width and height and
changes to the scene's size (if user resizes the stage) will not alter the
layout of the scene graph. If a resizable node (layout Region
or
Control
) is set as the root, then the root's size will track the
scene's size, causing the contents to be relayed out as necessary.
The scene's size may be initialized by the application during construction. If no size is specified, the scene will automatically compute its initial size based on the preferred size of its content. If only one dimension is specified, the other dimension is computed using the specified dimension, respecting content bias of a root.
An application may request depth buffer support or scene anti-aliasing
support at the creation of a Scene
. A scene with only 2D shapes and
without any 3D transforms does not need a depth buffer nor scene
anti-aliasing support. A scene containing 3D shapes or 2D shapes with 3D
transforms may use depth buffer support for proper depth sorted rendering; to
avoid depth fighting (also known as Z fighting), disable depth testing on 2D
shapes that have no 3D transforms. See
depthTest
for more information. A scene with
3D shapes may enable scene anti-aliasing to improve its rendering quality.
The depthBuffer and antiAliasing flags are conditional features. With the
respective default values of: false and SceneAntialiasing.DISABLED
.
See ConditionalFeature.SCENE3D
for more information.
A default headlight will be added to a scene that contains one or more
Shape3D
nodes, but no light nodes. This light source is a
Color.WHITE
PointLight
placed at the camera position.
A Scene
may be created and modified on any thread until it is attached
to a Window
that is showing
.
After that, it must be modified only on the JavaFX Application Thread.
Note that Scene
is not thread-safe; modifying a Scene
on
multiple threads at the same time will lead to unpredictable results and
must be avoided.
The JavaFX Application Thread is created as part of the startup process for
the JavaFX runtime. See the Application
class and
the Platform.startup(Runnable)
method for more information.
Example:
import javafx.scene.*; import javafx.scene.paint.*; import javafx.scene.shape.*; Group root = new Group(); Scene s = new Scene(root, 300, 300, Color.BLACK); Rectangle r = new Rectangle(25,25,250,250); r.setFill(Color.BLUE); root.getChildren().add(r);
root
- The root node of the scene graph
NullPointerException
- if root is null
A child may be placed anywhere within the grid and may span multiple rows/columns. Children may freely overlap within rows/columns and their stacking order will be defined by the order of the gridpane's children list (0th node in back, last node in front).
GridPane may be styled with backgrounds and borders using CSS. See
Region
superclass for details.
A child's placement within the grid is defined by it's layout constraints:
Constraint | Type | Description |
---|---|---|
columnIndex | integer | column where child's layout area starts. |
rowIndex | integer | row where child's layout area starts. |
columnSpan | integer | the number of columns the child's layout area spans horizontally. |
rowSpan | integer | the number of rows the child's layout area spans vertically. |
If the row/column indices are not explicitly set, then the child will be placed in the first row/column. If row/column spans are not set, they will default to 1. A child's placement constraints can be changed dynamically and the gridpane will update accordingly.
The total number of rows/columns does not need to be specified up front as the gridpane will automatically expand/contract the grid to accommodate the content.
To use the GridPane, an application needs to set the layout constraints on the children and add those children to the gridpane instance. Constraints are set on the children using static setter methods on the GridPane class:
GridPane gridpane = new GridPane();
// Set one constraint at a time...
// Places the button at the first row and second column
Button button = new Button();
GridPane.setRowIndex(button, 0);
GridPane.setColumnIndex(button, 1);
// or convenience methods set more than one constraint at once...
Label label = new Label();
GridPane.setConstraints(label, 2, 0); // column=2 row=0
// don't forget to add children to gridpane
gridpane.getChildren().addAll(button, label);
Applications may also use convenience methods which combine the steps of
setting the constraints and adding the children:
GridPane gridpane = new GridPane();
gridpane.add(new Button(), 1, 0); // column=1 row=0
gridpane.add(new Label(), 2, 0); // column=2 row=0
GridPane gridpane = new GridPane();
gridpane.getColumnConstraints().add(new ColumnConstraints(100)); // column 0 is 100 wide
gridpane.getColumnConstraints().add(new ColumnConstraints(200)); // column 1 is 200 wide
By default the gridpane will resize rows/columns to their preferred sizes (either
computed from content or fixed), even if the gridpane is resized larger than
its preferred size. If an application needs a particular row or column to
grow if there is extra space, it may set its grow priority on the RowConstraints
or ColumnConstraints object. For example:
GridPane gridpane = new GridPane();
ColumnConstraints column1 = new ColumnConstraints(100,100,Double.MAX_VALUE);
column1.setHgrow(Priority.ALWAYS);
ColumnConstraints column2 = new ColumnConstraints(100);
gridpane.getColumnConstraints().addAll(column1, column2); // first column gets any extra width
Note: Nodes spanning multiple rows/columns will be also size to the preferred sizes. The affected rows/columns are resized by the following priority: grow priorities, last row. This is with respect to row/column constraints.
GridPane gridpane = new GridPane();
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(50);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPercentWidth(50);
gridpane.getColumnConstraints().addAll(column1, column2); // each get 50% of width
If a percentage value is set on a row/column, then that value takes precedent and the
row/column's min, pref, max, and grow constraints will be ignored.
Note that if the sum of the widthPercent (or heightPercent) values total greater than 100, the values will be treated as weights. e.g. if 3 columns are each given a widthPercent of 50, then each will be allocated 1/3 of the gridpane's available width (50/(50+50+50)).
A gridpane's parent will resize the gridpane within the gridpane's resizable range during layout. By default the gridpane computes this range based on its content and row/column constraints as outlined in the table below.
width | height | |
---|---|---|
minimum | left/right insets plus the sum of each column's min width. | top/bottom insets plus the sum of each row's min height. |
preferred | left/right insets plus the sum of each column's pref width. | top/bottom insets plus the sum of each row's pref height. |
maximum | Double.MAX_VALUE | Double.MAX_VALUE |
A gridpane's unbounded maximum width and height are an indication to the parent that it may be resized beyond its preferred size to fill whatever space is assigned to it.
GridPane provides properties for setting the size range directly. These properties default to the sentinel value USE_COMPUTED_SIZE, however the application may set them to other values as needed:
gridpane.setPrefSize(300, 300);
// never size the gridpane larger than its preferred size:
gridpane.setMaxSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
Applications may restore the computed values by setting these properties back
to USE_COMPUTED_SIZE.
GridPane does not clip its content by default, so it is possible that children's bounds may extend outside its own bounds if a child's min size prevents it from being fit within it space.
An application may set additional constraints on children to customize how the child is sized and positioned within the layout area established by it's row/column indices/spans:
Constraint | Type | Description |
---|---|---|
halignment | javafx.geometry.HPos | The horizontal alignment of the child within its layout area. |
valignment | javafx.geometry.VPos | The vertical alignment of the child within its layout area. |
hgrow | javafx.scene.layout.Priority | The horizontal grow priority of the child. |
vgrow | javafx.scene.layout.Priority | The vertical grow priority of the child. |
margin | javafx.geometry.Insets | Margin space around the outside of the child. |
By default the alignment of a child within its layout area is defined by the alignment set for the row and column. If an individual alignment constraint is set on a child, that alignment will override the row/column alignment only for that child. Alignment of other children in the same row or column will not be affected.
Grow priorities, on the other hand, can only be applied to entire rows or columns. Therefore, if a grow priority constraint is set on a single child, it will be used to compute the default grow priority of the encompassing row/column. If a grow priority is set directly on a RowConstraint or ColumnConstraint object, it will override the value computed from content.
Extending Parent
allows the SliderPanel
to become a Node
and
be inserted in the scene graph (subtyping) and well as
inherit the ability to contain children nodes (code reuse).
Chapter 8, insight #15
You can inherit from component classes of the GUI framework to create custom graphical components that can be added to an application's GUI component graph
Extending Parent
allows the SliderPanel
to become a Node
and
be inserted in the scene graph (subtyping) and well as
inherit the ability to contain children nodes (code reuse).
Chapter 8, insight #15
You can inherit from component classes of the GUI framework to create custom graphical components that can be added to an application's GUI component graph
This class handles all hierarchical scene graph operations, including adding/removing child nodes, marking branches dirty for layout and rendering, picking, bounds calculations, and executing the layout pass on each pulse.
There are two direct concrete Parent subclasses
This is the implementation of Observer's callback method.
Chapter 8, insight #9
Callback methods can be thought of as events to support a type of event-based programming. In this case, models are the event source and observers are the event handlers
This is the implementation of Observer's callback method.
Chapter 8, insight #9
Callback methods can be thought of as events to support a type of event-based programming. In this case, models are the event source and observers are the event handlers
Chapter 8, insight #14
The component graph must be instantiated before the user interface becomes visible. In JavaFX this instantiation is triggered in the start
method of the application class
Chapter 8, insight #14
The component graph must be instantiated before the user interface becomes visible. In JavaFX this instantiation is triggered in the start
method of the application class
Chapter 8, insight #2
Consider separating the code responsible for storing data from the code responsible for viewing this data from the code responsible for changing the data (the Model--View--Controller decomposition)
Chapter 8, insight #2
Consider separating the code responsible for storing data from the code responsible for viewing this data from the code responsible for changing the data (the Model--View--Controller decomposition)
Chapter 8, insight #7
The model needs to notify observers when it changes its state, but when to issue that notification is a design decision
Chapter 8, insight #7
The model needs to notify observers when it changes its state, but when to issue that notification is a design decision
Lists that support this operation may place limitations on what elements may be added to this list. In particular, some lists will refuse to add null elements, and others will impose restrictions on the type of elements that may be added. List classes should clearly specify in their documentation any restrictions on what elements may be added.
add
in interface Collection<E>
e
- element to be appended to this list
true
(as specified by Collection.add(E)
)
UnsupportedOperationException
- if the add
operation is not supported by this list
ClassCastException
- if the class of the specified element prevents it from being added to this list
NullPointerException
- if the specified element is null and this list does not permit null elements
IllegalArgumentException
- if some property of this element prevents it from being added to this list
Integer
class wraps a value of the primitive type int
in an object. An object of type Integer
contains a single field whose type is int
.
Integer
class wraps a value of the primitive type int
in an object. An object of type Integer
contains a single field whose type is int
.
In addition, this class provides several methods for converting an int
to a String
and a String
to an int
, as well as other constants and methods useful when dealing with an int
.
This is a value-based class; programmers should treat instances that are equal as interchangeable and should not use instances for synchronization, or unpredictable behavior may occur. For example, in a future release, synchronization may fail.
Implementation note: The implementations of the "bit twiddling" methods (such as highestOneBit
and numberOfTrailingZeros
) are based on material from Henry S. Warren, Jr.'s Hacker's Delight, (Addison Wesley, 2002).
A child may be placed anywhere within the grid and may span multiple rows/columns. Children may freely overlap within rows/columns and their stacking order will be defined by the order of the gridpane's children list (0th node in back, last node in front).
GridPane may be styled with backgrounds and borders using CSS. See
Region
superclass for details.
A child's placement within the grid is defined by it's layout constraints:
Constraint | Type | Description |
---|---|---|
columnIndex | integer | column where child's layout area starts. |
rowIndex | integer | row where child's layout area starts. |
columnSpan | integer | the number of columns the child's layout area spans horizontally. |
rowSpan | integer | the number of rows the child's layout area spans vertically. |
If the row/column indices are not explicitly set, then the child will be placed in the first row/column. If row/column spans are not set, they will default to 1. A child's placement constraints can be changed dynamically and the gridpane will update accordingly.
The total number of rows/columns does not need to be specified up front as the gridpane will automatically expand/contract the grid to accommodate the content.
To use the GridPane, an application needs to set the layout constraints on the children and add those children to the gridpane instance. Constraints are set on the children using static setter methods on the GridPane class:
GridPane gridpane = new GridPane();
// Set one constraint at a time...
// Places the button at the first row and second column
Button button = new Button();
GridPane.setRowIndex(button, 0);
GridPane.setColumnIndex(button, 1);
// or convenience methods set more than one constraint at once...
Label label = new Label();
GridPane.setConstraints(label, 2, 0); // column=2 row=0
// don't forget to add children to gridpane
gridpane.getChildren().addAll(button, label);
Applications may also use convenience methods which combine the steps of
setting the constraints and adding the children:
GridPane gridpane = new GridPane();
gridpane.add(new Button(), 1, 0); // column=1 row=0
gridpane.add(new Label(), 2, 0); // column=2 row=0
GridPane gridpane = new GridPane();
gridpane.getColumnConstraints().add(new ColumnConstraints(100)); // column 0 is 100 wide
gridpane.getColumnConstraints().add(new ColumnConstraints(200)); // column 1 is 200 wide
By default the gridpane will resize rows/columns to their preferred sizes (either
computed from content or fixed), even if the gridpane is resized larger than
its preferred size. If an application needs a particular row or column to
grow if there is extra space, it may set its grow priority on the RowConstraints
or ColumnConstraints object. For example:
GridPane gridpane = new GridPane();
ColumnConstraints column1 = new ColumnConstraints(100,100,Double.MAX_VALUE);
column1.setHgrow(Priority.ALWAYS);
ColumnConstraints column2 = new ColumnConstraints(100);
gridpane.getColumnConstraints().addAll(column1, column2); // first column gets any extra width
Note: Nodes spanning multiple rows/columns will be also size to the preferred sizes. The affected rows/columns are resized by the following priority: grow priorities, last row. This is with respect to row/column constraints.
GridPane gridpane = new GridPane();
ColumnConstraints column1 = new ColumnConstraints();
column1.setPercentWidth(50);
ColumnConstraints column2 = new ColumnConstraints();
column2.setPercentWidth(50);
gridpane.getColumnConstraints().addAll(column1, column2); // each get 50% of width
If a percentage value is set on a row/column, then that value takes precedent and the
row/column's min, pref, max, and grow constraints will be ignored.
Note that if the sum of the widthPercent (or heightPercent) values total greater than 100, the values will be treated as weights. e.g. if 3 columns are each given a widthPercent of 50, then each will be allocated 1/3 of the gridpane's available width (50/(50+50+50)).
A gridpane's parent will resize the gridpane within the gridpane's resizable range during layout. By default the gridpane computes this range based on its content and row/column constraints as outlined in the table below.
width | height | |
---|---|---|
minimum | left/right insets plus the sum of each column's min width. | top/bottom insets plus the sum of each row's min height. |
preferred | left/right insets plus the sum of each column's pref width. | top/bottom insets plus the sum of each row's pref height. |
maximum | Double.MAX_VALUE | Double.MAX_VALUE |
A gridpane's unbounded maximum width and height are an indication to the parent that it may be resized beyond its preferred size to fill whatever space is assigned to it.
GridPane provides properties for setting the size range directly. These properties default to the sentinel value USE_COMPUTED_SIZE, however the application may set them to other values as needed:
gridpane.setPrefSize(300, 300);
// never size the gridpane larger than its preferred size:
gridpane.setMaxSize(Region.USE_COMPUTED_SIZE, Region.USE_COMPUTED_SIZE);
Applications may restore the computed values by setting these properties back
to USE_COMPUTED_SIZE.
GridPane does not clip its content by default, so it is possible that children's bounds may extend outside its own bounds if a child's min size prevents it from being fit within it space.
An application may set additional constraints on children to customize how the child is sized and positioned within the layout area established by it's row/column indices/spans:
Constraint | Type | Description |
---|---|---|
halignment | javafx.geometry.HPos | The horizontal alignment of the child within its layout area. |
valignment | javafx.geometry.VPos | The vertical alignment of the child within its layout area. |
hgrow | javafx.scene.layout.Priority | The horizontal grow priority of the child. |
vgrow | javafx.scene.layout.Priority | The vertical grow priority of the child. |
margin | javafx.geometry.Insets | Margin space around the outside of the child. |
By default the alignment of a child within its layout area is defined by the alignment set for the row and column. If an individual alignment constraint is set on a child, that alignment will override the row/column alignment only for that child. Alignment of other children in the same row or column will not be affected.
Grow priorities, on the other hand, can only be applied to entire rows or columns. Therefore, if a grow priority constraint is set on a single child, it will be used to compute the default grow priority of the encompassing row/column. If a grow priority is set directly on a RowConstraint or ColumnConstraint object, it will override the value computed from content.
child
- the node being added to the gridpane
columnIndex
- the column index position for the child within the gridpane, counting from 0
rowIndex
- the row index position for the child within the gridpane, counting from 0
colspan
- the number of columns the child's layout area should span
rowspan
- the number of rows the child's layout area should span
title
property.title
property.Stage
.value
- the value for the title
propertyresizable
property.
resizable
property.
Stage
is resizable or not by the user. Programatically you may still change the size of the Stage. This is a hint which allows the implementation to optionally make the Stage resizable by the user.
Warning: Since 8.0 the property cannot be bound and will throw RuntimeException
on an attempt to do so. This is because the setting of resizable is asynchronous on some systems or generally might be set by the system / window manager.
Bidirectional binds are still allowed, as they don't block setting of the property by the system.
value
- the value for the resizable
property
Stage
class is the top level JavaFX container. The primary Stage is constructed by the platform. Additional Stage objects may be constructed by the application.
Stage
class is the top level JavaFX container. The primary Stage is constructed by the platform. Additional Stage objects may be constructed by the application.
Stage objects must be constructed and modified on the JavaFX Application Thread.
The JavaFX Application Thread is created as part of the startup process for the JavaFX runtime. See the Application
class and the Platform.startup(Runnable)
method for more information.
Some Stage
properties are read-only, even though they have corresponding set methods, because they can be changed externally by the underlying platform, and therefore must not be bindable. Further, these properties might be ignored on some platforms, depending on whether or not there is a window manager and how it is configured. For example, a platform without a window manager might ignore the iconified
property.
Style
A stage has one of the following styles:
StageStyle.DECORATED
- a stage with a solid white background and platform decorations.StageStyle.UNDECORATED
- a stage with a solid white background and no decorations.StageStyle.TRANSPARENT
- a stage with a transparent background and no decorations.StageStyle.UTILITY
- a stage with a solid white background and minimal platform decorations.The style must be initialized before the stage is made visible.
On some platforms decorations might not be available. For example, on some mobile or embedded devices. In these cases a request for a DECORATED or UTILITY window will be accepted, but no decorations will be shown.
Owner
A stage can optionally have an owner Window. When a window is a stage's owner, it is said to be the parent of that stage.
Owned Stages are tied to the parent Window. An owned stage will always be on top of its parent window. When a parent window is closed or iconified, then all owned windows will be affected as well. Owned Stages cannot be independantly iconified.
The owner must be initialized before the stage is made visible.
Modality
A stage has one of the following modalities:
Modality.NONE
- a stage that does not block any other window.Modality.WINDOW_MODAL
- a stage that blocks input events from being delivered to all windows from its owner (parent) to its root. Its root is the closest ancestor window without an owner.Modality.APPLICATION_MODAL
- a stage that blocks input events from being delivered to all windows from the same application, except for those from its child hierarchy.When a window is blocked by a modal stage its Z-order relative to its ancestors is preserved, and it receives no input events and no window activation events, but continues to animate and render normally. Note that showing a modal stage does not necessarily block the caller. The show()
method returns immediately regardless of the modality of the stage. Use the showAndWait()
method if you need to block the caller until the modal stage is hidden (closed). The modality must be initialized before the stage is made visible.
Example:
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class HelloWorld extends Application {
@Override public void start(Stage stage) {
Text text = new Text(10, 40, "Hello World!");
text.setFont(new Font(40));
Scene scene = new Scene(new Group(text));
stage.setTitle("Welcome to JavaFX!");
stage.setScene(scene);
stage.sizeToScene();
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
produces the following on Windows:
produces the following on Mac OSX:
produces the following on Linux:
hgap
property.
hgap
property.
value
- the value for the hgap
property
vgap
property.
vgap
property.
value
- the value for the vgap
property
padding
property.padding
property.Insets.EMPTY
. Setting the
value to null
should be avoided.value
- the value for the padding
propertyThis class handles all hierarchical scene graph operations, including adding/removing child nodes, marking branches dirty for layout and rendering, picking, bounds calculations, and executing the layout pass on each pulse.
There are two direct concrete Parent subclasses
The three fundamental variables of the slider are min
,
max
, and value
. The value
should always
be a number within the range defined by min
and
max
. min
should always be less than or equal to
max
(although a slider whose min
and
max
are equal is a degenerate case that makes no sense).
min
defaults to 0, whereas max
defaults to 100.
This first example creates a slider whose range, or span, goes from 0 to 1, and whose value defaults to .5:
Slider slider = new Slider(0, 1, 0.5);
This next example shows a slider with customized tick marks and tick mark labels, which also spans from 0 to 1:
Slider slider = new Slider(0, 1, 0.5); slider.setShowTickMarks(true); slider.setShowTickLabels(true); slider.setMajorTickUnit(0.25f); slider.setBlockIncrement(0.1f);
value
property.
value
property.
min
and max
, inclusive. If it is ever out of bounds either due to min
or max
changing or due to itself being changed, then it will be clamped to always remain valid.
value
- the value for the value
property
String
class represents character strings. All string literals in Java programs, such as "abc"
, are implemented as instances of this class.
String
class represents character strings. All string literals in Java programs, such as "abc"
, are implemented as instances of this class.
Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared. For example:
String str = "abc";
is equivalent to:
char data[] = {'a', 'b', 'c'}; String str = new String(data);
Here are some more examples of how strings can be used:
System.out.println("abc"); String cde = "cde"; System.out.println("abc" + cde); String c = "abc".substring(2, 3); String d = cde.substring(1, 2);
The class String
includes methods for examining individual characters of the sequence, for comparing strings, for searching strings, for extracting substrings, and for creating a copy of a string with all characters translated to uppercase or to lowercase. Case mapping is based on the Unicode Standard version specified by the Character
class.
The Java language provides special support for the string concatenation operator ( + ), and for conversion of other objects to strings. For additional information on string concatenation and conversion, see The Java Language Specification.
Unless otherwise noted, passing a null
argument to a constructor or method in this class will cause a NullPointerException
to be thrown.
A String
represents a string in the UTF-16 format in which supplementary characters are represented by surrogate pairs (see the section Unicode Character Representations in the Character
class for more information). Index values refer to char
code units, so a supplementary character uses two positions in a String
.
The String
class provides methods for dealing with Unicode code points (i.e., characters), in addition to those for dealing with Unicode code units (i.e., char
values).
Unless otherwise noted, methods for comparing Strings do not take locale into account. The Collator
class provides methods for finer-grain, locale-sensitive String comparison.
javac
compiler may implement the operator with StringBuffer
, StringBuilder
, or java.lang.invoke.StringConcatFactory
depending on the JDK version. The implementation of string conversion is typically through the method toString
, defined by Object
and inherited by all classes in Java.
Parent
.
Parent
.
See the class documentation for Node
for scene graph structure restrictions on setting a Parent
's children list. If these restrictions are violated by a change to the list of children, the change is ignored and the previous value of the children list is restored. An IllegalArgumentException
is thrown in this case.
If this Parent
node is attached to a Scene
attached to a Window
that is showning (Window.isShowing()
), then its list of children must only be modified on the JavaFX Application Thread. An IllegalStateException
is thrown if this restriction is violated.
Note to subclasses: if you override this method, you must return from your implementation the result of calling this super method. The actual list instance returned from any getChildren() implementation must be the list owned and managed by this Parent. The only typical purpose for overriding this method is to promote the method to be public.
Parent
.
int
.Number
is the superclass of platform classes representing numeric values that are convertible to the primitive types byte
, double
, float
, int
, long
, and short
. The specific semantics of the conversion from the numeric value of a particular Number
implementation to a given primitive type is defined by the Number
implementation in question. For platform classes, the conversion is often analogous to a narrowing primitive conversion or a widening primitive conversion as defined in The Java Language Specification for converting between primitive types. Therefore, conversions may lose information about the overall magnitude of a numeric value, may lose precision, and may even return a result of a different sign than the input. See the documentation of a given Number
implementation for conversion details.
Number
is the superclass of platform classes representing numeric values that are convertible to the primitive types byte
, double
, float
, int
, long
, and short
. The specific semantics of the conversion from the numeric value of a particular Number
implementation to a given primitive type is defined by the Number
implementation in question. For platform classes, the conversion is often analogous to a narrowing primitive conversion or a widening primitive conversion as defined in The Java Language Specification for converting between primitive types. Therefore, conversions may lose information about the overall magnitude of a numeric value, may lose precision, and may even return a result of a different sign than the input. See the documentation of a given Number
implementation for conversion details.
ObservableValue
is an entity that wraps a value and allows to
observe the value for changes. In general this interface should not be
implemented directly but one of its sub-interfaces
(ObservableBooleanValue
etc.).
ObservableValue
is an entity that wraps a value and allows to
observe the value for changes. In general this interface should not be
implemented directly but one of its sub-interfaces
(ObservableBooleanValue
etc.).
The value of the ObservableValue
can be requested with
getValue()
.
An implementation of ObservableValue
may support lazy evaluation,
which means that the value is not immediately recomputed after changes, but
lazily the next time the value is requested (see note 1 in "Implementation Requirements").
An ObservableValue
generates two types of events: change events and
invalidation events. A change event indicates that the value has changed
(see note 2 in "Implementation Requirements"). An
invalidation event is generated if the current value is not valid anymore.
This distinction becomes important if the ObservableValue
supports
lazy evaluation, because for a lazily evaluated value one does not know if an
invalid value really has changed until it is recomputed. For this reason,
generating change events requires eager evaluation while invalidation events
can be generated for eager and lazy implementations.
Implementations of this class should strive to generate as few events as possible to avoid wasting too much time in event handlers. Implementations in this library mark themselves as invalid when the first invalidation event occurs. They do not generate any more invalidation events until their value is recomputed and valid again.
Two types of listeners can be attached to an ObservableValue
:
InvalidationListener
to listen to invalidation events and
ChangeListener
to listen to change events.
Important note: attaching a ChangeListener
enforces eager computation
even if the implementation of the ObservableValue
supports lazy
evaluation.
Object#equals(Object)
) of the value.ChangeListener
is notified whenever the value of an
ObservableValue
changes. It can be registered and unregistered with
ObservableValue.addListener(ChangeListener)
respectively
ObservableValue.removeListener(ChangeListener)
ChangeListener
is notified whenever the value of an
ObservableValue
changes. It can be registered and unregistered with
ObservableValue.addListener(ChangeListener)
respectively
ObservableValue.removeListener(ChangeListener)
For an in-depth explanation of change events and how they differ from
invalidation events, see the documentation of ObservableValue
.
The same instance of ChangeListener
can be registered to listen to
multiple ObservableValues
.
ChangeListener
which will be notified whenever the value of the ObservableValue
changes. If the same listener is added more than once, then it will be notified more than once. That is, no check is made to ensure uniqueness.
ChangeListener
which will be notified whenever the value of the ObservableValue
changes. If the same listener is added more than once, then it will be notified more than once. That is, no check is made to ensure uniqueness.
Note that the same actual ChangeListener
instance may be safely registered for different ObservableValues
.
The ObservableValue
stores a strong reference to the listener which will prevent the listener from being garbage collected and may result in a memory leak. It is recommended to either unregister a listener by calling removeListener
after use or to use an instance of WeakChangeListener
avoid this situation.
listener
- The listener to register
NullPointerException
- if the listener is null
showTickMarks
property.
showTickMarks
property.
Skin
implementation should show tick marks.
value
- the value for the showTickMarks
property
showTickLabels
property.
showTickLabels
property.
Skin
implementation will only show labels if showTickMarks
is also true.
value
- the value for the showTickLabels
property
minWidth
property.
minWidth
property.
Defaults to the USE_COMPUTED_SIZE
flag, which means that minWidth(forHeight)
will return the region's internally computed minimum width.
Setting this value to the USE_PREF_SIZE
flag will cause minWidth(forHeight)
to return the region's preferred width, enabling applications to easily restrict the resizability of the region.
value
- the value for the minWidth
property
majorTickUnit
property.
majorTickUnit
property.
min
is 0 and the max
is 100 and the majorTickUnit
is 25, then there would be 5 tick marks: one at position 0, one at position 25, one at position 50, one at position 75, and a final one at position 100.
This value should be positive and should be a value less than the span. Out of range values are essentially the same as disabling tick marks.
value
- the value for the majorTickUnit
property
blockIncrement
property.
blockIncrement
property.
snapToTicks
is true then the nearest tick mark to the adjusted value will be used.
value
- the value for the blockIncrement
property
minorTickCount
property.
minorTickCount
property.
value
- the value for the minorTickCount
property
snapToTicks
property.
snapToTicks
property.
value
of the Slider
should always be aligned with the tick marks. This is honored even if the tick marks are not shown.
value
- the value for the snapToTicks
property
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextArea
control. Additionally, if you want
a form of rich-text editing, there is also the
HTMLEditor
control.
TextField supports the notion of showing prompt text
to the user when there is no text
already in the
TextField (either via the user, or set programmatically). This is a useful
way of informing the user as to what is expected in the text field, without
having to resort to tooltips
or on-screen labels
.
Example:
var textField = new TextField("Hello World!");
Integer
instance representing the specified int
value. If a new Integer
instance is not required, this method should generally be used in preference to the constructor Integer(int)
, as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
Integer
instance representing the specified int
value. If a new Integer
instance is not required, this method should generally be used in preference to the constructor Integer(int)
, as this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
i
- an int
value.
Integer
instance representing i
.
Unlike sets, lists typically allow duplicate elements. More formally, lists typically allow pairs of elements e1
and e2
such that e1.equals(e2)
, and they typically allow multiple null elements if they allow null elements at all. It is not inconceivable that someone might wish to implement a list that prohibits duplicates, by throwing runtime exceptions when the user attempts to insert them, but we expect this usage to be rare.
The List
interface places additional stipulations, beyond those specified in the Collection
interface, on the contracts of the iterator
, add
, remove
, equals
, and hashCode
methods. Declarations for other inherited methods are also included here for convenience.
The List
interface provides four methods for positional (indexed) access to list elements. Lists (like Java arrays) are zero based. Note that these operations may execute in time proportional to the index value for some implementations (the LinkedList
class, for example). Thus, iterating over the elements in a list is typically preferable to indexing through it if the caller does not know the implementation.
The List
interface provides a special iterator, called a ListIterator
, that allows element insertion and replacement, and bidirectional access in addition to the normal operations that the Iterator
interface provides. A method is provided to obtain a list iterator that starts at a specified position in the list.
The List
interface provides two methods to search for a specified object. From a performance standpoint, these methods should be used with caution. In many implementations they will perform costly linear searches.
The List
interface provides two methods to efficiently insert and remove multiple elements at an arbitrary point in the list.
Note: While it is permissible for lists to contain themselves as elements, extreme caution is advised: the equals
and hashCode
methods are no longer well defined on such a list.
Some list implementations have restrictions on the elements that they may contain. For example, some implementations prohibit null elements, and some have restrictions on the types of their elements. Attempting to add an ineligible element throws an unchecked exception, typically NullPointerException
or ClassCastException
. Attempting to query the presence of an ineligible element may throw an exception, or it may simply return false; some implementations will exhibit the former behavior and some will exhibit the latter. More generally, attempting an operation on an ineligible element whose completion would not result in the insertion of an ineligible element into the list may throw an exception or it may succeed, at the option of the implementation. Such exceptions are marked as "optional" in the specification for this interface.
The List.of
and List.copyOf
static factory methods provide a convenient way to create unmodifiable lists. The List
instances created by these methods have the following characteristics:
UnsupportedOperationException
to be thrown. However, if the contained elements are themselves mutable, this may cause the List's contents to appear to change. null
elements. Attempts to create them with null
elements result in NullPointerException
. subList
views implement the RandomAccess
interface. This interface is a member of the Java Collections Framework.
String
object representing this Integer
's value. The value is converted to signed decimal representation and returned as a string, exactly as if the integer value were given as an argument to the toString(int)
method.
String
object representing this Integer
's value. The value is converted to signed decimal representation and returned as a string, exactly as if the integer value were given as an argument to the toString(int)
method.
text
property.text
property.value
- the value for the text
propertyonAction
property.
onAction
property.
null
if no action handler is assigned. The action handler is normally called when the user types the ENTER key.
value
- the value for the onAction
property
text
property.
text
property.
text
property
'-'
('\u002D'
) to indicate a negative value or an ASCII plus sign '+'
('\u002B'
) to indicate a positive value. The resulting integer value is returned, exactly as if the argument and the radix 10 were given as arguments to the parseInt(java.lang.String, int)
method.
'-'
('\u002D'
) to indicate a negative value or an ASCII plus sign '+'
('\u002B'
) to indicate a positive value. The resulting integer value is returned, exactly as if the argument and the radix 10 were given as arguments to the parseInt(java.lang.String, int)
method.
s
- a String
containing the int
representation to be parsed
NumberFormatException
- if the string does not contain a parsable integer.
HBox example:
HBox hbox = new HBox(8); // spacing = 8
hbox.getChildren().addAll(new Label("Name:), new TextBox());
HBox will resize children (if resizable) to their preferred widths and uses its
fillHeight property to determine whether to resize their heights to
fill its own height or keep their heights to their preferred (fillHeight defaults to true).
The alignment of the content is controlled by the alignment property,
which defaults to Pos.TOP_LEFT.
If an hbox is resized larger than its preferred width, by default it will keep children to their preferred widths, leaving the extra space unused. If an application wishes to have one or more children be allocated that extra space it may optionally set an hgrow constraint on the child. See "Optional Layout Constraints" for details.
HBox lays out each managed child regardless of the child's visible property value; unmanaged children are ignored.
An hbox's parent will resize the hbox within the hbox's resizable range during layout. By default the hbox computes this range based on its content as outlined in the table below.
width | height | |
---|---|---|
minimum | left/right insets plus the sum of each child's min width plus spacing between each child. | top/bottom insets plus the largest of the children's min heights. |
preferred | left/right insets plus the sum of each child's pref width plus spacing between each child. | top/bottom insets plus the largest of the children's pref heights. |
maximum | Double.MAX_VALUE | Double.MAX_VALUE |
An hbox's unbounded maximum width and height are an indication to the parent that it may be resized beyond its preferred size to fill whatever space is assigned to it.
HBox provides properties for setting the size range directly. These properties default to the sentinel value USE_COMPUTED_SIZE, however the application may set them to other values as needed:
hbox.setPrefWidth(400);
Applications may restore the computed values by setting these properties back
to USE_COMPUTED_SIZE.
HBox does not clip its content by default, so it is possible that children's bounds may extend outside its own bounds if a child's min size prevents it from being fit within the hbox.
An application may set constraints on individual children to customize HBox's layout. For each constraint, HBox provides a static method for setting it on the child.
Constraint | Type | Description |
---|---|---|
hgrow | javafx.scene.layout.Priority | The horizontal grow priority for the child. |
margin | javafx.geometry.Insets | Margin space around the outside of the child. |
For example, if an hbox needs the TextField to be allocated all extra space:
HBox hbox = new HBox();
TextField field = new TextField();
HBox.setHgrow(field, Priority.ALWAYS);
hbox.getChildren().addAll(new Label("Search:"), field, new Button("Go"));
If more than one child has the same grow priority set, then the hbox will
allocate equal amounts of space to each. HBox will only grow a child up to
its maximum width, so if the child has a max width other than Double.MAX_VALUE,
the application may need to override the max to allow it to grow.
For example:
HBox hbox = new HBox();
Button button1 = new Button("Add");
Button button2 = new Button("Remove");
HBox.setHgrow(button1, Priority.ALWAYS);
HBox.setHgrow(button2, Priority.ALWAYS);
button1.setMaxWidth(Double.MAX_VALUE);
button2.setMaxWidth(Double.MAX_VALUE);
hbox.getChildren().addAll(button1, button2);
Parent
.
Parent
.
See the class documentation for Node
for scene graph structure
restrictions on setting a Parent
's children list.
If these restrictions are violated by a change to the list of children,
the change is ignored and the previous value of the children list is
restored. An IllegalArgumentException
is thrown in this case.
If this Parent
node is attached to a Scene
attached to a Window
that is showning (Window.isShowing()
), then its
list of children must only be modified on the JavaFX Application Thread.
An IllegalStateException
is thrown if this restriction is
violated.
Note to subclasses: if you override this method, you must return from your implementation the result of calling this super method. The actual list instance returned from any getChildren() implementation must be the list owned and managed by this Parent. The only typical purpose for overriding this method is to promote the method to be public.
getChildren
in class Parent
String
to another String
, ignoring case considerations. Two strings are considered equal ignoring case if they are of the same length and corresponding Unicode code points in the two strings are equal ignoring case.
String
to another String
, ignoring case considerations. Two strings are considered equal ignoring case if they are of the same length and corresponding Unicode code points in the two strings are equal ignoring case.
Two Unicode code points are considered the same ignoring case if at least one of the following is true:
==
operator) Character.toLowerCase(Character.toUpperCase(int))
on each Unicode code point produces the same result Note that this method does not take locale into account, and will result in unsatisfactory results for certain locales. The Collator
class provides locale-sensitive comparison.
anotherString
- The String
to compare this String
against
true
if the argument is not null
and it represents an equivalent String
ignoring case; false
otherwise