Control
class and the basic controls that are part of JavaFX 8. In addition, the chapter will demonstrate how the controls can be used and combined to create an application. Lastly, the chapter will look at how to start changing the UI and behavior of these controls. In Chapter 6, I’ll cover the more advanced controls.Control
class. This class provides some default features that are part of each control. For example, each control is a node, so each control can be part of the scene graph. Figure 5-1 shows the dependency hierarchy of the Control
class. The diagram is not a comprehensive list of all the controls that extend the Control
class; in addition to the Button
class shown here, several abstract classes extend the Control
class and provide basic functionality for special types of controls. The ButtonBase
class is one example; it defines basic functionality for a button-based control.Control
class extends the Region
class. Because of the class hierarchy, the Control
class can control all the properties, such as the padding, of the Region
class. Each JavaFX control is composed of a set of nodes, so each control internally holds a set of child nodes. When using default controls, developers don’t need to be aware of this behavior, but a custom control often uses a set of shapes or other nodes. You will look at this in more detail when I discuss custom controls in Chapter 10.Control
class offers some properties that you can use to configure each control. Table 5-1 contains an overview of these properties. Some of them, like the skin
property, are useful only when you need a custom control or a special behavior. I will discuss these properties in more detail later in the following chapters, but take a minute to review them now.Button
CheckBox
Hyperlink
ToggleButton
RadioButton
Label
TextField
PasswordField
TextArea
ProgressIndicator
ProgressBar
Slider
Control
classes. The controls in JavaFX offer much greater potential than most other available toolkits such as Swing. All Control
classes contain properties that can be used to create individual forms of these controls, and by setting these properties, you can easily change the font of a button or its text alignment, for example. In addition, you can style the controls using CSS. These features allow you to create a modern and interactive application with a custom look.GridPane
is created as the root node of the scene graph. This pane contains all the controls that are used in the application as child nodes. To define a more professional look and give you a better understanding of the application, I used a special property for the TextField
instances, shown in Figure 5-3. Specifically, by using the promptText
property, I added a text hint to the text fields. This text will be shown when the fields contain no custom text.Control
classes are implemented as properties, and therefore, you can create bindings between these properties. Let’s apply three behaviors to this application: I’ll show how to disable the PasswordField
until a username is entered, disable the Login button until text is entered in both text fields, and display a short login message after the Login button is clicked. The following code snippet implements the complete behavior in only three lines of code:disable
property of the PasswordField
is bound to a Boolean
property that defines whether the TextField
for the username is empty. Here, I use the isEmpty()
method of the StringProperty
class. Most of the property classes in JavaFX provide helpful methods like this one. The method creates a Boolean
property that wraps the empty state of the StringProperty
. Whenever the internal string of the property is null or empty, the created BooleanProperty
will contain the Boolean
value true. Otherwise, it will contain false. The second line shows another feature of the property API. With the internal fluent API, you can create a concatenation of two different Boolean
properties by using the or(…)
method. This method is part of the BooleanProperty
and can be used to combine different Boolean
properties. Additionally, the class offers functions such as not()
or and(…)
. You can find comparable methods in all property types in JavaFX. In the last line, I add an event handler to the Button
control. Once text is entered in both fields, the button can be clicked. With each click, the event handler will handle the event and print the entered login information on the console. The handler is defined as a lambda expression, so it can be written in one line of code.NOTE
The helpful methods used in the code snippet to concatenate Boolean properties or define properties that wrap the empty state of a StringProperty are defined in the expression classes. JavaFX contains these abstract classes for the data types Boolean , Double , Float , Integer , List , Long , Map , Number , Object , Set , and String . The specific property classes such as StringProperty extend the corresponding expression class to provide these functionalities. You can find all the expression classes in the javafx.beans.binding package. In addition to these classes, the When class and a set of binding classes for all given data types are part of this package. With the use of these classes, JavaFX provides a fluent API that can be used to create really complex and flexible bindings with only a few lines of code. |
Labeled
class. This class defines properties that can be used to influence the rendering of text onscreen. The basic controls that extend the Labeled
class include the following:CheckBox
Hyperlink
ToggleButton
RadioButton
Button
Label
Labeled
class, but are considered advanced controls. I’ll discuss these further in Chapter 6.Labeled
controls have been used in many of the examples so far. Whenever I created a button or a label, I defined text for these controls. The String that was passed to the controls as the visible text is used for the text
property internally. In most cases, the String was passed as a parameter of the constructor of these controls, but it can be easily changed at any time by calling setText(…)
or textProperty().set(…)
. Besides the text property, the Labeled
class defines a lot of properties to style the look of the text and the complete control. Table 5-2 describes the properties that are part of the Labeled
class.wrapText
property to split the text into two lines dynamically, showing the complete text within a given width. The lineSpacing
property defines the space between the lines, and the textFill
property defines a color to render the text onscreen. In Table 5-2, notice that the textFill
property is defined as ObjectProperty<Paint>
. The Paint
class is the superclass for colors, gradients, or patterns that can be used in JavaFX to fill or draw a section.graphic
property is used as an easy way to define an icon or a custom visual representation of any state or data in a control. The graphic
property can hold any Node
object. This node will be added to the Labeled
control and rendered in it. You can define the position of the graphic node with a set of properties, as already mentioned in Table 5-2. In the example, I use a simple static rectangle as the graphic node of the button, but thanks to JavaFX, there no limits here; each class that extends the Node
class can be used for the graphic
property. For example, you could instead choose a custom image or even an MP4 movie as the graphic object onscreen.NOTE
Most of the nodes in JavaFX are resolution independent and can be scaled without a loss of information or pixelation. Whenever a pixel-based image is used in JavaFX, though, this benefit is destroyed. Think about an icon that has a size of 32×32 pixels, for example. When this icon is defined as an image for the graphic property of a button, it will be shown onscreen. When the button is scaled up by a transform, the icon can look pixelated. Therefore, to avoid this behavior, you need to use a vector-based icon. You could use the SVGPath class, which is a node that extends the Shape class and renders a Scalable Vector Graphic (SVG) path onscreen. (SVG is a standard specification to define vector-based graphics.) With the help of this class, you can create an icon as an SVG path that can easily be used in JavaFX. |
Label
class encapsulates text and shows it onscreen. Most of the functionality of the Label
control is implemented in the Labeled
class, which is the superclass of the Label
control. Thus, the Label
contains only one additional property: labelFor
. The labelFor
property is an ObjectProperty<Node>
, where the node can utilize the label to show its mnemonics.ButtonBase
class provides basic functionality for all controls that act like buttons. This means that a control can be in an “armed,” (or “pressed”) state and fire an event. A button will be armed when the mouse is pressed on it and will fire when the mouse is released. This abstract class includes two properties: armed
, which is a ReadOnlyBooleanProperty
that indicates the button has been armed, and onAction
, which is an ObjectProperty<EventHandler<ActionEvent>>
that invokes the event handler when the button is fired. The following are the most important methods:void arm()
Arms the buttonvoid disarm()
Disarms the buttonvoid fire()
Fires the buttonButtonBase
class extends Labeled
, the text that is part of each control that extends this class can be styled as mentioned earlier.ButtonBase
class is the Button
control. This control behaves exactly as you would expect and is well known to most developers. The button is armed by pressing a mouse or a key, and it will fire an action whenever the mouse or key is released. All this functionality is already implemented in the ButtonBase
class, and the Button
class offers two additional Boolean
properties:cancelButton
If cancelButton
is set to true, the Button
class will handle a keyboard VK_ESC
press if no other node in the scene consumes it. In this case, the onAction
event handler will be called.defaultButton
If defaultButton
is set to true, the Button
class will handle a keyboard VK_ENTER
press if no other node in the scene consumes it. In this case, the onAction
event handler will be called.CheckBox
control has a checked state and can be checked or unchecked. Normally, this is shown with a tick mark. In JavaFX, a CheckBox
control can have two or three different states. The class provides a selected
property that behaves exactly as in other UI toolkits, but also contains an indeterminate
property, which is the property that can be used to define a third state of the CheckBox
control. Table 5-3 shows the impact on the visual representation of the control.CheckBox
class extends the ButtonBase
class, and therefore, an event handler for action events can be added to it. This handler will be called whenever the state of the CheckBox
changes. The CheckBox
class provides three Boolean
properties to define its behavior and state, shown here:selected
Indicates whether this CheckBox
is checkedindeterminate
Determines whether the CheckBox
is in the indeterminate stateallowIndeterminate
Defines whether indeterminate is usedHyperlink
control is like a Label
control that adds action support. Everyone knows hyperlinks on the Web link one page to another. In JavaFX, the Hyperlink
control looks like an HTML hyperlink. It appears like a label that can be pressed and will become underlined whenever the mouse is over it. Likewise, the JavaFX Hyperlink
control changes its color after it is pressed the first time. To do so, the control offers the visited
property. This is the only property that is implemented by the class. The Hyperlink
control extends the ButtonBase
class.RadioButton
control that most developers should know from other UI toolkits, such as Swing, the ToggleButton
is an alternative control in JavaFX that can be used to define toggleable controls in an application. The RadioButton
class extends the ToggleButton
class that inherits from the Control
class. Both controls should be used when a series of items is needed where only one item can be selected. Instances of ToggleButton
and RadioButton
can be placed in groups. A group is represented by the ToggleGroup
class and needs to be created; by default, the controls are not in a group. You can define a toggleable control to a group by calling the setToggleGroup(…)
method on the ToggleButton
or RadioButton
. Whenever one control in a group is selected, all other controls will be automatically deselected. Each of these two control types can hold custom user data. The user data of the selected control can be received by the group. Here is a small example that shows how to create a group with a RadioButton
and a ToggleButton
:Control
classes and the ToggleGroup
provide properties to check the selection state and to receive the user data of the selected control. The following code snippet shows how this can be done in different ways:NOTE
The ToggleGroup uses internally the javafx.scene.control.Toggle interface. This interface defines all methods that are needed to use a toggleable control in a ToggleGroup . ToggleButton and RadioButton implement this interface. Besides these two controls, some special controls for menus such as the RadioMenuItem class implement this interface, too. If a custom control should be used inside a ToggleGroup , the Control class needs to implement this interface. By doing so, the control can be combined with any other toggleable control in a ToggleGroup . |
RadioButton
and ToggleButton
have some differences in look and behavior. You can see both controls in Figure 5-2 shown earlier. Unlike the RadioButton
, the ToggleButton
is rendered like a button, but it’s not a command button like the Button
control. When a ToggleButton
is selected, it is rendered like an armed button. The next difference between these two controls is that a ToggleButton
can be deselected. Unlike the RadioButton
, a ToggleButton
can be unselected, which allows you to create a ToggleGroup
where no item needs to be selected. There are two properties implemented by the ToggleButton
class: selectedProperty
, which is a Boolean
property that indicates whether the toggle button is selected, and toggleGroupProperty
, which is an ObjectProperty<ToggleGroup>
that defines the ToggleGroup
to which the ToggleButton
belongs.TextInputControl
, which is the class that defines the basic properties and functionalities for all controls that offer text input. All these controls support the possibility of text selection, editing, and a caret. A caret is an indicator that is used to show the current position within the text. Normally, a caret will be shown when the text input control is the one in focus, and the position of the caret can usually be changed by the mouse or the arrow keys. Table 5-4 shows the properties that are offered by the TextInputControl
class.TextInputControl
offers a number of methods. In addition, the basic class includes methods for editing the contained text or selecting a sequence of the text. Table 5-5 gives an overview of these methods.TextInputControl
class is the TextField
class. This control can wrap one line of text. The TextField
control was used in earlier examples, including the login sample at the beginning of this chapter (shown in Figure 5-2). The control adds some properties to the basic ones that are defined in its superclass. Table 5-6 describes these properties.PasswordField
class extends TextField
. A PasswordField
masks the entered input and can be used for login dialogs, among other things. In addition, cut and copy can’t be used in a PasswordField
. The PasswordField
introduces no additional properties or methods.TextArea
. This control can be used to enter multiple lines of plain text; it is specially designed to render long text that can be wrapped in multiple lines. If the text is too long to fit in the TextArea
, a scroll bar will be added automatically to the control so users can scroll through the whole text. In addition, you can define the preferred count of characters in a line and the preferred number of lines. This will internally be used to define the preferred size of the TextArea
. By default, the text wrap is not active in a TextArea
. If the entered text will exceed the width of the TextArea
, a horizontal scroll bar will be shown. Once wrapping is activated, the text will wrap in multiple lines. In this case, a vertical scroll bar will be shown when the text extends the TextArea
. Table 5-7 describes all the properties defined in the TextArea
class.TextField
.TextArea
with some sample text and create some labels. These labels have EventHandler
instances that handle mouse events to interact with the TextArea
. I’m not using buttons here because the click of a button will request the focus of the application. Once this happens, the button will be in focus, and the TextArea
loses the focus. A TextArea
that is not focused won’t render the caret, so I use customized labels here for a user interaction since labels are not focusable by default. By clicking the labels, the caret position in the TextArea
will change, and the text wrap can be activated or disabled. In addition, I have customized the style and behavior of the controls. All controls have a big font size to render their content, and the labels will change their text color whenever the mouse hovers over them. Figure 5-6 shows the example application.Button
class. In this case, the requestFocus()
method should do nothing:Slider
class in JavaFX directly extends the Control
class. The Slider
control can be used to visualize a numeric value in a defined range and let the user define a value in the given range. To do so, a so-called thumb is displayed in the slider. This thumb defines the selected value; the user can drag it to change the value. The class contains a large set of properties that can be used to change the visual representation of the slider, the range, and its selectable steps in that range. The most fundamental properties of the Slider
are min
, max
, and value
. The min
and max
properties define the range. The value
property is a number within this range. Table 5-8 describes all properties of the Slider
class.Slider
class provides some methods to change the value programmatically, including decrement()
and increment()
. These methods behave as you would imagine, with decrement()
reducing the value and increment()
increasing the value by the counts defined by the blockIncrement
property.Slider
class in many ways. The following sample creates two Slider
controls that are rendered differently and defines custom ranges to select a value, each customized using properties from the Slider
class:StringConverter
instance. The second slider shows many unlabeled tick marks.NOTE
As you saw in the previous example, JavaFX controls provide numerous properties that you can use to change the visual representation of the controls. Using these properties is the simplest way to change the view of a control. This is a great benefit compared to other UI toolkits such as Swing. The UI components in Swing provide attributes to change the visualization of controls but often lack the depth of manipulation possible in JavaFX. If the properties used so far aren’t enough, you can also use a custom skin. I will discuss this more with custom controls in Chapter 10. |
ProgressIndicator
and ProgressBar
controls to indicate an infinite or finite progress. These controls are most often used to show the state of a task. If data is loaded in the background, for example, a ProgressBar
control can be used to show the progress of this task. The ProgressIndicator
class extends the Control
class and is the superclass of the ProgressBar
. The ProgressIndicator
contains two special properties to define the type and the progress value of the control. The indeterminate
property, a ReadOnlyBoolean
property, defines whether the ProgressIndicator
shows indeterminate progress, while the progress
property, a DoubleProperty
, is used to show the actual progress. If the value is negative, the ProgressIndicator
shows indeterminate progress.javafx.concurrent
API and uses a ProgressIndicator
and a ProgressBar
to visualize the state of the task:progress
property is –1. Once the button is clicked, the Task
instance starts in a background thread. The Task
class provides a progress
property, which can be bound to the property of the ProgressIndicator
and ProgressBar
. Then, both controls will visualize the progress of the background task. Figure 5-8 shows the application in infinite and finite progress states.NOTE
The Task class that is used in this application is part of the concurrency API of JavaFX. I won’t cover concurrency in depth in this book, but all related classes can be found in the javafx.concurrency package, including properties for messaging and exceptions. Normally, the classes in this package can be used to create background tasks that can retrieve or upload data. A major benefit of the javafx.concurrency classes is the use of the property API. As shown in the example application, the Task class provides a progressProperty that can be easily bound to other properties. |
tooltip
property to show a tooltip whenever a mouse hovers over the control. A tooltip can be used to show the user helpful information about a control’s usage. A tooltip in JavaFX is defined by the Tooltip
class and is always shown as a pop-up over the control. Usually, a tooltip will contain plain text that describes the control and its use, but in JavaFX, a tooltip can also contain rich graphics or nodes by using the graphic property. You can use the graphic
property like described for the Labeled
control earlier. In addition to this property, the class contains some other properties to define the layout of the tooltip and the rendering of the text. Table 5-9 describes the defined properties.Tooltip
class can be used in JavaFX to offer rich tooltips to the user. Here, I am adding a shape to the tooltip instead of simple plain text.NOTE
The graphic property of the Tooltip class can contain any node instance. Because panes and controls extend the Node class, a control or a complete layouted pane could be used in a tooltip. This might make sense if you develop a GUI editor, for example, but it doesn’t make sense to add interaction to controls that are part of a tooltip. A tooltip will be closed whenever the mouse leaves the control that provides the tooltip, so the mouse can never enter the tooltip by default. |
Control
classes reviewed so far, there are some special controls that can be used to create menus in JavaFX applications. There are several different ways a menu can be shown and used in an application, including the following:MenuBar
that is integrated in a windowContextMenu
that is shown as a pop-up for a controlControl
classes that can be used as containers for a menu: the MenuBar
and the ContextMenu
. This chapter will cover both types.ContextMenu
can be used to show a pop-up on another Control
instance. This pop-up can be used to provide specific actions or configurations that can be handled by the user. Some controls in JavaFX already use a ContextMenu
by default. If you right-click in a TextArea
, for example, a pop-up menu will appear that contains some basic operations, such as Copy and Paste. This functionality is implemented by a ContextMenu
. As mentioned earlier in this chapter, the Control
class contains a contextMenu
property that can define a ContextMenu
for a control. By simply setting a specific menu to this property, a pop-up with the content of the menu will be shown whenever the user right-clicks the control. On some operating systems, this behavior will change in the future, but by default, the right mouse button is the action trigger for this functionality.ContextMenu
can contain different menu items, which I’ll review in more detail after showing a basic sample. In the following application code, a simple ContextMenu
is added to a Button
instance:ContextMenu
: a MenuItem
and a CheckMenuItem
. Only MenuItem
instances or instances of classes that extend this superclass can be added to a ContextMenu
. The MenuItem
is a simple menu entry that can be clicked, and whenever an item is clicked, an action event will be handled. As shown in many samples, an event handler can be set to the onAction
property of the control. This is done in this example application, too. The CheckMenuItem
behaves like a CheckBox
. It contains a selected
property that will change with each click on the item. In the sample, the underline
property of the Button
instance is bound to this property. Each time this menu item is activated, the text of the Button
instance will appear underlined. Figure 5-10 shows an example of this behavior.ContextMenu
class contains an onAction
property. Like in all other classes that support action events, this property is defined as ObjectProperty<EventHandler<ActionEvent>>
and will handle all action events. This will happen for each action that occurs on a menu item in the ContextMenu
. So, whenever the Rotate menu item in the previous example is clicked, the event handler of the item itself and of the ContextMenu
will be triggered. In addition, the ContextMenu
provides some helpful methods, described in Table 5-10.MenuItem
RadioMenuItem
TabMenuItem
CheckMenuItem
CustomMenuItem
SeparatorMenuItem
Menu
Menu
class is a special item because instances can contain additional menu items. By using the Menu
class, you can create a menu hierarchy. The following application shows how to achieve this in code. As already mentioned, besides a ContextMenu
, a MenuBar
can be used to display menus onscreen. In the following example, a MenuBar
with several menu items is added to the screen:NOTE
Some operating systems such as Mac OS define a global menu bar, and not each application has its own bar that is wrapped in the application window. Instead, the OS contains a bar that is usually displayed at the top of the screen, and its content changes whenever another application receives the focus. You can use this kind of menu bar in JavaFX, too. To do so, the MenuBar class contains the useSystemMenuBar property. By setting the Boolean value of this property to true, the content of the MenuBar won’t be displayed in the window. Instead, all items of the MenuBar are displayed in the global one of the operating system. |
Separator
control defines a horizontal or vertical line that can be used as a visual separation in a view or a menu. The following sample adds a separator to a list of CheckBox
instances. By doing so, a division of the elements is shown onscreen. Figure 5-11 shows the result.Separator
control in the previous example is displayed as a horizontal line, but a separator can be vertical, too, by using the orientation
property. In some special cases, like in a toolbar, the separator will automatically appear vertically based on internal CSS definitions. In the following example, the Separator
instance is created like before and no properties are set:GridPane
. The three labels are just static content of the application view. Some other controls, like Slider
, need to define some interaction with the user. This interaction will be added in Java code later. To create a link between the FXML file and the Java code, all these controls contain a unique ID. The following code snippet shows the FXML definition of the sliders:fx:id
attribute defines a unique ID. You can use any text as the ID, and by doing so, you can create a link from the Java code to the FXML code by injecting the FXML-defined Node
instance in your Java code. The following code defines a simplified version of the controller class that will be used for the FXML file:Java
class contains all three sliders as private fields. These fields are annotated with the @FXML
annotation, which is used to create the link between Java and FXML. When the ViewController
is instantiated by an FXMLLoader
, all fields that are marked by the @FXML
annotation will be injected with the created nodes that are defined in the FXML. It is important to know that the name of the fields must be the same as the previously defined fx:id
value.BorderPane
is used as the rootNode
, and the ViewController
class is defined in its fx:controller
attribute:FXMLLoader
instance and adds its root node to the scene, as shown here:bigApp.fxml
file in the same package as the FirstBigApp
class, you can use the getClass().getResource(…)
method to receive the URL of the FXML file.NOTE
The FXMLLoader class provides more functionality than discussed here. The controller instance can be accessed by the class or can define a resource bundle, for example. Here, FXML should be used to exclude the layout of an application from the Java code. In a bigger application, it would be useful to create links between controllers in order to switch between different views. For additional information, review the FXML API and the flow API of DataFX (www.javafxdata.org). The flow API provides functionality to switch between different views and share data models between them. |
ViewController
class:initialize()
method. This method is defined in the FXML API and will be called whenever a controller is created by an FXMLLoader
. Because all fields that are annotated with @FXML
will be injected after the constructor of the controller is called, this method needs to be used to access the injected fields.RadioButton
instances to the application. When talking about RadioButton
controls, I introduced the ToggleGroup
class. This is the class used in this application to group the RadioButton
controls. Each of the radio buttons defines a custom shape as its userData
: One holds a Rectangle
instance, one holds a Circle
instance, and one holds a Text
instance. All three radio buttons are part of the same ToggleGroup
. Whenever the selection of the group changes, the updateShape()
method will be called. This is done with a ChangeListener
that is added to the selectedToggle
property of the group. In this method, the shape that is defined as the user data of the selected radio button will be added to the screen.initialize()
method define some binding between properties of controls. I placed a TextField
next to each of the slides in order to define the RGB value of the shape’s fill color. The text of these fields is bound to the current value of the slider. Whenever a user changes the slider, the text value of the text field will update automatically. In addition, the shape can be transformed by wrapping it in a pane that is defined by the private StackPane canvas
field. The rotate
and scale
properties of this pane are bound to the values of sliders. The user can change these sliders to change the transform of the shape.ChangeListener
instances to the value
property of each slider in order to change the color of the shape. I did this for the two CheckBox
instances (invert color and saturation) too. The listeners are defined as lambda expressions and call the updateShape()
method whenever the value of the property is changed. This method creates the displayed shape and sets its fill to the defined color.Control
class and general controls and showed sample illustrations for all the basic JavaFX controls and their features. I explained the most important properties and methods of each control so you have insight into the endless possibilities these controls offer. As a more complex example, you saw an application that uses a lot of these features internally. JavaFX offers a huge set of additional nodes and controls beyond these basics that can be used to create modern applications that handle and visualize huge sets of data. You will look at these additional controls in the following chapter.3.137.220.92