image
CHAPTER
5
JavaFX Basic Controls
JavaFX 8 provides a huge set of default controls that you can use to create modern desktop applications. Because there are so many, it will take two chapters to cover all of them. This chapter will cover the 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.
The Control Class
All controls in JavaFX extend the abstract 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.
image
image
image
FIGURE 5-1.Simplified dependency hierarchy of controls
As you can see in Figure 5-1, the 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.
The 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.
image
TABLE 5-1.Properties of the Control Class
Controls in JavaFX are classified in two types: basic controls (for example, a button or a text field) and complex controls (for example, a table or a tree). For now, it’s important to understand basic controls before moving on to more complex commands in the next chapter.
Basic Controls
Most developers will be familiar with basic controls because most UI toolkits rely on these controls. The basic controls in JavaFX include the following:
imageButton
imageCheckBox
imageHyperlink
imageToggleButton
imageRadioButton
imageLabel
imageTextField
imagePasswordField
imageTextArea
imageProgressIndicator
imageProgressBar
imageSlider
Figure 5-2 shows a window that includes a sample of each of these 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.
image
image
image
FIGURE 5-2.Basic controls
Let’s first look at the interaction between controls by creating a demo application. The following class defines the complete application:
image
image
Most of the functions used in this application were covered in earlier chapters, but let’s take a more detailed look at what is happening here: A 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.
image
image
image
FIGURE 5-3.Login dialog created by basic controls
With JavaFX, you can use the property API to add interactions to this application using a few simple lines of code. Most attributes of the different 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:
image
image
In the first line, the 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.
image
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.
The following sections explain the specific properties and characteristics of the controls I identified as basic controls. The examples are intended to provide a general understanding of the power of JavaFX controls. An exhaustive list of properties and methods is beyond our scope, but can be found in the complete documentation available in the JavaDoc of JavaFX.
Labeled Controls
All control types that can render labeled text on their surface extend the 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:
imageCheckBox
imageHyperlink
imageToggleButton
imageRadioButton
imageButton
imageLabel
Figure 5-4 shows the class hierarchy of these classes. Controls such as menu items and table cells also extend the Labeled class, but are considered advanced controls. I’ll discuss these further in Chapter 6.
image
image
image
FIGURE 5-4.Class hierarchy of labeled controls
You may have noticed that 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.
image
TABLE 5-2.Properties of the Labeled Class
The following code snippet uses a handful of these properties to define a custom button:
image
image
The button that is defined by the snippet can be used in any scene graph as shown in earlier examples. As you can see in Figure 5-5, the button looks different from any buttons shown previously. Both the font and the position of the text in the control have changed. I used the 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.
image
image
image
FIGURE 5-5.Customized button control
Besides custom alignment and text style, the 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.
image
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
The 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 and Button
The 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:
imagevoid arm() Arms the button
imagevoid disarm() Disarms the button
imagevoid fire() Fires the button
Because the ButtonBase class extends Labeled, the text that is part of each control that extends this class can be styled as mentioned earlier.
The most common implementation of the 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:
imagecancelButton  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.
imagedefaultButton  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  In most UI toolkits, a 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.
image
TABLE 5-3.States of a CheckBox
The 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:
imageselected  Indicates whether this CheckBox is checked
imageindeterminate  Determines whether the CheckBox is in the indeterminate state
imageallowIndeterminate  Defines whether indeterminate is used
Hyperlink  The Hyperlink 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 and ToggleButton  Besides the 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:
image
image
Because both controls are part of the same group, only one of them can be selected. The 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:
image
image
image
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.
The 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.
Controls for Text Input
JavaFX contains a set of controls that can be used to enter text on the screen. These controls extend the abstract class 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.
image
TABLE 5-4.Properties of the TextInputControl Class
Using the caret allows you to position text within the containing text. To set the position of the caret, the 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.
image
image
TABLE 5-5.Methods of the TextInputControl Class
The most common implementation of the 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.
image
TABLE 5-6.Properties of the TextField Class
The 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.
The next text input control is the 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.
image
TABLE 5-7.Properties of the TextArea Class
The following application uses some of the features of text input controls. In the example, you can use a menu to change the caret position of the TextField.
image
image
image
In the application, I define a 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.
image
image
image
FIGURE 5-6.Demo of a TextArea control
The demo application can be created with buttons in the menu, too. To do so, you need a special type of button that doesn’t request the focus when it is clicked. You do this by extending the Button class. In this case, the requestFocus() method should do nothing:
image
image
The button that is defined is rendered like a normal button. It can be clicked to fire an action event, but the button will never request the focus of the current window. The label instances in the previous sample can be changed to this special button to provide a more typical user experience.
Slider
The 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.
image
TABLE 5-8.Properties of the Slider Class
In addition to properties, the 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.
By using properties, you can customize instances of the 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:
image
image
image
As you can see in Figure 5-7, the two sliders look different: The orientation is varied, the tick marks are customized, and the slider ranges are completely different. The first slider has only a few tick marks that are labeled with custom text showing the values of the marks in degrees Celsius. This was accomplished using a StringConverter instance. The second slider shows many unlabeled tick marks.
image
image
image
FIGURE 5-7.Two visual representations of the Slider control
image
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
You can use the 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.
The following application defines a background task by using the javafx.concurrent API and uses a ProgressIndicator and a ProgressBar to visualize the state of the task:
image
image
When the application starts, the two progress indicators are shown with infinite progress because the default value of 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.
image
image
image
FIGURE 5-8.States of the ProgressIndicator and ProgressBar
image
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 of a Control
Each control in JavaFX offers a 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.
image
TABLE 5-9.Methods of the Tooltip Class
The following application demonstrates how the 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.
image
image
Figure 5-9 shows the result of this code. Here, the tooltip pop-up of the Circle label instance is shown. The size of the tooltip is calculated by the preferred size of its content. As you can see, the tooltip contains a Circle shape instead of plain text. This is accomplished by setting a shape as the graphics object of the tooltip within the code. Although the tooltip currently contains no text, custom text can be added in addition to the shape.
image
image
image
FIGURE 5-9.A custom tooltip
image
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.
Using Menus in JavaFX
In addition to the 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:
image  A MenuBar that is integrated in a window
image  A ContextMenu that is shown as a pop-up for a control
image  A system menu bar like in Mac OS
JavaFX provides two Control classes that can be used as containers for a menu: the MenuBar and the ContextMenu. This chapter will cover both types.
A 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.
A 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:
image
image
As you can see in the code, I added two different items to the 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.
image
image
image
FIGURE 5-10.A context menu
As already shown in the example application, the 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.
image
TABLE 5-10.Methods of the ContextMenu
JavaFX contains the following item types that can be added to a menu:
imageMenuItem
imageRadioMenuItem
imageTabMenuItem
imageCheckMenuItem
imageCustomMenuItem
imageSeparatorMenuItem
imageMenu
The 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:
image
image
When running the application, the window will contain a menu bar that holds all the defined menu items.
image
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.
Using Separators
The 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.
image
image
image
FIGURE 5-11.Using a separator
image
image
The 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:
image
image
Creating an Application with Basic Controls
Now that I have covered most of the basic controls in JavaFX, I’ll show how to create a more complex application that utilizes the features discussed, as well as introducing new features, like FXML.
As you recall, it is best practice to define the views of a more complex application in FXML. By using Scene Builder, I created the following application in only a few minutes. Scene Builder is a WYSIWYG editor for FXML, and because an FXML file contains all the information about the alignment and layout of nodes in a view, it can become quite huge. In fact, the FXML for the application shown here is too large to print in full. I will rely on code snippets here, but you can access the complete code by following the instructions in the Introduction of this book. Thanks to Scene Builder, it’s not necessary that developers know how an FXML file has to be defined, but you should know how to read an FXML file and understand its syntax and content. This will be helpful for finding bugs or tracking down layout issues in an application. The following code shows a basic FXML file. It defines the content of the FXML file that creates the login dialog that was shown at the beginning of the chapter.
image
image
As you can see in the XML, all nodes of the view and its hierarchy are defined as XML tags. In addition, the initial values of properties are defined as XML attributes in these tags.
Figure 5-12 shows the application that was completely designed with Scene Builder. It is a demo application that can be used to change the visual nature of a simple shape. With the use of the controls discussed in this chapter, the user can customize the shape and some of its properties.
image
image
image
FIGURE 5-12.An application created with basic controls
When creating a JavaFX application with the help of Scene Builder and FXML, it is best to use the Model-View-Control (MVC) pattern. This pattern separates the model, the controller, and the view of an application. In JavaFX, the view will usually be created in FXML. This is done for the demo application, too. In the FXML file, all needed properties of the shown controls are defined with initial values. As an example, the definitions of the three labels that name the color sliders are shown here:
image
image
For each of the three labels, an initial value for the text property is set in FXML. In addition, some layout properties are defined to position the labels in its parent pane. In the application, the labels and sliders are wrapped in a 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:
image
image
The FXML tags that define the three sliders contain one new attribute. In addition to the initial values for all the properties and the layout information, the 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:
image
image
The 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.
In JavaFX and FXML, the view defines its specific controller class. This is done in the FXML file as an attribute of the topmost node. In the example, a BorderPane is used as the rootNode, and the ViewController class is defined in its fx:controller attribute:
image
image
Once this is done, JavaFX can easily load the combination of view and controller. You just need to create a main class for the application that loads the FXML with an FXMLLoader instance and adds its root node to the scene, as shown here:
image
image
Because the controller class is currently named in the FXML file, you don’t need to define the controller in the Java code. If you place the 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.
image
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.
The complete logic and interaction of the application is defined in the controller. The following shows the complete code of the ViewController class:
image
image
image
When the application starts, you can use the controls in the menus to change the look of the shape that is shown in the top part of the application. Let’s take a look at how this is done in the controller class. The first thing that is new is the 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.
The user can change the shape shown in the top of the application. To do this, I added three 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.
The next lines of the 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.
In addition, I added 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.
Even if this example contains only two Java classes and an FXML file, it is the most complex application I have shown until now. In the code, you can see how easily you can separate the view and controller in Java. The application is created with only panes and a set of basic controls. For the interaction of the application, you define bindings and listeners. In other UI toolkits, coding the same application would have presented a number of problems, including workarounds or special APIs to define bindings; in addition, the complete layout of the application would need to be done in Java code. Using functional interfaces in JavaFX allows you to drastically reduce the amount of boilerplate code.
Summary
This chapter showed you how to use basic controls in JavaFX. I covered the elementary concepts of the 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.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.220.124.177