JavaFX初探(时间选择器)

JavaFX初探(时间选择器)

本章我们主要介绍javafX时间选择器的使用,描述了DatePicker控件的基本特性。
javaFX的DatePicker控件可以让我们从一个给定的日历中选择一天,主要用于网站或应用中需要用户输入一个日期。

使用时间数据和日期格式

JDK8中新的日期API可以让我们执行非常多的日期操作,包括设置日历和通过时区来这是本地时间。
日期的基本包是java.time。提供了下面的类来定义时间,根据国际标准组织定义的日期:

  • Clock 获取当前时间、日期、时区时间
  • Duration 一段持续的时间
  • Instant 时间线上的一点
  • LocalDate ISO-8601日期系统中的无时区日期
  • LocalDateTime ISO-8601日期系统中的无时区时间
  • LocalTime ISO-8601日期系统中的无时区时间
  • MonthDay ISO-8601日期系统中的月日
  • OffsetDateTime 日期系统中伴有偏移的日期时间
  • OffsetTime 日期系统中伴有偏移的时间
  • Period 一段时间
  • Year 年
  • YearMonth 年月
  • ZonedDateTime 有时区的日期时间
  • ZoneId 时区ID
  • ZoneOffset 时区偏移

更多的功能和代码实例,请参照日期API

日期选择器设计概要

为了使用java8的日期控件提高javaFX用户界面,javafX SDK提供了DatePicker控件,这个控件包含了一个可编辑的组合框以及一个日历,如下图所示:
JavaFX初探(时间选择器)_第1张图片

添加日期控件到应用UI

使用DatePicker控件,我们可以往用户界面上添加日期选择组件。代码如下所示:

import java.util.Locale;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DatePickerSample extends Application {

    private Stage stage;
    private DatePicker checkInDatePicker;
    public static void main(String[] args) {
        Locale.setDefault(Locale.US);
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        stage.setTitle("DatePickerSample ");
        initUI();
        stage.show();
    }

    private void initUI() {
        VBox vbox = new VBox(20);
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, 400, 400);
        stage.setScene(scene);

        checkInDatePicker = new DatePicker();

        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);

        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, 0, 0);

        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, 0, 1);
        vbox.getChildren().add(gridPane);
    }
}

上面的代码实现了基本的日期选择控件,当你编译的运行此程序的时候,如下图所示:
这里写图片描述
需要指出的是,初始化状态下的日期控件日期域的空的,我们可以通过setValue方法来设置初试值,就像下面这样:

//Setting a particular date value in the class constructor
checkInDatePicker = new DatePicker(LocalDate.of(1998, 10, 8));
//Setting a particular date value by using the setValue method
checkInDatePicker.setValue(LocalDate.of(1998, 10, 8));
//Setting the minimum date available in the calendar
checkInDatePicker.setValue(LocalDate.MIN);
//Setting the maximum date available in the calendar
checkInDatePicker.setValue(LocalDate.MAX);
//Setting the current date
checkInDatePicker.setValue(LocalDate.now());

当初始值被设置了的时候,运行应用是,日期域就会显示设置了的时间。
这里写图片描述
DatePicker 控件提供了一些属性和方法来改变控件的行为,通常,你可以开关星期的显示,自定义日期格式,定义和使用单元格工厂。

自定义日期控件

你可以设置是否显示星期,通过setShowWeekNumbers 这个方法就可以,

checkInDatePicker.setShowWeekNumbers(true);

运行如下图所示:
JavaFX初探(时间选择器)_第2张图片
默认的情况下,日期的格式是:mm/dd/yyyy,通常你不需要修改这个默认格式。当然我们可以通过调用setConverter 方法来改变这个格式,如果设置的是null值,那么还是默认值。
下面的代码我们改变默认格式为: yyyy-MM-dd。

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class DatePickerSample extends Application {

    private Stage stage;
    private DatePicker checkInDatePicker;
    private final String pattern = "yyyy-MM-dd";

    public static void main(String[] args) {
        Locale.setDefault(Locale.US);
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        stage.setTitle("DatePickerSample ");
        initUI();
        stage.show();
    }

    private void initUI() {
        VBox vbox = new VBox(20);
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, 400, 400);
        stage.setScene(scene);
        checkInDatePicker = new DatePicker();
        StringConverter converter = new StringConverter<LocalDate>() {
            DateTimeFormatter dateFormatter = 
                DateTimeFormatter.ofPattern(pattern);
            @Override
            public String toString(LocalDate date) {
                if (date != null) {
                    return dateFormatter.format(date);
                } else {
                    return "";
                }
            }
            @Override
            public LocalDate fromString(String string) {
                if (string != null && !string.isEmpty()) {
                    return LocalDate.parse(string, dateFormatter);
                } else {
                    return null;
                }
            }
        };             
        checkInDatePicker.setConverter(converter);
        checkInDatePicker.setPromptText(pattern.toLowerCase());
        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, 0, 0);
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, 0, 1);
        vbox.getChildren().add(gridPane);
        checkInDatePicker.requestFocus();
    }
}

运行如下图所示:
JavaFX初探(时间选择器)_第3张图片
你也可以修改日历单元格的默认样式,为了实现这个任务,考虑这个场景:订酒店系通过中的选择预定时间和退房时间,代码如下,有两个日期控件:

import java.time.LocalDate;
import java.util.Locale;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class DatePickerSample extends Application {

    private Stage stage;
    private DatePicker checkInDatePicker;
    private DatePicker checkOutDatePicker;

    public static void main(String[] args) {
        Locale.setDefault(Locale.US);                  
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        stage.setTitle("DatePickerSample ");
        initUI();
        stage.show();
    }

    private void initUI() {
        VBox vbox = new VBox(20);
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, 400, 400);
        stage.setScene(scene);
        checkInDatePicker = new DatePicker();
        checkOutDatePicker = new DatePicker();
        checkInDatePicker.setValue(LocalDate.now());
        checkOutDatePicker.setValue(checkInDatePicker.getValue().plusDays(1));
        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, 0, 0);
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, 0, 1);
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, 0, 2);
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, 0, 3);
        vbox.getChildren().add(gridPane);
    }
}

预定义的预定时间是当前时间,退房时间是下一天,运行如下图所示:
JavaFX初探(时间选择器)_第4张图片
默认情况下所有的时间都是可以选择的,这就出现一种情况,退房时间在预定时间之前,这是不正确的。
下面的例子解决这个问题:

import java.time.LocalDate;
import java.util.Locale;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class DatePickerSample extends Application {

    private Stage stage;
    private DatePicker checkInDatePicker;
    private DatePicker checkOutDatePicker;

    public static void main(String[] args) {
        Locale.setDefault(Locale.US);                  
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        stage.setTitle("DatePickerSample ");
        initUI();
        stage.show();
    }

    private void initUI() {
        VBox vbox = new VBox(20);
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, 400, 400);
        stage.setScene(scene);
        checkInDatePicker = new DatePicker();
        checkOutDatePicker = new DatePicker();
        checkInDatePicker.setValue(LocalDate.now());
        final Callback<DatePicker, DateCell> dayCellFactory = 
            new Callback<DatePicker, DateCell>() {
                @Override
                public DateCell call(final DatePicker datePicker) {
                    return new DateCell() {
                        @Override
                        public void updateItem(LocalDate item, boolean empty) {
                            super.updateItem(item, empty);

                            if (item.isBefore(
                                    checkInDatePicker.getValue().plusDays(1))
                                ) {
                                    setDisable(true);
                                    setStyle("-fx-background-color: #ffc0cb;");
                            }   
                    }
                };
            }
        };
        checkOutDatePicker.setDayCellFactory(dayCellFactory);
        checkOutDatePicker.setValue(checkInDatePicker.getValue().plusDays(1));
        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, 0, 0);
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, 0, 1);
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, 0, 2);
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, 0, 3);
        vbox.getChildren().add(gridPane);
    }
}

运行如下所示:
JavaFX初探(时间选择器)_第5张图片
下面的例子计算当前时间和当前日期单元格之间的时间。

import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.Locale;
import javafx.application.Application;
import javafx.geometry.HPos;
import javafx.scene.Scene;
import javafx.scene.control.DateCell;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class DatePickerSample extends Application {

    private Stage stage;
    private DatePicker checkInDatePicker;
    private DatePicker checkOutDatePicker;

    public static void main(String[] args) {
        Locale.setDefault(Locale.US);                  
        launch(args);
    }

    @Override
    public void start(Stage stage) {
        this.stage = stage;
        stage.setTitle("DatePickerSample ");
        initUI();
        stage.show();
    }

    private void initUI() {
        VBox vbox = new VBox(20);
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, 400, 400);
        stage.setScene(scene);
        checkInDatePicker = new DatePicker();
        checkOutDatePicker = new DatePicker();
        checkInDatePicker.setValue(LocalDate.now());
        final Callback<DatePicker, DateCell> dayCellFactory = 
            new Callback<DatePicker, DateCell>() {
                @Override
                public DateCell call(final DatePicker datePicker) {
                    return new DateCell() {
                        @Override
                        public void updateItem(LocalDate item, boolean empty) {
                            super.updateItem(item, empty);
                            if (item.isBefore(
                                    checkInDatePicker.getValue().plusDays(1))
                                ) {
                                    setDisable(true);
                                    setStyle("-fx-background-color: #ffc0cb;");
                            }
                            long p = ChronoUnit.DAYS.between(
                                    checkInDatePicker.getValue(), item
                            );
                            setTooltip(new Tooltip(
                                "You're about to stay for " + p + " days")
                            );
                    }
                };
            }
        };
        checkOutDatePicker.setDayCellFactory(dayCellFactory);
        checkOutDatePicker.setValue(checkInDatePicker.getValue().plusDays(1));
        GridPane gridPane = new GridPane();
        gridPane.setHgap(10);
        gridPane.setVgap(10);
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, 0, 0);
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, 0, 1);
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, 0, 2);
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, 0, 3);
        vbox.getChildren().add(gridPane);
    }
}

如下图所示:
JavaFX初探(时间选择器)_第6张图片

修改日期系统

import java.time.chrono.*;

checkInDatePicker.setChronology(ThaiBuddhistChronology.INSTANCE);
checkOutDatePicker.setChronology(HijrahChronology.INSTANCE);

JavaFX初探(时间选择器)_第7张图片

你可能感兴趣的:(Datepicker,javafx8)