Core Java

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.

FX controls in Swing JFrame
FX controls in Swing JFrame

FX DatePicker with calender popup
FX DatePicker with calender popup

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:

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 the java.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

Download
You can download the full source code of this example here: FXDatePickerInSwingExample.zip

*

Prasad Saya

Prasad Saya is a software engineer with over ten years’ experience in application development, maintenance, testing and consulting on various platforms. He is also a certified Java and Java EE developer. At present his interest is in developing Java applications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button