ドキュメント



JavaFX: JavaFX UIコンポーネントの操作

26 日付ピッカー

この章では、JavaFXでサポートされている日付データの概要を示し、DatePickerコントロールの基本機能について説明します。

JavaFX DatePickerは、特定のカレンダから日付を選択できるコントロールです。これは主に、ユーザーが日付を入力する必要があるWebサイトやアプリケーションで使用されます。DatePickerコントロールは、日付フィールドと日付チューザがあるコンボ・ボックスで構成されています。

時間データと日付書式の使用

JDK 8に導入されている新しい日時APIを使用すると、様々なタイムゾーンにわたるカレンダおよびローカル時間の設定を含む、日時データを使用した様々な操作を実行できます。

日時APIの基本パッケージはjava.timeです。これには、国際標準化機構(ISO)のカレンダに基づいて暦体系内の時間を定義するために次のクラスが用意されています。

  • Clock - タイムゾーンを使用して現在の時点、日付および時間へのアクセスを提供するクロック

  • Duration - 時間ベースの時間量

  • Instant - 時系列上の一瞬の点

  • LocalDate - ISO-8601暦体系のタイムゾーンのない日付

  • LocalDateTime - ISO-8601暦体系のタイムゾーンのない日時

  • LocalTime - ISO-8601暦体系のタイムゾーンのない時間

  • MonthDay - ISO-8601暦体系での日

  • OffsetDateTime - ISO-8601暦体系でのグリニッジ/UTCからのオフセット付きの日時

  • OffsetTime - ISO-8601暦体系でのグリニッジ/UTCからのオフセット付きの時間

  • Period - 日付ベースの時間量

  • Year - ISO-8601暦体系での年

  • YearMonth - ISO-8601暦体系での年月

  • ZonedDateTime - ISO-8601暦体系のタイムゾーンのある日時

  • ZoneId - タイムゾーンID

  • ZoneOffset - グリニッジ/UTCからのタイムゾーンのオフセット

使用可能な機能およびコード・サンプルの詳細は、Javaチュートリアルの日時API」トレールに関する項を参照してください。

日付ピッカーの設計の概要

JDK 8の日時APIの新機能を使用してJavaFXアプリケーションのユーザー・インタフェースを拡張するために、JavaFX SDKにはDatePickerコントロールが導入されています。DatePickerコントロールは、図26-1に示す編集可能なコンボ・ボックス(日付フィールド)とカレンダ(日付チューザ)で構成されています。

図26-1 日付ピッカー・コントロールの例

図26-1の説明が続きます
「図26-1 日付ピッカー・コントロールの例」の説明

アプリケーションUIへの日付ピッカーの追加

図26-1に示すように、javafx.scene.controlパッケージに用意されているDatePickerクラスを使用して、JavaFXアプリケーションのユーザー・インタフェース(UI)に日付ピッカー・コンポーネントを追加します。

例26-1 日付ピッカー・コンポーネントの追加

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);
    }
}

例26-1では、ホテル予約のチェックイン日を選択するための一般的なUIを実装しています。アプリケーションをコンパイルして実行すると、図26-2に示すコンポーネントが表示されます。

図26-2 日付ピッカー・コンポーネントの初期ビュー

図26-2の説明が続きます
「図26-2 日付ピッカー・コンポーネントの初期ビュー」の説明

日付フィールドの初期状態は空であることに注意してください。ただし、この動作を変更し、日付が選択される前に日付値が表示されるよう指定することもできます。DatePickerコンストラクタにvalueプロパティを設定するか、ComboBoxクラスから継承されたsetValueメソッドをコールします。例26-2に、LocalDate値を設定するためのオプションをいくつか示します。

例26-2 日付値の設定

//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());

初期値を設定すると、アプリケーションをコンパイルして実行した後に日付フィールドに表示されます。図26-3に、日付フィールドに指定した初期日付を示します。

図26-3 初期日付を指定した日付フィールド

図26-3の説明が続きます
「図26-3 初期日付を指定した日付フィールド」の説明

DatePicker APIには、日付ピッカーのデフォルトの外観と動作を変更するために複数のプロパティおよびメソッドが用意されています。特に、週番号の表示の切替え、日付書式のカスタマイズ、および日付セル・ファクトリの定義と適用が可能です。

日付ピッカーのカスタマイズ

カレンダでISOの週番号の表示を有効または無効にするには、DatePickerクラスのsetShowWeekNumbersメソッドを使用します。例26-3は、このタスクをcheckInDatePickerに実装するコード行です。

例26-3 日付ピッカーでの週番号の有効化

checkInDatePicker.setShowWeekNumbers(true);

この変更により、図26-4に示すように、カレンダ要素に週番号が追加された日付ピッカー・コンポーネントが生成されます。

図26-4 カレンダでの週番号の表示

図26-4の説明が続きます
「図26-4 カレンダでの週番号の表示」の説明

デフォルトでは、日付フィールドの日付は、システム・ロケールおよびISO暦体系によって定義された書式で表示されます。このため、例26-1で選択した日付は、mm/dd/yyyyの書式で表示されます。通常、このデフォルトの書式を変更する必要はありません。ただし、必要な場合は、DatePickerクラスのconverterプロパティおよびsetConverterメソッドを使用して、別の日付書式を設定できます。converter値をnullに設定すると、デフォルトの日付書式に戻ります。

例26-4では、yyyy-MM-ddのパターンに応じて日付の書式を変更するためのコンバータを作成しています。これにより、ユーザーが日付フィールドに日付を入力したときに、入力テキストをLocalDateタイプのオブジェクトに変換します。また、カレンダで選択した日付に対応するLocalDateオブジェクトを、日付フィールドに表示されるテキストに変換します。

例26-4 日付書式の変換

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();
    }
}

例26-4では、日付書式を変換するだけでなく、必要な日付書式についてユーザーに通知するためのプロンプト・テキストを日付フィールドに設定しています。図26-5に、日付書式コンバータが適用された日付ピッカーの2つの状態を示します。プロンプト・テキストと選択した日付の両方が新しい書式で表示されています。

図26-5 書式コンバータとプロンプト・テキストが適用された日付ピッカー

図26-5の説明が続きます
「図26-5 書式コンバータとプロンプト・テキストが適用された日付ピッカー」の説明

デフォルトの外観を変更したり、カレンダ要素の1つ以上のセルに特定の動作を設定することもできます。このタスクを実装するには、実際のユースケース(ホテルの予約時におけるチェックイン日とチェックアウト日の選択)について考えてみます。例26-5では、2つの日付ピッカーを使用して一般的なユーザー・インタフェースを作成しています。

例26-5 2つの日付ピッカー・コンポーネントの追加

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);
    }
}

例26-5のcheckInDatePickerの事前定義済の値は、システム・クロックの現在の日付に対応するLocalDate.now()です。checkOutDatePickerの事前定義済の日付は、現在の日付の翌日です。

この例を2013年9月19日でコンパイルして実行すると、図26-6に示す出力が生成されます。

図26-6 2つの日付ピッカー・コンポーネント

図26-6の説明が続きます
「図26-6 2つの日付ピッカー・コンポーネント」の説明

デフォルトでは、カレンダ要素内のすべてのセルが選択可能です。この場合、チェックアウト日がチェックイン日の前になる可能性がありますが、これは正しくありません。

例26-6では、checkInDatePickerで選択した日付に対応するセル、およびこれより前の日付に対応するすべてのセルを無効にするために、checkOutDatePickerに対して日付セル・ファクトリを作成しています。

例26-6 特定の日付を無効にするための日付セル・ファクトリの実装

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);
    }
}

checkOutDatePickerに適用されたdayCellFactoryは、setDisableおよびsetStyleメソッドをDateCell項目に対してコールし、特定のセルを選択できないようにし、これらをピンク色にしています。

例26-6のコードをコンパイルして実行すると、DatePickerSampleでは、図26-7に示すように、所定の動作でUIが生成されます。

図26-7 カレンダ要素のセルの無効化

図26-7の説明が続きます
「図26-7 カレンダ要素のセルの無効化」の説明

ここまで、日付セル・ファクトリの作成方法について学習しました。これで、checkOutDatePickerのデフォルトの動作を拡張し、選択可能な日付セルに追加機能を設定できるようになります。

例26-7では、checkInDatePickerで選択した日付と現在の日付セルの間の日付間隔を計算しています。この結果は、セル・ツールチップでレンダリングされます。

例26-7 時間間隔の計算

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);
    }
}

変更したDatePickerSampleアプリケーションをコンパイルして実行すると、日付セルの上にマウス・カーソルを置いたときにツールチップが表示されます。図26-8は、9月30日のセルの上にマウス・カーソルを置いた瞬間を捉えています。このツールチップは、9月19日と9月30日の間の日数が11日間であることを示しています。

図26-8 日付セルのツールチップの設定

図26-8の説明が続きます
「図26-8 日付セルのツールチップの設定」の説明

暦体系の変更

JDK 8に導入されている日時Java APIを使用すると、開発者は、ISOベースの暦体系だけでなく、和暦、イスラム暦、民国暦およびタイ仏暦などの別の暦体系も使用できます。

DatePickerコントロールは、適切に年をレンダリングすることによってISO以外の暦体系もサポートしています。月の日付がISOの日付とは異なるイスラム暦の場合、ISOとイスラム暦の日付を区別するために別の視覚テーマが用意されています。

例26-8では、タイ仏暦をcheckInDatePickerに適用し、イスラム暦をcheckOutDatePickerに適用しています。

例26-8 タイ仏暦とイスラム暦の適用

import java.time.chrono.*;

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

これらの行をDatePickerSampleアプリケーションに適用すると、図26-9に示すように、日付ピッカー・コントロールの外観が変更されます。

図26-9 別の暦の使用

図26-9の説明が続きます
「図26-9 別の暦の使用」の説明

ISO以外の日付のサポートの詳細は、Javaチュートリアルの対応するレッスンを参照してください。

関連ドキュメント

ウィンドウを閉じる

目次

JavaFX: JavaFX UIコンポーネントの操作

展開 | 縮小