Written by Jonathan Giles
When JavaFX first shipped back in 2007, it did not have any user interface controls available for users to put into their user interfaces. Developers had to settle for either creating their own rudimentary UI controls or importing UI components from the Swing toolkit that also ships with Java. Starting with JavaFX 1.2, this situation started to improve, with the introduction of a number of critically important UI controls, such as Button, ProgressBar, and ListView. In subsequent releases, JavaFX began to attain a complete and well-regarded set of UI controls, providing the ability to construct user interfaces for applications that one would find inside a corporate environment.
This chapter will introduce most of the UI controls that exist in the core JavaFX 11 release. Due to the limited number of pages available in this chapter, the code samples are kept intentionally brief. Rest assured that the code repository for this book includes a comprehensive demo application that covers all JavaFX UI controls, with code that can be copy/pasted into your own applications.
The UI Controls Module
javafx.scene.chart: This package houses the charting components for building charts such as line, bar, area, pie, bubble, and scatter charts. These will not be covered as part of this chapter.
javafx.scene.control: This package houses the APIs for almost all user interface controls in JavaFX. This is the primary package we will cover in this chapter.
javafx.scene.control.cell: This package houses the APIs for a large number of pre-built “cell factories,” which we will cover in more depth when we get to the “Advanced Controls” section later in this chapter.
javafx.scene.control.skin: This package houses the “skins,” or the visual components, for each UI control. We won’t be covering this package in this chapter as it is beyond the scope of this book.
What Is a UI Control?
A valid question to ask in the context of JavaFX is: What exactly is a UI control? A simple definition might be that it is a visual component that forms a small part of a user interface and which is often interactive (but not always). In the strictest sense, a UI control extends from the Control class, but a more relaxed definition would allow for any component that extends from Node to be considered a UI control. For the sake of this chapter, most of the UI controls being discussed extend from the Control class.
This inevitably leads to the next question: What is the Control class? Control is a class that extends from Parent, which itself extends from Node. In the commonly referenced MVC2 nomenclature, a Control can be thought of as the model. In any user interface built using JavaFX UI controls, a developer should only ever interact with the Control classes, as these are where all API exists for manipulating and reading the state of the control.
Because the Control class extends from Node, it is afforded all abilities that Node has. This means a UI control can have effects, rotation, scaling, and numerous other properties modified, as necessary. Event handlers for mouse, swipe, drag, touch, key input, and more can also be added in the standard fashion. Adding UI controls to a scene graph is also handled in the same fashion as any Node – by adding it to a layout container with the relevant sizing information, layout constraints, and so on.
As of JavaFX 9, and as noted previously, the visuals of all UI controls, known as the skins, have also become public API in the javafx.scene.control.skin package. The reason the skins are public API is to enable developers to subclass them and to therefore override the default visuals of a UI control.
JavaFX Basic Controls
- 1.
"Labeled" controls: Button, CheckBox, Hyperlink, Label, RadioButton, and ToggleButton
- 2.
"Text input" controls: TextField, TextArea, and PasswordField
- 3.
"Other" simple controls: ProgressBar, ProgressIndicator, and Slider
Labeled Controls
Most controls that display read-only text extend from a common abstract superclass known as Labeled. This class specifies a common set of properties for handling alignment, fonts, graphic (and graphic positioning), wrapping, and so on, as well as, of course, for the text to be displayed itself. Because Labeled is abstract, it is not commonly used directly, but many of the actual UI controls extend from it, including Button, CheckBox, Hyperlink, Label, RadioButton, and ToggleButton. In addition to these basic controls, other more advanced controls (to be covered later in this chapter) also benefit from Labeled, including MenuButton, TitledPane, and ToggleButton.
Properties of the Labeled class
Property | Type | Description |
---|---|---|
alignment | ObjectProperty<Pos> | Specifies how the text and graphic should be aligned. |
contentDisplay | ObjectProperty<ContentDisplay> | Specifies the positioning of the graphic relative to the text. |
font | ObjectProperty<Font> | The default font to use for text. |
graphic | ObjectProperty<Node> | An optional icon for the Labeled. |
textAlignment | ObjectProperty<TextAlignment> | Specifies the behavior for lines of text when text is multiline. |
text | StringProperty | The text to display in the label. |
wrapText | BooleanProperty | Specifies whether text should wrap into multiple lines when width is exceeded. |
As noted, because the Labeled control is abstract, most developers do not use this class directly. Instead, they use one of the concrete subclasses that ship with JavaFX, which will be detailed in more depth now.
Label
Because Labeled is so comprehensive, the concrete Label class is extremely simple – it only adds one additional piece of API. This is called labelFor and is used to make keyboard navigation into UI controls using mnemonics simpler, as well as to improve text-to-speech output for people who are blind and partially sighted. It is best practice, when using a Label to describe another control (e.g., a Slider), to associate the Label instance with the Slider instance by saying label.labelFor(slider), for example. This means that when focus is given to the Slider control, the screen reading software for people with full or partial blindness can read out the text of the Label to help describe to users what the Slider is used for.
Button
Properties of the Button (and ButtonBase) class
Property | Type | Description |
---|---|---|
armed | ReadOnlyBooleanProperty4 | Indicates whether the user is currently pressing the button. |
cancelButton | BooleanProperty | If true, the button will handle Escape key presses. |
defaultButton | BooleanProperty | If true, the button will handle Enter key presses. |
onAction | ObjectProperty<EventHandler<ActionEvent>> | A callback that is executed when a Button is fired. |
Creating a JavaFX Button instance that handles clicks by printing to the console
CheckBox
Typically, a CheckBox enables a user to specify whether something is true or false. In JavaFX this is possible, but there is also the ability to show a third state: indeterminate. By default, the JavaFX CheckBox will toggle between checked and unchecked states only (and this is reflected in the selected property). To support toggling through the indeterminate state, developers must set the allowIndeterminate property to true. When this is enabled, the indeterminate property can be read, in conjunction with the selected property, to determine the state of the CheckBox.
Properties of the CheckBox class
Property | Type | Description |
---|---|---|
allowIndeterminate | BooleanProperty | Determines if the CheckBox should toggle into the indeterminate state. |
indeterminate | BooleanProperty | Specifies whether the CheckBox is currently indeterminate. |
selected | BooleanProperty | Specifies whether the CheckBox is currently selected. |
Creating a CheckBox instance that is determinate (i.e., only toggles between selected and unselected)
Hyperlink
Properties of the Hyperlink class
Property | Type | Description |
---|---|---|
visited | BooleanProperty | Toggles to true when the hyperlink has been fired for the first time by the user. |
Creating a Hyperlink instance and listening for it to be clicked
ToggleButton
ToggleButton is a Button (meaning that it can still fire action events), but generally this is not the best approach to take. This is because the intent of a ToggleButton is to toggle its selected property state between being selected and unselected, once per click. When a ToggleButton is selected, its visual appearance is different, appearing to be “pushed in.” ToggleButton instances may be added to a ToggleGroup to control selection.
What is a ToggleGroup?
ToggleGroup is a class that simply contains a list of Toggle instances for which it manages their selected state. ToggleGroup ensures that at most only one Toggle can be selected at a time.
Toggle is an interface with two properties – selected and toggleGroup. Classes that implement this interface include ToggleButton, RadioButton, and RadioMenuItem.
How do I use ToggleButton and ToggleGroup?
What this all boils down to then is that a ToggleButton may be associated with a ToggleGroup by instantiating a ToggleGroup instance, and multiple ToggleButton instances, and setting the toggleGroup property on each ToggleButton to be the single ToggleGroup instance. This is shown in Listing 4-4.
Properties of the ToggleButton class
Property | Type | Description |
---|---|---|
selected | BooleanProperty | Indicates whether the toggle is selected. |
toggleGroup | ObjectProperty<ToggleGroup> | The ToggleGroup to which this ToggleButton belongs. |
Creating three ToggleButtons and adding them to a single ToggleGroup and listening to selection changes
RadioButton
RadioButton is a ToggleButton, with a different styling applied and a slightly different behavior when placed in a ToggleGroup. Whereas ToggleButtons in a ToggleGroup can be all unselected, in the case of RadioButtons in a ToggleGroup, there is no way for a user to unselect all RadioButtons. This is because, visually, a RadioButton can only be clicked to enter the selected state. Subsequent clicks have no effect (certainly it does not result in unselection). Therefore, the only way to unselect a RadioButton is to select a different RadioButton in the same ToggleGroup.
Because the API for RadioButton is essentially equivalent to ToggleButton, please refer to Listing 4-4 for the ToggleButton code sample. The only difference is to replace ToggleButton instances with RadioButton instances.
Text Input Controls
The next set of controls to cover, after the simple Labeled controls, are the three controls primarily used for text input, namely, TextArea, TextField, and PasswordField. TextField is designed to receive single-line input from users, whereas TextArea is designed to receive multiline input. PasswordField extends from TextField, enabling users to enter sensitive information by masking user input. In all three cases, these controls do not accept rich text input (see the HTMLEditor control later in this chapter for one option for rich text input).
Properties of the TextInputControl class
Property | Type | Description |
---|---|---|
anchor | ReadOnlyIntegerProperty | The anchor of the text selection. The range between anchor and caret represents the text selection range. |
caretPosition | ReadOnlyIntegerProperty | The current position of the caret within the text. |
editable | BooleanProperty | Whether the user can edit the text in the control. |
font | ObjectProperty<Font> | The font to use to render the text. |
length | ReadOnlyIntegerProperty | The number of characters entered in the control. |
promptText | StringProperty | Text to display when there is no user input. |
selectedText | ReadOnlyStringProperty | The text that has been selected in the control, via mouse or keyboard or programmatically. |
textFormatter | ObjectProperty<TextFormatter<?>> | See section “TextFormatter.” |
text | StringProperty | The textual content of this control. |
TextFormatter
- 1.
A filter that can intercept and modify user input. This helps to keep the text in the desired format. A default text supplier can be used to provide the initial text.
- 2.
A value converter and value can be used to provide special format that represents a value of type V. If the control is editable and the text is changed by the user, the value is then updated to correspond to the text.
It’s possible to have a formatter with just filter or value converter. If value converter is not provided however, setting a value will result in an IllegalStateException, and the value is always null.
TextField, PasswordField, and TextArea
Creating and using a TextField control
PasswordField functions in exactly the same way as TextField, except that it obscures the user input so that there is some degree of security from prying eyes behind the user. In addition, for security reasons, the PasswordField does not support cut and copy operations (paste is still valid however). There are no additional properties or API on PasswordField.
Properties of the TextArea class
Property | Type | Description |
---|---|---|
prefColumnCount | IntegerProperty | Preferred number of text columns. |
prefRowCount | IntegerProperty | Preferred number of text rows. |
wrapText | BooleanProperty | Whether to wrap text or let the TextArea scroll horizontally when a line exceeds the width available. |
Other Simple Controls
Beyond the Labeled controls and the text input controls, there are three other controls that can be considered “simple”: ProgressBar, ProgressIndicator, and Slider.
ProgressBar and ProgressIndicator
JavaFX offers two UI controls for displaying progress to users: ProgressBar and ProgressIndicator . They are very closely related in terms of API, as ProgressBar extends ProgressIndicator and adds no additional API. The most important properties for ProgressIndicator are shown in Table 4-8.
Both controls can be used to display progress or can be set into indeterminate state to indicate to the user that work is proceeding, but that the progress is unknown at this point in time.
To show progress, developers should set the progress property to a value between 0.0 and 1.0. This at first may appear counterintuitive – why use a range between 0.0 and 1.0, instead of a range of 0–100? The answer isn’t clear that this was a conscious design choice throughout the entire JavaFX UI toolkit whenever dealing with percentages. To make the progress controls switch to their indeterminate form, simply set the progress property value to -1. When this is done, the indeterminate property will change from false to true.
Properties of the ProgressIndicator class
Property | Type | Description |
---|---|---|
indeterminate | ReadOnlyBooleanProperty | A boolean flag indicating if the indeterminate progress animation is playing. |
progress | DoubleProperty | The actual progress (between 0.0 and 1.0), or can be set to -1 for indeterminate. |
Creating a ProgressBar that will show 25% progress
Slider
Properties of the Slider class
Property | Type | Description |
---|---|---|
blockIncrement | DoubleProperty | How much the Slider moves if the track is clicked. |
max | DoubleProperty | The maximum value represented by the Slider. |
min | DoubleProperty | The minimum value represented by the Slider. |
orientation | ObjectProperty<Orientation> | Whether the Slider is horizontal or vertical. |
value | DoubleProperty | The current value represented by the Slider. |
Creating a Slider that will have a range between 0.0 and 1.0
Container Controls
Now that we have worked through the simple UI controls, we can move on to some more exciting controls. This section will be covering “container” controls, or controls that are used to contain and display other user interface elements. These container controls provide some additional functionality, be it the ability to collapse their content, offer a tabbed interface to change views, or something else.
Accordion and TitledPane
TitledPane is a container that displays a title area and a content area and has the ability to expand and collapse the content area by clicking on the title area. This is useful for side panels and the like in a user interface in that it allows for information to be displayed but optionally collapsed by users, such that they only see what they need to see.
Properties of the TitledPane class
Property | Type | Description |
---|---|---|
animated | BooleanProperty | Whether the TitledPane animates as it expands and collapses. |
collapsible | BooleanProperty | Whether the TitledPane can be collapsed by the user. |
content | ObjectProperty<Node> | The Node to display in the content area of the TitledPane. |
expanded | BooleanProperty | Whether the TitledPane is currently expanded or not. |
text | StringProperty | The text to show in the header area of the TitledPane. |
With TitledPane introduced, we can move on to Accordion, which is a control that is simply a container of zero or more TitledPanes. When an Accordion is displayed to the user, it only allows for one TitledPane to be expanded at any time. Expanding a different TitledPane will result in the currently expanded TitledPane being collapsed.
Properties of the Accordion class
Property | Type | Description |
---|---|---|
expandedPane | ObjectProperty<TitledPane> | The currently expanded TitledPane in the Accordion. |
To add TitledPanes to the Accordion, we use the getPanes() method to retrieve the ObservableList of TitledPanes, and we add the applicable TitledPanes into this list. The result of doing this will be that the TitledPanes will be displayed stacked vertically in the order that they appear within this list. A code example of this is shown in Listing 4-8.
Creating three TitledPanes and adding them all to a single Accordion
ButtonBar
Properties of the ButtonBar class
Property | Type | Description |
---|---|---|
buttonMinWidth | DoubleProperty | The minimum width of all buttons placed in the ButtonBar. |
buttonOrder | StringProperty | The ordering of buttons in the ButtonBar. |
Creating a ButtonBar with “Yes” and “No” buttons. Ordering will depend on the operating system that this code is executed on
ScrollPane
ScrollPane is a control that is crucial to almost every user interface – the ability to scroll horizontally and vertically when content extends beyond the bounds of the user interface. For example, imagine an image manipulation program such as Adobe Photoshop. In this user interface, you may zoom in to work on a tiny section of your drawing, and the horizontal and vertical scrollbars allow for you to move this section around to see adjoining sections.
Properties of the ScrollPane class
Property | Type | Description |
---|---|---|
content | ObjectProperty<Node> | The Node to be displayed. |
fitToHeight | BooleanProperty | Will attempt to keep content resized to match height of viewport. |
fitToWidth | BooleanProperty | Will attempt to keep content resized to match width of viewport. |
hbarPolicy | ObjectProperty<ScrollBarPolicy> | Sets policy for when to show horizontal scrollbars. |
hmax | DoubleProperty | The maximum allowed hvalue. |
hmin | DoubleProperty | The minimum allowed hvalue. |
hvalue | DoubleProperty | The current horizontal position of the ScrollPane. |
vbarPolicy | ObjectProperty<ScrollBarPolicy> | Sets policy for when to show vertical scrollbars. This can be one of the enum constants in ScrollPane.ScrollBarPolicy: ALWAYS, AS_NEEDED, or NEVER |
vmax | DoubleProperty | The maximum allowed vvalue. |
vmin | DoubleProperty | The minimum allowed vvalue. |
vvalue | DoubleProperty | The current vertical position of the ScrollPane. |
Creating a ScrollPane instance
SplitPane
The SplitPane control accepts two or more children and draws them with a draggable divider between them. The user is then able to use this divider to give more space to one child, at the cost of taking space away from the other child. A SplitPane control is great for user interfaces where there is a main content area, and then an area on the left/right/bottom of the content area is used to display more context-specific information. In this scenario, the user may give additional space to the main content area or the context-specific area as necessary.
Historically, UI toolkits have only supported two children (i.e., a “left” and a “right” or a “top” and a “bottom”), but JavaFX removed this restriction and allows for an unlimited number of children, with one restriction: all children must have the same divider orientation. This means that a SplitPane only has one orientation property for all dividers (as shown in Table 4-14). There is however a way around this: simply embed SplitPane instances inside each other, such that the end result consists of dividers operating both horizontally and vertically in the desired order.
The SplitPane control observes the minimum and maximum size properties of its children. It will never reduce the size of a node below its minimum size and will never give it more size than its maximum size. For this reason, it is recommended that all nodes added to a SplitPane be wrapped inside a separate layout container, such that the layout container may handle the sizing of the node, without impacting the SplitPane’s ability to function.
A divider’s position ranges from 0 to 1.0 (inclusive). A position of 0 will place the divider at the left-/topmost edge of the SplitPane plus the minimum size of the node. A position of 1.0 will place the divider at the right-/bottommost edge of the SplitPane minus the minimum size of the node. A divider position of 0.5 will place the divider in the middle of the SplitPane. Setting the divider position greater than the node’s maximum size position will result in the divider being set at the node’s maximum size position. Setting the divider position less than the node’s minimum size position will result in the divider being set at the node’s minimum size position.
Properties of the SplitPane class
Property | Type | Description |
---|---|---|
orientation | ObjectProperty<Orientation> | The orientation of the SplitPane. |
Creating a SplitPane instance with three children (and therefore two dividers)
TabPane
TabPane is a UI control that enables for tabbed interfaces to be displayed to users. For example, most readers will be familiar with the tabbed interface in their preferred web browser, so that they do not need to have multiple windows open – one for each page that they wish to have open.
- 1.
UNAVAILABLE: Tabs cannot be closed by the user.
- 2.
SELECTED_TAB: The currently selected tab will have a small close button in the tab area (shown as a small “x”). When a different tab is selected, the close button will disappear from the previously selected tab and instead be shown on the newly selected tab.
- 3.
ALL_TABS: All tabs visible in the TabPane will have the small close button visible.
Properties of the TabPane class
Property | Type | Description |
---|---|---|
rotateGraphic | BooleanProperty | Whether graphics should rotate to display appropriately when tabs are placed on the left/right side. |
selectionModel | ObjectProperty<SingleSelectionModel> | The selection model being used in the TabPane.5 |
side | ObjectProperty<Side> | The location at which tabs will be displayed. |
tabClosingPolicy | ObjectProperty<TabClosingPolicy> | Described in the preceding text. |
How to instantiate and use a TabPane
ToolBar
The ToolBar control is a very simple UI control. In its most common permutation, it can be thought of as a stylized HBox – that is, it presents whatever nodes are added to it horizontally, with a background gradient. The most common elements to add to a ToolBar are other UI controls such as Button, ToggleButton, and Separator, but there is no restriction on what can be placed within a ToolBar, as long as it is a Node.
The ToolBar control does offer one useful piece of functionality – it supports the concept of overflow, so that if there are more elements to be displayed than there is space to display them all, it removes the “overflowing” elements from the ToolBar and instead shows an overflow button that when clicked pops up a menu containing all overflowing elements of the ToolBar.
As noted in Table 4-16, ToolBar offers a vertical orientation, so that it may be placed on the left- or right-hand side of an application user interface, although this is not as common as being placed at the top of the user interface, typically just below the menu bar.
Properties of the ToolBar class
Property | Type | Description |
---|---|---|
orientation | ObjectProperty<Orientation> | Whether the ToolBar should be horizontal or vertical. |
Instantiating a ToolBar with multiple Button and Separator instances
Other Controls
HTMLEditor
The HTMLEditor control enables users to create rich text input that is internally formatted as HTML content. The control provides a number of UI controls to specify font size, color, and type, as well as alignment and so on.
One point to note about the HTMLEditor control is that, because it is dependent on the JavaFX WebView component for rendering the user input, this control does not ship in the javafx.controls module, but rather the javafx.web module, and within that it can be found in the javafx.scene.web package.
Despite the large amount of functionality offered to the end user, there is surprisingly little API available to the developer using HTMLEditor. There are no relevant properties, and the only relevant methods are the getter and setter methods for htmlText. These methods operate with a String, and it is expected that this String consists of valid HTML.6
Pagination
The simplest way to understand the Pagination control is to think of the Google search results page, with the “Gooooooooogle” text at the bottom and the numbers “1, 2, 3,…10.” Each of these numbers represents a page of results, and the user may click these to be taken to that page. Of importance is the fact that Google doesn’t predetermine the elements to place on any page other than the current page – the rest of the pages are only determined when they are requested.
This is precisely the functionality that Pagination offers in JavaFX. The key properties of the pagination class are shown in Table 4-17. Pagination is an abstract way of representing multiple pages, where only the currently showing page actually exists in the scene graph and all other pages are only generated upon request.
Properties of the Pagination class
Property | Type | Description |
---|---|---|
currentPageIndex | IntegerProperty | The current page index being displayed. |
pageCount | IntegerProperty | The total number of pages available to be displayed. |
pageFactory | ObjectProperty<Callback<Integer,Node>> | Callback function that returns the page corresponding to the given index. |
Instantiating a Pagination control with ten pages
ScrollBar
The ScrollBar control is essentially a Slider control with a different style. It consists of a track over which a thumb can be moved, as well as buttons at either end of incrementing and decrementing the value (and thus moving the thumb). ScrollBar typically is not used in the same circumstances as Slider however – instead, it is typically used as part of a more complex UI control. For example, it is used in the ScrollPane control to support vertical and horizontal scrolling and is used in the ListView, TableView, TreeView, and TreeTableView controls discussed later.
Properties of the ScrollBar class
Property | Type | Description |
---|---|---|
blockIncrement | DoubleProperty | How much the thumb moves if the track is clicked. |
max | DoubleProperty | The maximum allowed value. |
min | DoubleProperty | The minimum allowed value. |
orientation | ObjectProperty<Orientation> | Whether the ScrollBar is horizontal or vertical. |
unitIncrement | DoubleProperty | The amount to adjust the value when increment/decrement methods are called. |
value | DoubleProperty | The current value of the ScrollBar. |
Separator
The Separator control is perhaps the simplest control in the entire JavaFX UI toolkit. It is a control that lacks any interactivity and is simply designed to draw a line in the relevant section of the user interface. This is commonly used in the ToolBar control to group buttons into subgroups, for example. A similar approach is used in popup menus, but as noted previously, in the case of menus, it is required to use SeparatorMenuItem, rather than the standard Separator control discussed here.
By default, a Separator is oriented vertically such that is draws appropriately when placed in a horizontal ToolBar. This can be controlled by modifying the orientation property.
Spinner
The Spinner control was introduced to JavaFX relatively recently, in JavaFX 8u40. A Spinner can be thought of as a single-line TextField that may or may not be editable, with the addition of increment and decrement arrows to step through some set of values. Table 4-19 introduces the most critical properties of this control.
Properties of the Spinner class
Property | Type | Description |
---|---|---|
editable | BooleanProperty | Whether text input is able to be typed by the user. |
editor | ReadOnlyObjectProperty<TextField> | The editor control used by the Spinner. |
promptText | StringProperty | The prompt text to display when there is no user input. |
valueFactory | ObjectProperty<SpinnerValueFactory<T>> | As discussed in the preceding text. |
value | ReadOnlyObjectProperty<T> | The value selected by the user. |
Creating a Spinner with an integer value factory
Tooltip
Tooltips are common UI elements which are typically used for showing additional information about a Node in the scene graph when the Node is hovered over by the mouse. Any Node can show a tooltip. In most cases, a Tooltip is created, and its text property is modified to show plain text to the user. However, a Tooltip is able to show within it an arbitrary scene graph of nodes – this is done by creating the scene graph and setting it inside the Tooltip graphic property.
Adding a Tooltip to any Node in the JavaFX scene graph
This tooltip will then participate with the typical tooltip semantics (i.e., appearing on hover and so on). Note that the Tooltip does not have to be uninstalled: it will be garbage collected when it is not referenced by any Node. It is possible to manually uninstall the tooltip, however, in much the same way.
A single tooltip can be installed on multiple target nodes or multiple controls.
Adding a Tooltip to a UI control using convenience API
Properties of the Tooltip class
Property | Type | Description |
---|---|---|
graphic | ObjectProperty<Node> | An icon or arbitrarily complex scene graph to display within the Tooltip popup. |
text | StringProperty | The text to display within the Tooltip popup. |
wrapText | BooleanProperty | Whether to wrap text when it exceeds the Tooltip width. |
Popup Controls
JavaFX ships with a comprehensive set of controls that “pop up.” What this means is that, behind the scenes, they are placed in their own window that is separate from the main stage of the user interface, and as such they may appear outside of the window in situations whether they are taller or wider than the window itself. Developers do not need to concern themselves with the placement, sizing, or any detail related to this, but it is a useful detail to understand.
This section covers all UI controls in JavaFX that make use of this popup functionality. For many of them, they also make use of the same APIs for building menus, so we will firstly cover this common functionality, before talking about each control in turn.
Menu-Based Controls
Menu and MenuItem
Building a menu in JavaFX starts with the Menu and MenuItem classes. Both classes are notable for not actually extending Control, which is because they are designed to represent a menu structure, but the implementation is handled behind the scenes by JavaFX.
MenuItem acts essentially in the same fashion as a Button does. It supports a similar set of properties – text, graphic, and onAction. On top of this, it adds support for specifying keyboard accelerators (e.g., Ctrl-c). These are detailed in Table 4-21.
Because MenuItem simply extends from Object, on its own it is useless and cannot be added to a JavaFX user interface in the standard way. The way in which MenuItem is used is via the Menu class, which acts as a container for MenuItem instances. The Menu class has a getItems() method that works in the standard way of most other JavaFX APIs – developers add MenuItem instances into the getItems() method, and these items will then be displayed in the Menu whenever it is displayed to the user.
- 1.
How does JavaFX support nested menus (i.e., where a menu contains a submenu, which itself may contain more submenus)? This is handled simply by the fact that the Menu class itself extends from MenuItem. This means that whenever the API allows for a MenuItem, it implicitly supports Menu as well.
- 2.
How does JavaFX support menu items with checkboxes or radio states? JavaFX ships with two subclasses – CheckMenuItem and RadioMenuItem – that support this. CheckMenuItem has a selected property that will toggle between true and false every time the user clicks the menu item. RadioMenuItem functions in a similar fashion to RadioButton – it should be associated with a ToggleGroup, and then JavaFX will enforce that at most one RadioMenuItem will be selected at any one time.
- 3.
How do I separate menu items into groups? The common way this is handled in user interfaces is with separators. As mentioned earlier in this chapter, it is not possible to add a Separator directly into a Menu (as it does not extend from MenuItem), and so for this reason JavaFX ships with SeparatorMenuItem, which places a Separator into the Menu at the position the SeparatorMenuItem is placed inside the Menu items list.
- 4.What about custom menu elements? What if I want to show a Slider or a TextField in a Menu, for example? JavaFX supports this with the CustomMenuItem class. By using this class, developers can embed any arbitrary Node into the content property.Table 4-21
Properties of the MenuItem class
Property
Type
Description
accelerator
ObjectProperty<KeyCombination>
A keyboard shortcut to access this menu item.
disable
BooleanProperty
Whether the menu item should be user interactive.
graphic
ObjectProperty<Node>
The graphic to show to the left of the menu item text.
onAction
ObjectProperty<EventHandler<ActionEvent>>
The event handler to be called when the menu item is clicked.
text
StringProperty
The text to display in the menu item.
visible
BooleanProperty
Whether the menu item is visible in the menu or not.
MenuBar
So far we have covered the API required to specify a Menu, but not how it may be displayed to the user. By far, the most common way in which menus are added to a JavaFX user interface is through the MenuBar control. This class is traditionally placed at the top of the user interface (e.g., if a BorderLayout is used, it is typically set to be the top node), and it is constructed simply by creating an instance and then adding Menu instances to the list returned by calling getMenus().
On some operating systems (most notably Mac OS), it is typically quite uncommon to see a menu bar at the top of an application window, as Mac OS instead has a “system menu bar” which runs across the very top of the screen. This system menu bar is application context specific, in that it changes its content whenever the focused application changes. JavaFX supports this, and the MenuBar class has a useSystemMenuBar property that, if set to true, will remove the MenuBar from the application window and instead render the menu bar natively using the system menu bar. This will happen automatically on platforms that have a system menu bar (Mac OS), but will have no effect on platforms that do not (and in which case, the MenuBar will be positioned in the user interface however it is specified to appear by the application developer).
Creating a MenuBar with two menus (the first of which has a submenu)
MenuButton and SplitMenuButton
Another way menus are commonly shown to users in JavaFX applications is through the MenuButton and SplitMenuButton classes. These classes are quite closely related, but they do function in slightly different fashions, so we will cover them separately in the following.
MenuButton is a button-like control that, whenever clicked, will show a menu consisting of all MenuItem elements added to the items list. Because the MenuButton class extends from ButtonBase (which itself extends from Labeled), there is a significant amount of API overlap with the JavaFX Button control. For example, MenuButton has the same onAction event, as well as text and graphic properties and so on. Note however that for a MenuButton, setting onAction has no effect, as the MenuButton does not fire onAction events, because this is used instead to show a popup. Table 4-22 outlines the properties introduced by MenuItem, and Listing 4-19 demonstrates how to use MenuButton in code.
Properties of the MenuButton class
Property | Type | Description |
---|---|---|
popupSide | ObjectProperty<Side> | The side the context menu should be shown relative to the button. |
An example of using MenuButton
An example of using SplitMenuButton
ContextMenu
ContextMenu is a popup control that contains within it MenuItems. This means that it is never added to a scene graph and instead is called either directly (via the two show() methods) or as a consequence of a user requesting a context menu to show using common mouse or keyboard operations (most commonly via right-clicking the mouse).
Specifying a ContextMenu and adding it to a Button instance
- 1.
show(Node anchor, double screenX, double screenY): This method will show the context menu at the specified screen coordinates.
- 2.
show(Node anchor, Side side, double dx, double dy): This method will show the context menu at the specified side (top, right, bottom, or left) of the specified anchor node, with the amount of x- and y-axis shifting specified by dx and dy, respectively (also note that dx and dy can be negative if desired, but most commonly these values can simply be zero).
Adding a ContextMenu to a JavaFX Rectangle by manually showing it when requested
ChoiceBox
ChoiceBox is a JavaFX UI control that displays a popup menu when clicked, but it is not constructed through MenuItem instances. Instead, ChoiceBox is a generic class (e.g., ChoiceBox<T>), where the type of the class is also the type used for the items list. In other words, rather than have users specify menu items, a ChoiceBox is constructed with zero or more objects of type T, and these are what are displayed to the user in the popup menu.
Because the default toString() method of the T class may not be appropriate or overly human readable, ChoiceBox supports the notion of a converter property (which is of type StringConverter<T>). If a converter is specified, the ChoiceBox will take each element from the items list (which is of type T) and pass it through the converter, which should return a more human-readable string to be displayed in the popup menu.
When a user makes a selection in the ChoiceBox, the value property will be updated to reflect this new selection. When the value property changes, the ChoiceBox control also fires an onAction ActionEvent, so developers can choose whether to observe the value property or to add an onAction event handler.
Due to the UI design of ChoiceBox, this control is best suited to relatively small lists of elements. If the number of elements to display is large, it is normally recommended that developers instead use the ComboBox control.
Properties of the ChoiceBox class
Property | Type | Description |
---|---|---|
converter | ObjectProperty<StringConverter<T>> | Allows for a way to convert the visual presentation of the items list. |
items | ObjectProperty<ObservableList<T>> | The items to display in the ChoiceBox. |
selectionModel | ObjectProperty<SingleSelectionModel<T>> | The selection model for the ChoiceBox. |
showing | ReadOnlyBooleanProperty | Indicates if the ChoiceBox popup is visible. |
value | ObjectProperty<T> | The current selection in the ChoiceBox. |
Creating a ChoiceBox with four choices and a listener
ComboBox-Based Controls
Beyond the menu-based controls, there are a lot of other controls that pop up based on user interaction. This section covers a set of controls that all can be classified as controls that are “combo boxes.” In JavaFX, the controls in this set all extend from the ComboBoxBase class (whose properties are shown in Table 4-24) and are known as ComboBox, ColorPicker, and DatePicker.
They appear as a button that, when clicked, will pop up some UI that allows the user to make a selection.
There is a value property that represents the current value selected by the user.
They typically can be editable or not, by setting the editable property appropriately. When the control is editable, it displays with a TextField and a button on the side – the TextField allows for user input, and the button will show the popup. When the control is not editable, the entire control will appear as a button.
- There are show() and hide() methods to programmatically cause the popup to show itself or, if it is already showing, to hide.Table 4-24
Properties of the ComboBoxBase class
Property
Type
Description
editable
BooleanProperty
Whether the control shows a text input area to receive user input.
onAction
ObjectProperty<EventHandler<ActionEvent>>
The event handler when the user sets a new value.
promptText
StringProperty
The prompt text to display – whether it displays is dependent on the subclass.
value
ObjectProperty<T>
The latest selection (or input if editable) by the user.
ComboBox
Properties of the ComboBox class
Property | Type | Description |
---|---|---|
cellFactory | ObjectProperty<Callback<ListView<T>,ListCell<T>>> | Used to customize rendering of items. |
converter | ObjectProperty<StringConverter<T>> | Converts user-typed input (when editable) to an object of type T to set as value. |
items | ObjectProperty<ObservableList<T>> | The elements to show in popup. |
placeholder | ObjectProperty<Node> | What to show when the ComboBox has no items. |
selectionModel | ObjectProperty<SingleSelectionModel<T>> | Selection model of ComboBox. |
Creating a ComboBox with multiple choices and a listener
ColorPicker
The ColorPicker control is a specialized form of ComboBox, designed specifically to allow users to select a color value.7 The ColorPicker control does not add any additional functionality on top of ComboBoxBase, but of course the user interface is vastly different. Using a ColorPicker is very similar to the other controls, as shown in Listing 4-25.
The ColorPicker control provides a color palette with a predefined set of colors. If the user does not want to choose from the predefined set, they can create a custom color by interacting with a custom color dialog. This dialog provides RGB, HSB, and web modes of interaction, to create new colors. It also lets the opacity of the color to be modified.
Creating a ColorPicker and listening for selection changes
DatePicker
Properties of the DatePicker class
Property | Type | Description |
---|---|---|
chronology | ObjectProperty<Chronology> | Which calendar system to use. |
converter | ObjectProperty<StringConverter<LocalDate>> | Converts text input into a LocalDate and vice versa. |
dayCellFactory | ObjectProperty<Callback<DatePicker,DateCell>> | Cell factory to customize individual day cells in popup. |
showWeekNumbers | BooleanProperty | Whether the popup should show week numbers. |
Creating a DatePicker and listening for selection changes
JavaFX Dialogs
JavaFX, since the 8u40 release, has shipped with a comprehensive set of dialog APIs to alert, query, and inform users. There exists API for simply popping open an informational alert all the way through creating custom dialogs. At the simplest end of the spectrum, developers should use the Alert class to show pre-built dialogs. Developers who want to prompt a user for text input or to make a choice from a list of options would be better served by using TextInputDialog and ChoiceDialog, respectively. Completely custom dialogs can be created using the Dialog and DialogPane classes.
A modal dialog is one that appears atop another window and prevents the user from clicking that window until the dialog is dismissed.
A blocking dialog is one that causes code execution to stop at the very line that caused the dialog to appear. This means that, once the dialog is dismissed, execution continues from that line of code. This can be thought of as a synchronous dialog. Blocking dialogs are simpler to work with, as developers can retrieve a return value from the dialog and continue execution without needing to rely on listeners and callbacks.
In JavaFX, by default all dialogs are modal, but it is possible to be non-modal by using the initModality(Modality) method on Dialog. For blocking, this is up to the developer – they may choose to call showAndWait() for blocking and show() for non-blocking dialogs.
Alert
Confirmation: Best used to confirm that a user is sure before performing some action. Shows with a blue question mark image and “Cancel” and “OK” buttons.
Error: Best used to inform the user that something has gone wrong. Shows a red “X” image and a single “OK” button.
Information: Best used to inform the user of some useful information. Shows a blue “I” image (to represent “information”) and a single “OK” button.
None: This will result in no image and no buttons being set. This should rarely be used unless a custom implementation is about to be provided.
Warning: Best used to warn user of some fact or pending problem. Shows a yellow exclamation mark image and a single “OK” button.
Creating an alert, waiting to see if the user selects the OK button, and, if so, performing an action
ChoiceDialog
ChoiceDialog is a dialog that shows a list of choices to the user, from which they can pick one item at most. In other words, this dialog will use a control such as a ChoiceBox or ComboBox (it is left as an implementation detail; a developer cannot specify their preference) to enable a user to make a selection. This selection will subsequently be returned to the developer to act on as appropriate, as shown in Listing 4-28.
Creating a ChoiceDialog with default choice of “Cat” and three choices. Dialog is modal and blocking, and if the user clicks the “OK” button, output is printed to console
Properties of the ChoiceDialog class
Property | Type | Description |
---|---|---|
selectedItem | ReadOnlyObjectProperty<T> | The item that was selected by the user in the dialog. |
TextInputDialog
TextInputDialog is similar to ChoiceDialog, except rather than allow a user to make a selection from a popup list, it instead enables a user to provide a single line of text input.
Methods on the TextInputDialog class
Method | Type | Description |
---|---|---|
getEditor() | TextField | The TextField the user is shown in the dialog. |
Creating a TextInputDialog. Dialog is modal and blocking, and if the user clicks the “OK” button, their input is printed to console
Dialog and DialogPane
Dialog is the most flexible dialog option in JavaFX, enabling complete configuration of a dialog. This allows for creation of dialogs such as username/password prompts, complex forms, and similar.
When a Dialog is instantiated, developers can specify a single generic type, R, which represents the type of the result property. This is important, because it is what we as developers will receive back when the dialog is dismissed.
This may lead to the obvious question: What should the R type be? The answer is that it depends on what exactly is being asked of the user. In the case of a password prompt, it might be an instance of a UsernamePassword class, for example.
Because the Dialog class does not know about the content it is displaying and therefore does not know how to convert the values entered by the user into an instance of the R type, it is necessary for the developer to set the resultConverter property. This is required whenever the R type is not Void or ButtonType. If this is not heeded, developers will find that they get ClassCastException thrown in their code, for failure to convert from ButtonType via the result converter.
Properties of the Dialog class
Property | Type | Description |
---|---|---|
contentText | StringProperty | The main text to display. |
dialogPane | ObjectProperty<DialogPane> | The root node in the Dialog. Contains most other properties displayed here. |
graphic | ObjectProperty<Node> | The graphic to display. |
headerText | StringProperty | The text to display in the header area (above the contentText) |
result | ObjectProperty<R> | The value returned once the dialog is dismissed. |
resultConverter | ObjectProperty<Callback<ButtonType, R>> | API to convert the user button click into a result. |
title | StringProperty | The dialog title to display to the user. |
Internally, Dialog defers all layout handling of the viewable area to an embedded DialogPane instance. In fact, many of the properties simply forward on to this DialogPane.8 The DialogPane API provides a lot of additional functionality that is not exposed at the Dialog level, and developers can retrieve the currently installed DialogPane by calling getDialogPane() on the dialog instance.
Advanced Controls
The last set of controls that need to be covered are the “advanced” controls: ListView, TreeView, TableView, and TreeTableView. These controls contain the most API and also the most functionality. All four controls share a lot of common concepts, so this section will dive deeply into ListView (being the simplest of the four) and then discuss the other three controls at a higher level.
ListView
A ListView control is used to show a list of elements to a user. ListView is a generic class, so a ListView<T> is able to contain items of type T. As with most UI controls, to populate a ListView with items is incredibly easy – simply add elements of type T into the items list. The order in which elements appear in the items list will correspond to the order in which they are displayed inside the ListView.
Because ListView (as with all “advanced” controls in this section) is “virtualized,” it does not pay a performance penalty as the number of elements in the list increases. This is because, behind the scenes, a ListView only creates enough “cells” to contain the elements in the visible area of the ListView. For example, if the ListView is tall enough to fit 20 rows, the ListView may choose to create 22 cells and reuse these as the user scrolls through the list.
The ListView control has selectionModel and focusModel properties, enabling developers to control precisely what is selected and focused on in the user interface. These concepts will be covered in more depth later in the “Selection and Focus Models” section.
Properties of the ListView class
Property | Type | Description |
---|---|---|
cellFactory | ObjectProperty<Callback<ListView<T>, ListCell<T>>> | See “Cells and Cell Factories” section. |
editable | BooleanProperty | Whether the ListView supports editing cells. |
focusModel | ObjectProperty<FocusModel<T>> | Refer to the “Selection and Focus Models” section. |
items | ObjectProperty<ObservableList<T>> | The elements to show within the ListView. |
orientation | ObjectProperty<Orientation> | Whether the ListView is vertical or horizontal. |
placeholder | ObjectProperty<Node> | Text to display within the ListView if the items list is empty. |
selectionModel | ObjectProperty<MultipleSelectionModel<T>> | Refer to the “Selection and Focus Models” section. |
Cells and Cell Factories
In the advanced controls in this section (ListView, TreeView, TableView, and TreeTableView), a common aspect to their API is that they all support the concept of a “cell factory.” This is similar in concept to other factories we’ve already covered in this chapter, such as the page factory in the Pagination control.
The purpose of a cell factory is to create cells when requested by the UI control (e.g., ListView), which leads to the question: What exactly is a cell? In the JavaFX sense, it is a class that extends from the javafx.scene.control.Cell class. The Cell class is Labeled, meaning it exposes all of the API discussed at the beginning of this chapter, and a Cell is used to render a single “row” inside the ListView and other controls. Cells are also used for each individual “cell” inside TableView and TreeTableView.
Every cell is associated with a single data item (represented by the Cell item property). The cell is solely responsible for rendering this item. Depending on the cell type being used, the item may be represented as a String or by using some other UI control such as a CheckBox or Slider.
Cells are “stacked” inside a UI control like ListView, and as noted earlier, cell factories are used to generate these based on the needs of the control. But how then are cells updated when they are reused? There is a critical method called updateItem that is called by the UI control (e.g., ListView) whenever it is about to reuse a cell. When developers provide custom cell factories, it is this method that they must override, as it provides a hook in which a developer may, at the moment a cell is updated to contain new content, also update the presentation of the cell to better represent this new content.
Properties of the Cell class
Property | Type | Description |
---|---|---|
editable | BooleanProperty | Whether the Cell instance can enter an editing state. |
editing | ReadOnlyBooleanProperty | Whether the Cell is currently in an editing state |
empty | ReadyOnlyBooleanProperty | Whether the Cell has any item. |
item | ObjectProperty<T> | The object the Cell is currently representing. |
selected | ReadOnlyBooleanProperty | Whether the Cell has been selected by the user. |
There are other use cases too. Supporting editing inside a ListView is easy – when a cell enters its “editing” state, the same updateItem method is called, and inside this code a developer can choose to check the cell’s editing state, and if it is true the developer can choose to remove, for example, the text and to replace it with a TextField, allowing for custom input directly from the user.
Creating a custom ListCell subclass and overriding updateItem
Cell Editing
When a custom Cell is to be editable, we enable support for it simply by extending the updateItem method shown in Listing 4-31 to also add checks to see if the cell is being used to represent the current editing index in the control.
For many of the common cases, there already exist a number of pre-built cell factories that support editing shipping with the core JavaFX APIs, contained within the javafx.scene.control.cell package, and discussed in more detail in the next section.
Creating a ListCell that supports editing state
Pre-built Cell Factories
Pre-built cell factories
Type | Supported UI Controls |
---|---|
CheckBox | ListView, TableView, TreeView, TreeTableView |
ChoiceBox | ListView, TableView, TreeView, TreeTableView |
ComboBox | ListView, TableView, TreeView, TreeTableView |
ProgressBar | TableView, TreeTableView |
TextField | ListView, TableView, TreeView, TreeTableView |
Using a pre-built cell factory to customize the editing style of a ListView
TreeView
The TreeView control is the go-to control inside the JavaFX UI toolkit for displaying tree-like data structures to users, for example, for representing a file system or a corporate hierarchy. The TreeView control displays a hierarchical structure by showing “disclosure” nodes (i.e., arrows) on tree branches, allowing for them to be expanded and collapsed. When a tree branch is expanded, its children are displayed beneath the branch but with a certain amount of indentation to make it clear that the children belong to their parent.
Properties of the TreeView class
Property | Type | Description |
---|---|---|
cellFactory | ObjectProperty<Callback<TreeView<T>,TreeCell<T>>> | Cell factory used for creating all cells. |
editable | BooleanProperty | Whether the TreeView is able to enter editing state. |
editingItem | ReadOnlyObjectProperty<TreeItem<T>> | The TreeItem currently being edited. |
expandedItemCount | ReadOnlyIntegerProperty | The total number of tree nodes able to be visible in the TreeView. |
focusModel | ObjectProperty<FocusModel<TreeItem<T>>> | Refer to the “Selection and Focus Models” section. |
root | ObjectProperty<TreeItem<T>> | The root tree item in the TreeView. |
selectionModel | ObjectProperty<MultipleSelectionModel<TreeItem<T>>> | Refer to the “Selection and Focus Models” section. |
showRoot | BooleanProperty | Whether the root is shown or not. If not, all children of the root will be shown as root elements. |
Properties of the TreeItem class
Property | Type | Description |
---|---|---|
expanded | BooleanProperty | Whether this TreeItem is expanded or collapsed. |
graphic | ObjectProperty<Node> | The graphic to show beside any text or other representation. |
leaf | ReadOnlyBooleanProperty | Whether this TreeItem is a leaf node or has children. |
parent | ReadOnlyObjectProperty<TreeItem<T>> | The parent TreeItem of this TreeItem, or null if it is the root. |
value | ObjectProperty<T> | The value of the TreeItem – this is what will be rendered in the cell of the TreeView/TreeTableView control. |
TableView
TableView, as the name implies, enables developers to display tabular data to users. This control, therefore, can be thought of as a ListView with support for multiple columns of data, rather than the single column in a ListView. With this comes a vast array of additional functionality: columns may be sorted, reordered, resized, and nested, individual columns may have custom cell factories installed, resize policies can be set to control how columns have available space distributed to them, and so much more. The primary properties of TableView are shown in Table 4-35.
TableView has a single generic type, S, which is used to specify the value of the elements allowed in the items list. Each element in this list represents the backing object for one entire row in the TableView. For example, if the TableView was to show Person objects, then we would define a TableView<Person> and add all the relevant people into the items list.
Properties of the TableView class
Property | Type | Description |
---|---|---|
columnResizePolicy | ObjectProperty<Callback<ResizeFeatures, Boolean>> | This handles redistributing column space when columns or the table are resized. |
comparator | ReadOnlyObjectProperty<Comparator<S>> | The current comparator based on the table columns in the sortOrder list. |
editable | BooleanProperty | Whether the TableView is able to enter editing state. |
editingCell | ReadOnlyObjectProperty<TablePosition<S,?>> | The position of any cell that is currently being edited. |
focusModel | ObjectProperty<TableViewFocusModel<S>> | Refer to the “Selection and Focus Models” section. |
items | ObjectProperty<ObservableList<S>> | The elements to show within the TableView. |
placeholder | ObjectProperty<Node> | Text to display within the ListView if the items list is empty. |
rowFactory | ObjectProperty<Callback<TableView<S>,TableRow<S>>> | The rowFactory is responsible for creating an entire row of TableCells (for all columns). |
selectionModel | ObjectProperty<TableViewSelectionModel<S>> | Refer to the “Selection and Focus Models” section. |
sortPolicy | ObjectProperty<Callback<TableView<S>,Boolean>> | Specifies how sorting should be performed. |
tableMenuButtonVisible | BooleanProperty | Specifies whether a menu button should show in the top right of TableView. |
TableColumn and TreeTableColumn
Properties of the TableColumnBase class
Property | Type | Description |
---|---|---|
comparator | ObjectProperty<Comparator<T>> | The comparator to use when this column is part of the table sortOrder list. |
editable | BooleanProperty | Specifies if this column supports editing. |
graphic | ObjectProperty<Node> | Graphic to show in the column header area. |
parentColumn | ReadOnlyObjectProperty<TableColumnBase<S,?>> | Refer to the “Nested Columns” section. |
resizable | BooleanProperty | Whether the width of the column can be changed by the user. |
sortable | BooleanProperty | Whether the column can be sorted by the user. |
sortNode | ObjectProperty<Node> | The “sort arrow” to show when the column is part of the sort order list. |
text | StringProperty | The text to display in the column header area. |
visible | BooleanProperty | Whether the column shows to the user or not. |
width | ReadOnlyDoubleProperty | The width of the column. |
TableColumn is a generic class with two generic types, S and T, where S is the same type as the TableView generic type and T is the type for the values that will be used in the specific column that the TableColumn represents.
When creating a TableColumn instance, the two most important properties to set are the column text property (what to show in the column header area) and the column cellValueFactory property (which is used to populate individual cells in the column).9
Properties of the TableColumn and TreeTableColumn classes
Property | Type | Description |
---|---|---|
cellFactory | ObjectProperty<Callback<TableColumn<S,T>,TableCell<S,T>>> | Cell factory for all cells in this table column. |
cellValueFactory | ObjectProperty<Callback<CellDataFeatures<S,T>,ObservableValue<T>>> | The cell value factory for all cells in this table column. |
sortType | ObjectProperty<SortType> | Specifies, when this column is part of the sort, whether it should be ascending or descending. |
Code required to create a TableColumn and specify a cell value factory
The approach in Listing 4-33 assumes that the object returned from p.getValue() has a JavaFX ObservableValue that can simply be returned. The benefit of this is that the TableView will internally create bindings to ensure that, should the returned ObservableValue change, the cell contents will be automatically refreshed.
Example of using PropertyValueFactory
Wrapping non-property values for use in a JavaFX TableView
For the TreeTableView control, a class similar to the PropertyValueFactory exists, called TreeItemPropertyValueFactory. It performs the same function as the PropertyValueFactory class, but it is designed to work with the TreeItem class that is used as part of the data model of the TreeTableView class.
Nested Columns
The JavaFX TableView and TreeTableView controls both have built-in support for column nesting. This means that, for example, you may have a “Name” column that contains two sub-columns, for first name and last name. The “Name” column is for the most part decorative – it isn’t involved in providing a cell value factory or cell factory (this is the responsibility of the child columns), but it can be used by the user to reorder the column position and to resize all child columns.
Creating a “name” column with two nested child columns
Cell Factories in TableView
We have already covered cell factories in the context of ListView, but cell factories in TableView (and TreeTableView) are slightly more nuanced. This is because, unlike ListView and TreeView, in the TableView and TreeTableView classes, there are two possible places where a cell factory can be placed.
Firstly, a “row factory” can be specified on the TableView and TreeTableView controls. A row factory is responsible for displaying an entire row of information, and therefore a custom row factory must take care to carefully display all columns appropriately. For this reason, row factories are very rarely created by developers.
Instead, developers tend to specify a custom cell factory on a single TableColumn (or TreeTableColumn, for the TreeTableView case). When a cell factory is set on a TableColumn, it functions in much the same way as a cell factory functions when set on a ListView – it is focused solely on representing a single cell (i.e., a column/row intersection) and not an entire row. This works well, as in most cases it is a fact that we wish to display all cells in a given column the same way, and therefore by specifying a custom cell factory on a TableColumn, we can enable this without great difficulty. In fact, the approach to writing a custom cell factory for a TableColumn is essentially exactly the same as for writing one for a ListView.
TreeTableView
Now that we have covered TreeView and TableView, we are left with covering TreeTableView , which from an API point of view takes elements of both TreeView and TableView. Therefore, to simplify the discussion and avoid repetition, this section on TreeTableView will be largely spent detailing from which of the two controls TreeTableView inherits its API.
The high-level summary of TreeTableView is that it uses the same TreeItem API as TreeView, and therefore it is required for developers to set the root node in the TreeTableView. This also means that there is no items list, such as in ListView and TableView. Similarly, the TreeTableView control makes use of the same TableColumn-based approach that the TableView control uses, except instead of using the TableView-specific TableColumn class, developers will need to use the largely equivalent TreeTableColumn class instead.
Properties of the TreeTableView class
Property | Type | Description |
---|---|---|
columnResizePolicy | ObjectProperty<Callback<ResizeFeatures, Boolean>> | This handles redistributing column space when columns or the table are resized. |
comparator | ReadOnlyObjectProperty<Comparator<TreeItem<S>>> | The current comparator based on the table columns in the sortOrder list. |
editable | BooleanProperty | Whether the TableView is able to enter editing state. |
editingCell | ReadOnlyObjectProperty<TreeTablePosition<S,?>> | The position of any cell that is currently being edited. |
expandedItemCount | ReadOnlyIntegerProperty | The total number of tree nodes able to be visible in the TreeTableView. |
focusModel | ObjectProperty<TreeTTableViewFocusModel<S>> | Refer to the “Selection and Focus Models” section. |
items | ObjectProperty<ObservableList<S>> | The elements to show within the TableView. |
placeholder | ObjectProperty<Node> | Text to display within the ListView if the items list is empty. |
root | ObjectProperty<TreeItem<S>> | The root tree item in the TreeTableView. |
rowFactory | ObjectProperty<Callback<TreeTableView<S>,TreeTableRow<S>>> | The rowFactory is responsible for creating an entire row of TreeTableCells (for all columns). |
selectionModel | ObjectProperty<TreeTableViewSelectionModel<S>> | Refer to the “Selection and Focus Models” section. |
sortPolicy | ObjectProperty<Callback<TreeTableView<S>,Boolean>> | Specifies how sorting should be performed. |
tableMenuButtonVisible | BooleanProperty | Specifies whether a menu button should show in the top right of TreeTableView. |
treeColumn | ObjectProperty<TreeTableColumn<S,?>> | Which column should have the disclosure node drawn within it. |
Selection and Focus Models
A number of the UI controls that ship with JavaFX consistently expose selection or focus models. This abstraction makes it simpler for developers to understand all UI controls, as they offer the same API for common scenarios. The SelectionModel API is far more widely used in a number of APIs, so we will cover it first.
SelectionModel
SelectionModel is an abstract class extended with a single generic type, T, that represents the type of the selected item in the related UI control. Because SelectionModel is abstract, most use cases are typically based on one of the two provided subclasses: SingleSelectionModel and MultipleSelectionModel. As their names imply, SingleSelectionModel is used in UI controls where only a single selection can be made at a time (e.g., in TabPane, it is only ever valid to select a single Tab at a time), whereas MultipleSelectionModel supports there being multiple selections existing at the same time (e.g., multiple rows in a ListView may be selected at the same moment).
Properties of the SelectionModel class
Property | Type | Description |
---|---|---|
selectedIndex | ReadOnlyIntegerProperty | The currently selected cell index in the UI control. |
selectedItem | ReadOnlyObjectProperty<T> | The currently selected item in the UI control. |
Moving further down the inheritance hierarchy, MultipleSelectionModel introduces additional API for allowing developers to select multiple rows at once and to observe on the selectedIndices and selectedItems lists for when state changes.
The final level of inheritance is table-specific selection models (TableViewSelectionModel and TreeTableViewSelectionModel). These classes add APIs to change selection mode between row and cell selection, and when in cell selection mode make it possible to select cells based on their row/column intersection points. They also make available a selectedCells list to listen for state changes.
FocusModel
The notion of focus in JavaFX can be a little odd when applied to UI controls, as there is an overloading of the term. In JavaFX, the more correct use of focus is related to what happens when the user “tabs” through a user interface – they are shifting focus between the various UI controls and nodes. Whichever of these elements has focus is then receptive to all other keyboard input.
Some UI controls have overloaded the term focus to also mean what could more precisely be referred to as “internal focus.” The ListView, TreeView, TableView, and TreeTableView controls all have focus models to allow for programmatic manipulation and observation of this internal focus. In this regard, the focus is not on a Node, but rather on an element inside the UI control, and we do not concern ourselves with the Node, but the value (of type T) in that row (as well as the index position of that row).
Properties of the FocusModel class
Property | Type | Description |
---|---|---|
focusedIndex | ReadOnlyIntegerProperty | The currently focused cell index in the UI control. |
focusedItem | ReadOnlyObjectProperty<T> | The currently focused item in the UI control. |
Summary
This chapter has methodically stepped through all UI controls that ship as part of JavaFX 11. Readers should now feel that they have sufficient knowledge to more easily create user interfaces consisting of appropriate UI controls.
As noted at the beginning of this chapter, there is a companion application available with the source code samples for this book that demonstrates all UI controls that are available as part of the core JavaFX distribution. Readers are encouraged to execute this application to become more familiar with how each UI control operates and to also better see how to use the UI control in their own development.
Acknowledgments
The companion application that was developed for this chapter could not have been fully realized without contributions from members of the JavaFX community. The author of this chapter would therefore like to take the opportunity to thank the following people: Abhinay Agarwal, Fouad Almalki, Almas Baimagambetov, Frank Delporte, Cyril Fischer, and Hossein Rimaz. Thanks!
Additionally, this chapter was expertly reviewed by Abhinay Agarwal. Thanks!