I initialize all ChoiceBox entries with a ‘hardcoded’ list of values, and set the displayed value to the first item in the list. It would be logical to do this initialization in SceneBuilder, but the tool only seems capable of creating a default set of values (named Item1, Item2, and Item3). Here is an example for the startMonthSelect field.
Listing 5 – Initializing ChoiceBox Selection List Example
One of the key functions of the Controller is to properly handle events to respond to user actions in a natural way. There are several different types of events that I need to respond to:
- User selects a ChoiceBox value. The ChoiceBoxes (sometimes called SelectionBox or Dropdown Menu) restrict user selections to a pre-defined range of values; for example, the Start Month must be in the range of “Jan” … “Dec”.
- User enters a character (including a character key, digit key, Backspace, Delete, etc.,) in one of the Year fields.
- User selects or deselects one of the “Use Current Date/Time” CheckBoxes.
- User selects an item from one of the Menus (currently only the File menu has selectable items).
- User clicks the “Calculate”, “Reset”, or “Close” button.
Most of the event handling is straightforward – typically I call a private method to respond to a user clicking a button or selecting a menu item. I did customize a few events as follows (see Listing 6):
When navigating through the Start Date and Finish Date in the entry panes, the up/down arrow key default behavior is to move to a different field in the pane, or to the next object in the controller hierarchy. I overrode this behavior for these two keys so that if the cursor is located in a ChoiceBox, the up arrow key scrolls upward through the ChoiceBox selection list, and the down arrow key scrolls downward. To do this I added a handler for the appropriate KeyCodes (UP and DOWN) in the KeyEvent.KEY_PRESSED event. Note that the entry panes (startDTPane, finishDTPane) are the parents of the ChoiceBoxes within the pane. By consuming the event at the parent level, the behavior propagates down to the child ChoiceBox.
I also overrode the up and down arrow key behavior in the Year fields, so that pressing the UP key decrements the year field (until the minimum Year is reached), and pressing the DOWN key increments the year field (until the maximum Year is reached).
Listing 6 – Custom Event Handling
One last thing; I wanted the Year fields to be restricted to numeric values between minYear and maxYear. I started by creating a subclass of TextField called ConstrainedNumericTextField which did a simple override of methods in the parent class to ignore non-digit characters, and restrict the overall length of the field input to four characters. But I ran into a problem using SceneBuilder because it does not appear to support the concept of subclassing the standard JavaFX controls (such as TextField). I could update the FXML manually to refer to the subclasses, but I did not wish to manually edit the DateCalculatorUI.fxml file every time I used SceneBuilder. As a consequence, I added a few lines to the KeyEvent.KEY_RELEASED code to check the user input and ignore non-numeric entries and numeric entries beyond four digits (Listing 7). That also required tweaking the position of the caret (cursor) in the event handler.
Listing 7 – Numeric Text Field Validation