JavaFX 8 DatePicker in Swing Application
1. Overview
This article shows an example of a Java SE 8 Swing application using a JavaFX 8
DatePicker
control.
The
DatePicker
control allows the user to enter a date as text or to select a date from a calendar popup. This example uses a Swing
JFrame
with FX controls in it. To embed the FX content within the Swing application the
javafx.embed.swing
package provides the
JFXPanel
class.
The app takes an input date from a date picker and checks if it is within the user selected range of dates (from and to date) from two date pickers. The date picker’s date validation includes:
- The from date is less than the to date
- The dates are not from the future
- The input date is within the from and to dates (including)
The not valid or valid messages are shown in FX
Alert
dialogs.
The following two screenshots shows the app with a
JFrame
and the embedded FX controls (
FXPanel
with
Label
,
DatePicker
and
Button
) and
DatePicker
’s calendar popup respectively.
1.1. Source Code
The source code for this example
FXDatePickerInSwingExample.java
is available to download from the link provided at the end of this article. Note that Java SE 8 is required to compile and run the code. Java SE 8 includes the JavaFX 8.
2. Application Description
The Java Swing application
FXDatePickerInSwingExample
is started from a Java SE program’s
main()
method in an event dispatch thread, as follows:
SwingUtilities.invokeLater(() -> { new FXDatePickerInSwingExample().initAndShowGUI(); });
The
initAndShowGUI()
method displays a Swing
JFrame
with JavaFX controls embedded in it. The following code snippet shows the
JFrame
construction:
JFrame frame = new JFrame("JavaFX DatePicker in Swing App"); JFXPanel fxPanel = new JFXPanel(); frame.add(fxPanel); frame.setVisible(true);
javafx.embed.swing.JFXPanel
is the component to embed JavaFX content into Swing applications and provides JavaFX and Swing interoperability.
JFXPanel
extends the
javax.swing.JComponent
. The content to be displayed is specified with the
JFXPanel
‘s
setScene()
method that accepts an instance of
javafx.scene.Scene
. This method is invoked on an FX application event dispatch thread, as follows:
Platform.runLater(() -> { fxPanel.setScene(createScene()); });
The app’s
createScene()
method returns a
Scene
instance with the FX controls. The screenshots shown above has the completed GUI. The following code snippet shows the
createScene()
method with code fragments:
private Scene createScene() { GridPane grid = new GridPane(); // Title Label title1 = new Label("Enter and check if the input date is"); Label title2 = new Label("within the selected date range."); VBox titleVb = new VBox(); titleVb.setAlignment(Pos.CENTER); titleVb.getChildren().addAll(title1, title2); // Input date picker Label inPickLabel = new Label("Input date:"); inPicker = new DatePicker(); inPicker.setPromptText(pattern); DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); StringConverter converter = new LocalDateStringConverter(formatter, null); inPicker.setConverter(converter); grid.add(inPickLabel, 0, 0); grid.add(inPicker, 1, 0); // From and to date pickers Label pickLabel1 = new Label("From date:"); fmPicker = new DatePicker(LocalDate.now()); fmPicker.setEditable(false); grid.add(pickLabel1, 0, 1); grid.add(fmPicker, 1, 1); // Button // Vbox and scene VBox vbox = new VBox(20); vbox.setPadding(new Insets(15, 15, 15, 15)); vbox.getChildren().addAll(titleVb, grid, btnHb); return new Scene(vbox); }
2.1. DatePicker Control
The
javafx.scene.control.DatePicker
control allows the user to enter a date as text or to select a date from a calendar popup. The
DatePicker
‘s value property represents the currently selected
LocalDate
. This property can be used with the constructor and also has the methods
getValue()
and
setValue()
.
The following code snippet constructs a date picker object and sets its value to today’s date:
DatePicker picker = new DatePicker(LocalDate.now());
2.2. Date Validation
There are three date pickers in this app. All these are configured to capture valid dates:
- The date values cannot be greater than today.
- The from-date can never be after the to-date.
To accomplish these constraints the
dayCellFactoryProperty
of the
DatePicker
is used. A custom cell factory can be provided to customize individual day cells in the date picker popup. Date picker has a method to set the custom cell factory:
setDayCellFactory()
.
These API’s are used to create the custom cell factory: The
DateCell
class is used by date picker to render the individual grid cells in the calendar month. An application can override the
DateCell
’s
update
method to change each cell’s properties such as text, background color, etc.
The following code snippet shows the method that returns a custom
dayCellFactory
. Note that this single method returns the cell factory for the three date pickers.
private Callback getCustomDateCellFactory(DateParameterType dateParamType) { Callback dayCellFactory = new Callback() { @Override public DateCell call(DatePicker datePicker) { return new DateCell() { @Override public void updateItem(LocalDate select, boolean b) { super.updateItem(select, empty); // Date cannot be after today. // This applies for all the date pickers. if (select.isAfter(LocalDate.now())) { setDisable(true); return; // From-date cannot be greater than to-date. if ((dateParamType == DateParameterType.FROM_DATE) (select.isAfter(toPicker.getValue()))) { setDisable(true); // To-date cannot be less than from-date, // and cannot be greater than today. if (dateParamType == DateParameterType.TO_DATE) { if ((select.isBefore(fmPicker.getValue())) || (select.isAfter(LocalDate.now()))) { setDisable(true); return dayCellFactory;
This custom
dayCellFactory
is applied to the date pickers in the
createScene()
method as follows:
inPicker.setDayCellFactory(getCustomDateCellFactory(null)); fmPicker.setDayCellFactory(getCustomDateCellFactory(DateParameterType.FROM_DATE)); toPicker.setDayCellFactory(getCustomDateCellFactory(DateParameterType.TO_DATE));
The
getCustomDateCellFactory()
method of the app returns the custom cell factory detailed earlier above. The method parameter
DateParameterType
enum
identifies the date picker for which the cell factory is applied. For example, the from-date picker requires a to-date picker date to get the cells that are to be disabled; so the
DateParameterType.FROM
is used to identify the relevant fragment of the code (see the following code snippet).
// From-date cannot be greater than to-date. if ((dateParamType == DateParameterType.FROM_DATE) && (select.isAfter(toPicker.getValue()))) { setDisable(true); }
2.3. Custom Converter for Input Date
By default the date picker shows the date string in a pattern (for example, dd/mm/yyyy) as per the default converter. This can be overridden by providing a custom converter to the
DatePicker
‘s
setConverter()
method. The input date picker accepts and shows the date in a format different (dd-MMM-yy) than the default format using a custom converter. The following note shows the usage of a custom converter.
These API’s are used to create a custom converter in this example:
-
javafx.util.StringConverter
: This abstract class defines conversion behaviour between strings and objects. -
javafx.util.converter.LocalDateStringConverter
: This class is aStringConverter
implementation forLocalDate
values. -
java.time.format.DateTimeFormatter
: This is a formatter for printing and parsing date-time objects.
Create a
StringConverter
for
LocalDate
values using the supplied formatter and parser. The formatter is used to convert the date as a formatted string using the specified pattern. Note the parser is specified as null. This converter is applied to the input
DatePicker
with
dd-MMM-yy
format. When selected from the popup the date is displayed as
dd-MMM-yy
format using the converter.
The following code snippet shows the converter creation and usage:
String pattern = "dd-MMM-yy"; DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); StringConverter converter = new LocalDateStringConverter(formatter, null); picker.setConverter(converter);
2.4. LocalDate
Java.time.LocalDate
is a date in the ISO-8601 calendar system (modern civil calendar system used today in most of the world), such as 2007-12-03. There is no time or time zone info stored in this class. An instance can be created from a year, month and day using the static method
LocalDate.of(int year, int month, int dayOfMonth)
.
The following are the APIs used in this app:
-
LocalDate.now()
obtains the current date from the system clock in the default time-zone. This is a static method. -
isAfter(ChronoLocalDate localDate)
checks if this date is after the specified date. This checks to see if this date represents a point on the local time-line after the other date.LocalDate
implements thejava.time.chrono.ChronoLocalDate
interface. -
isBefore(ChronoLocalDate localDate)
checks if this date is before the specified date. -
isEqual(ChronoLocalDate localDate)
checks if this date is equal to the specified date.
The following routine is used in the example to check if the input date is within a selected date range. The input as well as the selected from and to dates are obtained from the
DatePicker
controls. The
DatePicker
‘s
getValue()
method returns a
LocalDate
object.
private boolean validDate(LocalDate start, LocalDate end, LocalDate input) { if ((input.isEqual(start)) || (input.isEqual(end))) { return true; else if ((input.isAfter(start)) && (input.isBefore(end))) { return true; else { return false; }
3. Alerts
This is the
link to an article
describing the
javafx.scene.control.Alert
dialogs used in this example.
4. Usage Example
Java Swing doesn’t have a date picker component. Using the technique shown in this example a Swing application can use FX’s
DatePicker
controls within a Swing
JFrame
window. For example, this
JFrame
can be a ‘Search by date’ function dialog window, where a range of dates can be selected and the input data (for example, a collection of invoices) can be searched by their dates within the selected date range.
The Swing application’s window can open this
JFrame
dialog as a non-modal window when a user clicks a ‘Search by date’
JButton
(the button
ActionListener
‘s
actionPerformed()
method creates an instance of this ‘Search by date’ dialog).
5. Download Source Code
This was an example of
JavaFX 8 DatePicker in Swing Application
You can download the full source code of this example here: FXDatePickerInSwingExample.zip
*