天天看點

JavaFX初探(時間選擇器)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初探(時間選擇器)JavaFX初探(時間選擇器)

添加日期控件到應用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();
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, , );
        stage.setScene(scene);

        checkInDatePicker = new DatePicker();

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

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

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

上面的代碼實作了基本的日期選擇控件,當你編譯的運作此程式的時候,如下圖所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

需要指出的是,初始化狀态下的日期控件日期域的空的,我們可以通過setValue方法來設定初試值,就像下面這樣:

//Setting a particular date value in the class constructor
checkInDatePicker = new DatePicker(LocalDate.of(, , ));
//Setting a particular date value by using the setValue method
checkInDatePicker.setValue(LocalDate.of(, , ));
//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());
           

當初始值被設定了的時候,運作應用是,日期域就會顯示設定了的時間。

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

DatePicker 控件提供了一些屬性和方法來改變控件的行為,通常,你可以開關星期的顯示,自定義日期格式,定義和使用單元格工廠。

自定義日期控件

你可以設定是否顯示星期,通過setShowWeekNumbers 這個方法就可以,

checkInDatePicker.setShowWeekNumbers(true);
           

運作如下圖所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

預設的情況下,日期的格式是: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();
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, , );
        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();
        gridPane.setVgap();
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, , );
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, , );
        vbox.getChildren().add(gridPane);
        checkInDatePicker.requestFocus();
    }
}
           

運作如下圖所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

你也可以修改月曆單元格的預設樣式,為了實作這個任務,考慮這個場景:訂酒店系通過中的選擇預定時間和退房時間,代碼如下,有兩個日期控件:

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();
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, , );
        stage.setScene(scene);
        checkInDatePicker = new DatePicker();
        checkOutDatePicker = new DatePicker();
        checkInDatePicker.setValue(LocalDate.now());
        checkOutDatePicker.setValue(checkInDatePicker.getValue().plusDays());
        GridPane gridPane = new GridPane();
        gridPane.setHgap();
        gridPane.setVgap();
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, , );
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, , );
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, , );
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, , );
        vbox.getChildren().add(gridPane);
    }
}
           

預定義的預定時間是目前時間,退房時間是下一天,運作如下圖所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

預設情況下所有的時間都是可以選擇的,這就出現一種情況,退房時間在預定時間之前,這是不正确的。

下面的例子解決這個問題:

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();
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, , );
        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())
                                ) {
                                    setDisable(true);
                                    setStyle("-fx-background-color: #ffc0cb;");
                            }   
                    }
                };
            }
        };
        checkOutDatePicker.setDayCellFactory(dayCellFactory);
        checkOutDatePicker.setValue(checkInDatePicker.getValue().plusDays());
        GridPane gridPane = new GridPane();
        gridPane.setHgap();
        gridPane.setVgap();
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, , );
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, , );
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, , );
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, , );
        vbox.getChildren().add(gridPane);
    }
}
           

運作如下所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

下面的例子計算目前時間和目前日期單元格之間的時間。

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();
        vbox.setStyle("-fx-padding: 10;");
        Scene scene = new Scene(vbox, , );
        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())
                                ) {
                                    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());
        GridPane gridPane = new GridPane();
        gridPane.setHgap();
        gridPane.setVgap();
        Label checkInlabel = new Label("Check-In Date:");
        gridPane.add(checkInlabel, , );
        GridPane.setHalignment(checkInlabel, HPos.LEFT);
        gridPane.add(checkInDatePicker, , );
        Label checkOutlabel = new Label("Check-Out Date:");
        gridPane.add(checkOutlabel, , );
        GridPane.setHalignment(checkOutlabel, HPos.LEFT);
        gridPane.add(checkOutDatePicker, , );
        vbox.getChildren().add(gridPane);
    }
}
           

如下圖所示:

JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)

修改日期系統

import java.time.chrono.*;

checkInDatePicker.setChronology(ThaiBuddhistChronology.INSTANCE);
checkOutDatePicker.setChronology(HijrahChronology.INSTANCE);
           
JavaFX初探(時間選擇器)JavaFX初探(時間選擇器)