Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Datepicker in JavaFX 8

Is there any implementation of Date Picker and Time Picker into the default JavaFX 8 package that I can use without using third party solutions?

like image 409
Peter Penzov Avatar asked Dec 04 '13 07:12

Peter Penzov


3 Answers

DatePicker

Yes, Java 8 has a DatePicker:

datepicker

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.DatePicker;
import javafx.stage.Stage;

import java.time.LocalDate;

public class PickerDemo extends Application {
    @Override public void start(Stage stage) {
        final DatePicker datePicker = new DatePicker(LocalDate.now());
        datePicker.setOnAction(event -> {
            LocalDate date = datePicker.getValue();
            System.out.println("Selected date: " + date);
        });

        stage.setScene(
            new Scene(datePicker)
        );
        stage.show();
    }
    public static void main(String[] args) { launch(args); }
}

TimePicker

No, Java 8 does not have a TimePicker.

There is a TimePicker in jfxtras (source here).

Given that Java 8 already has a DatePicker, the addition of a TimePicker might be an appropriate feature request, you could make.

like image 156
jewelsea Avatar answered Oct 06 '22 16:10

jewelsea


If you do not want to display calendar in popup. Here is a solution which uses internal CalendarPickerContent class.

DatePickerSkin skin = new DatePickerSkin(new DatePicker());
Node calendarControl = skin.getPopupContent();
like image 39
javaLearner Avatar answered Oct 06 '22 16:10

javaLearner


here is my try based on @javaLearner answer:

DateTimePicker.java:

package test;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Skin;
import javafx.util.StringConverter;


public class DateTimePicker extends DatePicker{

    private ObjectProperty<LocalTime> timeValue = new SimpleObjectProperty<>();
    private ObjectProperty<ZonedDateTime> dateTimeValue;

    public DateTimePicker(){
        super();
        setValue(LocalDate.now());
        setTimeValue(LocalTime.now());
        setConverter(new StringConverter<LocalDate>() {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HH:mm:ssZ");
            @Override
            public String toString ( LocalDate object ) {               
                return dateTimeValue.get().format(formatter);
            }

            @Override
            public LocalDate fromString ( String string ) {
                return LocalDate.parse(string, formatter);
            }
        });
    }

    @Override
    protected Skin<?> createDefaultSkin () {
        return new DateTimePickerSkin(this);
    }

    public LocalTime getTimeValue(){
        return timeValue.get();
    }

    void setTimeValue(LocalTime timeValue){
        this.timeValue.set(timeValue);
    }

    public ObjectProperty<LocalTime> timeValueProperty(){
        return timeValue;
    }


    public ZonedDateTime getDateTimeValue() {
        return dateTimeValueProperty().get();
    }


    public void setDateTimeValue (ZonedDateTime dateTimeValue) {
        dateTimeValueProperty().set(dateTimeValue);
    }

    public ObjectProperty<ZonedDateTime> dateTimeValueProperty(){
        if (dateTimeValue == null){
            dateTimeValue = new SimpleObjectProperty<>(ZonedDateTime.of(LocalDateTime.of(this.getValue(), timeValue.get()), ZoneId.systemDefault()));
            timeValue.addListener(t -> {
                dateTimeValue.set(ZonedDateTime.of(LocalDateTime.of(this.getValue(), timeValue.get()), ZoneId.systemDefault()));
            });

            valueProperty().addListener(t -> {
                dateTimeValue.set(ZonedDateTime.of(LocalDateTime.of(this.getValue(), timeValue.get()), ZoneId.systemDefault()));
            });
        }
        return dateTimeValue;
    }


}

DateTimePickerSkin.java:

package test;

import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.layout.HBox;

import com.sun.javafx.scene.control.skin.DatePickerContent;
import com.sun.javafx.scene.control.skin.DatePickerSkin;

public class DateTimePickerSkin extends DatePickerSkin {

    private DateTimePicker datePicker;
    private DatePickerContent ret;

    public DateTimePickerSkin(DateTimePicker datePicker){
        super(datePicker);
        this.datePicker = datePicker;
    }

    @Override 
    public Node getPopupContent() {
        if (ret == null){
            ret = (DatePickerContent) super.getPopupContent();

            Slider hours = new Slider(0, 23, (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getMinute() : 0));      
            Label hoursValue = new Label("Hours: " + (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getHour() : "") + " ");

            Slider minutes = new Slider(0, 59, (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getMinute() : 0));
            Label minutesValue =  new Label("Minutes: " + (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getMinute() : "") + " ");

            Slider seconds = new Slider(0, 59, (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getSecond() : 0));        
            Label secondsValue = new Label("Seconds: " + (datePicker.getTimeValue() != null ? datePicker.getTimeValue().getSecond() : "") + " ");

            ret.getChildren().addAll(new HBox(hoursValue, hours), new HBox(minutesValue, minutes), new HBox(secondsValue, seconds));

            hours.valueProperty().addListener((observable, oldValue, newValue) -> {
                datePicker.setTimeValue(datePicker.getTimeValue().withHour(newValue.intValue()));
                hoursValue.setText("Hours: " + String.format("%02d", datePicker.getTimeValue().getHour()) + " ");
            });

            minutes.valueProperty().addListener((observable, oldValue, newValue) -> {
                datePicker.setTimeValue(datePicker.getTimeValue().withMinute(newValue.intValue()));
                minutesValue.setText("Minutes: " + String.format("%02d", datePicker.getTimeValue().getMinute()) + " ");
            });

            seconds.valueProperty().addListener((observable, oldValue, newValue) -> {
                datePicker.setTimeValue(datePicker.getTimeValue().withSecond(newValue.intValue()));
                secondsValue.setText("Seconds: " + String.format("%02d", datePicker.getTimeValue().getSecond()) + " ");
            });

        }
        return ret;
    }


}

usage:

Main.java:

public class Main extends Application{

    @Override
    public void start ( Stage primaryStage ) {
        VBox vBox = new VBox();
        Scene s =  new Scene(new ScrollPane(vBox), 600, 400);
        DateTimePicker d = new DateTimePicker();

        // Date only
        d.valueProperty().addListener(t -> System.out.println(t));

        // Time only
        d.timeValueProperty().addListener(t -> System.out.println(t));

        // DateAndTime
        d.dateTimeValueProperty().addListener(t -> System.out.println(t));

        vBox.getChildren().add(d);

        primaryStage.setScene(s);
        primaryStage.show();
    }

    public static void main ( String[] args ) {
        launch(args);
    }
}

there is still the StringConverter job to be done, but it's quite usable even like this. hope it helps someone.

PS: this was tested with jdk8u40, and it uses classes from the com.sun package (DatePickerContent/DatePickerSkin) which are not public API and might change in the future, but common, even if they do, how hard is it to adapt the above code !? :)

edit: added a StringConverter for iso8601 format and added a ZonedDateTime property for a cleaner usage (can swapped with a LocalDateTime if you don't need the Zone information)

like image 27
Rima Avatar answered Oct 06 '22 17:10

Rima