torutkのブログ

ソフトウェア・エンジニアのブログ

JavaFXでカレンダー表示プログラムを作る(DatePickerのポップアップ利用)(続)

JavaFXでカレンダー表示プログラムを作る(DatePickerのポップアップ利用) - torutkのブログの続きです*1

JavaFXプログラムで画面レイアウトを作るには大きく2つの方法があります。

  1. 画面レイアウトをFXMLと呼ばれるXMLファイルで定義し、それをJavaFXプログラム実行時に読み込んで画面表示させる方法
  2. 画面レイアウトをJavaコードからJavaFX APIを呼び作成する方法

単純な画面であればJavaFX APIをゴリゴリ書いて画面レイアウトを作っても問題になりにくいですが、複雑な画面になるとJavaFX APIで制御するのが大変になってくるので、FXMLで作るという流れです。FXMLはたいていGUIデザインツール(例、Scene Builder)を使って生成します。Scene Builderを使うと、ぽとりぺたっと画面レイアウトを作成できます。

と、ここまで書いておきながら、今回のカレンダー表示プログラムはFXMLではなくJavaFX APIで作成していきます。当面、Nodeを1つだけ持つ画面レイアウトであり、またそのNodeは直接FXMLでは指定できなさそうだからです。

さて、先日の一番単純なカレンダー表示に対して、文字や余白の大きさ、文字の色などを変更します。このような見栄えの設定についても、JavaFXではCSSファイルで定義し、それをJavaFXプログラム実行時に読み込んで画面表示に反映させる方法と、JavaコードからAPIを呼ぶ方法、FXMLの中で指定する方法とがあります。
コードからAPIで指定する場合もFXMLで指定する場合も、CSSの文字列を渡すことになるので、ここはCSSファイルで指定することにします。

CSSファイルはリソースバンドルで読み込み、シーングラフの適用する範囲の共通のルートになるノードに設定します。今回は、Sceneに設定します。

    Scene scene = new Scene(root);
    scene.getStylesheets().add(getClass().getResource("Calendar.css").toExternalForm());

Calendarクラスと同じ場所にCalendar.cssを作成します。NetBeansでは、Calendar.javaと同じ場所(ソースパッケージ)に[ファイル] > [新規ファイル] > [その他] > [Cascading Style Sheet]を選択します。ファイル名はCalendarと入力しておきます(名前は任意で可)。すると、Calendar.javaと同じフォルダにCalendar.cssが生成されます。

CSSファイルへの記述は、JavaFXCSSリファレンスマニュアルを参照します。

JavaFX CSSリファレンス・ガイド

しかし、今回のDatePickerSkin#getPopupで取得するノードについては言及がありません。
そこで、直接JavaFX 8のCSS定義ファイルを調べてみます。

JavaFX 8のCSS定義ファイルの取り出しとDatePicker関連の設定内容の確認

JavaFX 8のCSS定義ファイルは、JDK 8またはJRE 8のjfxrt.jarファイルに含まれています。
Windowsの場合、C:\Program Files\Java\jdk1.8.0_92\jre\lib\ext\jfxrt.jar といった場所にあります。
このファイルをzip解凍ツールで開き、com/sun/javafx/scene/control/skin/modena/modena.css を取り出します。zip解凍ツールがない場合、JDK 8に含まれるjarコマンドでも取り出しできます。

modena.cssを開いて、DatePicker関連の設定を探します。およそ3000行目付近から、DatePickerの定義が記載されています。その中に、.date-picker-popup というクラス名のセレクタを使用した定義がいくつかあります。

.date-picker-popup {
     -fx-background-color:
        linear-gradient(to bottom,
            derive(-fx-color,-17%),
            derive(-fx-color,-30%)
        ),
        -fx-control-inner-background;
    -fx-background-insets: 0, 1;
    -fx-background-radius: 0;
    -fx-alignment: CENTER; /* VBox */
    -fx-spacing: 0; /* VBox */
    -fx-padding: 0.083333em; /* 1 1 1 1 */
    -fx-effect: dropshadow( gaussian , rgba(0,0,0,0.2) , 12, 0.0 , 0 , 8 );
}

背景、配置、パディングや効果を設定しています。ここには文字のサイズはないようです。
続いて見ていきます。

.date-picker-popup > .month-year-pane {
    -fx-padding: 0.588883em 0.5em 0.666667em 0.5em; /* 7 6 8 6 */
    -fx-background-color: derive(-fx-box-border,30%), linear-gradient(to bottom, derive(-fx-base,-3%), derive(-fx-base,5%) 50%, derive(-fx-base,-3%));
    -fx-background-insets: 0 0 0 0, 0 0 1 0;
}

上部の月・年表示およびそれぞれのスピナーを並べたペインの設定があります。
ここは隙間(padding)の指定がありますが、文字のサイズはないようです。

文字の大きさを指定している個所を探すと、次がありました。

.date-picker-popup > * > .day-name-cell,
.date-picker-popup > * > .week-number-cell {
    -fx-font-size: 0.916667em;
}

.day-name-cellは曜日を表示するセルで、.week-number-cellは今回は使用していませんが、週番号を表示するセルです。
この両者の文字の大きさを指定しています(-fx-font-size: 0.916667em)。

同様に文字の大きさを指定している個所を探します。

.date-picker-popup > * > .day-cell {
    -fx-padding: 0.333333em 0.583333em 0.333333em 0.583333em; /* 4 7 4 7 */
    -fx-border-color: derive(-fx-selection-bar-non-focused, 60%);
    -fx-border-width: 1px;
    -fx-font-size: 1em;
    -fx-background: -fx-control-inner-background;
    -fx-background-color: -fx-background;
    -fx-text-fill: -fx-text-background-color;
}

.day-cellは日付を表示するセルです。文字の大きさを指定しています(-fx-font-size: 1em)。

カレンダー表示の文字を小さく

Windows 7のカレンダーガジェットのようにデスクトップの脇にカレンダーを表示するには、文字はデフォルトより小さくしたいので、まず文字サイズを変更します。

JavaFX 8のmodena.cssで文字サイズを設定しているセレクタの定義を、Calendar.cssで変更します。

  • .date-picker-popup > * > .day-name-cell
  • .date-picker-popup > * > .day-cell
  • .date-picker-popup > * > .day-cell
/* 日付表示の文字の大きさを変更 */
.date-picker-popup > * > .day-cell {
    -fx-font-size: 0.72em;
}
/* 曜日表示の文字の大きさを変更 */
.date-picker-popup > * > .day-name-cell {
    -fx-font-size: 0.72em;
}

カレンダー表示プログラムを実行します。

文字の大きさを0.72emに変更 デフォルトの文字の大きさ

ウィンドウを小さくすると、文字が隠れてしまいます。

これは、日付セルのセル内の余白(padding)があるため、日付セルの領域が狭まったときに、paddingをとった残りの領域が文字表示に不十分となったからです。

そこで、paddingをなるべく小さくします。.day-cellのpaddingのデフォルトは次です。

    -fx-padding: 0.333333em 0.583333em 0.333333em 0.583333em; /* 4 7 4 7 */

これを、0にしてしまいます。

/* 曜日表示の文字の大きさ、セル内余白を変更 */
.date-picker-popup > * > .day-name-cell {
    -fx-padding: 0 0 0 0;
    -fx-font-size: 0.72em;
}

カレンダー表示プログラムを実行します。今度はここまで小さくしても文字が隠れません。

ただし、小さくすると、月・年を表示するペインの高さ(余白)が大きすぎて気になります。月・年表示は.month-year-paneで定義されています。

    -fx-padding: 0.588883em 0.5em 0.666667em 0.5em; /* 7 6 8 6 */

そこで、このpaddingも小さくします。上下を0.1emで、左右を0.2emで設定します。

.date-picker-popup > .month-year-pane {
    -fx-padding: 0.1em 0.2em 0.1em 0.2em;
}
起動時のウィンドウサイズでの表示 文字が隠れない範囲でウィンドウを小さくした表示

今回のプログラムは次にあります。

https://github.com/torutk/calendar/tree/v0.1.1

*1:朝晩ちょこちょこっと書き溜めていたので3日がかりの日記になってしまいました。日付は初日になっています