プロジェクト

全般

プロフィール

JavaFXとCSS

CSSファイル読み込みの設定

FXMLからCSSファイルを指定

Scene Builderで画面全体に設定するCSSファイルを指定する

直接JavaコードでCSSを適用する場合は、Sceneを指定できます。
Scene Builderで画面を作成している場合で、Scene Builder上でCSSを画面全体に適用するには、シーングラフの階層のトップに近いPaneに適用します。

まず、シーングラフの階層paneでもっともトップにあるpaneを選択します。画面を次に示します。

cssfile_settings-01.png

次にそのpaneのプロパティでStylesheetsに適用したいCSSファイルを設定します。プロパティのStylesheets欄の[+]となっている欄(次の画面)をクリックするとファイル選択ダイアログが表示されます。

cssfile_settings-02.png

ここで、予め作成しておいたCSSファイル(次の画面では darktheme.css)を選択します。

cssfile_settings-03.png

SceneBuilderはこの時点で指定したCSSの設定に合わせて画面が表示されます。
まずCSS指定前のデフォルト(JavaFX 8の場合はmodena)の画面例を次に示します。

cssfile_settings-04.png

CSS指定後の画面例を次に示します。

cssfile_settings-05.png

SceneBuilderからCSSファイルを指定した結果、FXMLファイルには次の記述が追加されました。

<BorderPane maxHeight="-Infinity" ...
    stylesheets="@darktheme.css" ...>

  • BorderPaneの属性stylesheetsにファイル名が追記されています。なお、このcssファイルはFXMLファイルおよびそれを使用するソースファイルと同じディレクトリに置いています。
  • 画面上部の背景が白のままですが、それは別の項で述べます。

ソースコード上でAPIでCSSファイルを指定

シーングラフの階層のNode(ここではScene)にCSSファイルを指定します。

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

FXMLでCSSファイルを指定した後でコードからCSSファイルを読み込む

先の指定でFXMLでCSSファイルを指定すると、クラスファイルと同じ場所にあるCSSファイルを読み込みます。
これを、プログラム実行後に別なCSSファイルを読み込み反映する場合、上述のSceneにCSSを指定してもFXMLで指定したCSSの内容を変更することができません。
Sceneに設定したCSSよりも、Sceneの子ノード(先の例ではBorderPane)に指定したCSSが優先されるためです。

そこで、CSSファイル指定を含むFXMLで定義したレイアウトをSceneに設定している場合、別なCSSファイルをプログラムコードから指定するには、次のようにSceneからrootノード(FXMLでロードしたトップノード)を取得し、そこにスタイルシートを設定します。

        File file = ...
        scene.getRoot().getStylesheets().add(
                file.toURI().toExternalForm()
        );

CSSの書き方

基本的な記法

CSSの基本的な記法は次です。JavaFX CSSもこれに従います。

<セレクター> {
  属性名 : 属性値 ;
  属性名 : 属性値 ;
}

セレクター

CSSでは、セレクターは(HTMLの)要素名、または要素に指定したクラス属性/ID属性です。疑似クラス(hover等)も使えます。
JavaFXでは、セレクターの指定にはCSSにおけるクラス属性およびID属性を使用します。JavaFXのドキュメントでは、CSSのクラス属性を「スタイル・クラス」と呼んでいます。

CSSのルールでは、クラス属性を指定するときはクラス属性名の先頭にピリオド(.)を、ID属性を指定するときはID属性名の先頭にナンバーサイン(#)を付けます。

JavaFXの標準コントロールには、スタイル・クラス(クラス属性)が設定済みなので、そのコントロールすべてにCSSの設定を適用する場合は、設定済みのスタイル・クラスをセレクターに指定します。例えば、Buttonクラスにはクラス属性 "button" が設定されているので、セレクターには ".button"を指定します。

例)すべてのJavaFX標準ボタンの背景色を赤に設定する

.button {
  -fx-background-color: red;
}

JavaFXのレイアウト部品には、スタイル・クラス(クラス属性)が未設定なので、レイアウト部品にCSSの設定を適用する場合は、レイアウト部品にスタイル・クラスを指定するか、後述のID属性を指定する必要があります。

独自のスタイル・クラス

独自のスタイル・クラスを個々のインスタンスに設定するには、getStyleClass().add(スタイル・クラス名)を使用します。

例)キャンセルボタンの文字色を指定
Javaコードでキャンセルボタンのインスタンスにスタイル・クラスを設定

    @FXML Button cancelButton;
      :
    cancelButton.getStyleClass().add("cancel-button");

CSSファイルでキャンセルボタンに文字色を設定

.cancel-button {
  -fx-text-fill: #006464;
}

どのコントロールにどんなスタイル・クラスが付けられているかは、「JavaFX CSSリファレンス・ガイド2」 に記載されています。なお、レイアウト部品系にはスタイル・クラスの設定がありません。リファレンス・ガイドに、「スタイル・クラス: デフォルトでは空」と記載されている部品がそうです。

このあたりを以前はてな日記に記載しました。
JavaFX 8でcssファイルに定義したHBoxのスタイルが反映されない
画面の背景をCSSで一括設定するには

独自のID

JavaFXの部品インスタンスには、setId(ID名)でID属性を設定できます。

例)id属性alfaを指定したボタンの文字色を指定
JavaコードでボタンのIDを設定

    @FXML Button alfaButton;
      :
    alfaButton.setId("alfa");

CSSファイルでalfaボタンに文字色を設定

#alfa {
  -fx-text-fill: #802020;
}

階層指定

シーングラフ上であるノードの下にあるノードだけを限定的に指定することが可能です。

.some-pane .button {
  -fx-text-fill: red;
}

.some-pane .buttonのように空白で区切ってセレクターを並べた場合、最初のセレクターで指定されるノード以下の階層のどこかに次のセレクターが存在するときだけ適用されます。
.some-pane > .buttonのように、">"で区切ってセレクターを並べた場合、最初のセレクターで指定されるノードの直下に次のセレクターが存在するときだけ適用されます。

擬似クラス

ラベルを非活性化(disabled)したときの見栄えは、JavaFXのmodenaでは次の様に記述されています。(分かりやすいようラベルのセレクタのみ抽出)

.label:disabled {
    -fx-opacity: 0.4;
}

ここで、セレクタに:disabledとあるのが擬似クラスとなります。セレクタのクラスがある状態を取るときの定義で、非活性化の他、マウスが部品の上に重なっている間を表す:hoverなどがあります。

独自に擬似クラスを定義したい

非活性化とは異なり部品に操作は可能としたいが、ある状態の間は薄く表示させたいとします。
この状態を:hazeという擬似クラスで定義するとします。

まず、CSSにラベルの擬似クラス:hazeを定義し薄くするため透過度を定義します。

.label:haze {
    -fx-opacity: 0.2;
}

次に、ラベルの状態を切り替える際に擬似クラスを設定します。
トグルボタンが押されているとき(isSelected が true)のときにラベルを:haze状態とする場合を
次のコードに示します。

private static final PseudoClass HAZE_PSEUDO_CLASS = PseudoClass.getPseudoClass("haze");
@FXML private ToggleButton toggle;
@FXML private Label label;
    :
public void initialize(URL location, ResourceBundle resources) {
    toggle.selectedProperty().addListener((obs, ov, nv) -> 
        label.pseudoClassStateChanged(HAZE_PSEUDO_CLASS, nv));
    :

CSSの設定例

グラデーションの設定

放射状グラデーション

背景を塗りつぶす場合は、-fx-background-color-fx-background-radius-fx-background-insetsを使います。
今回は、Paneをそのままグラデーションで塗りつぶすので、-fx-background-colorを指定します。

#myPane {
  -fx-background-color:
    radial-gradient(center 50% 50%, radius 50%, blue, green 50%, blue 80%, green 95%, black);
}

ポップアップメニューの設定

Modenaの設定

Java SE 8のデフォルトテーマ(Modena)で表示されるポップアップメニューは次です。

popupmenu-1.png

ポップアップメニューの下敷きはContextMenuクラスなので、modenaの設定を調べると次のように定義されています。


.context-menu {
    -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-padding: 0.333333em 0.083333em 0.333333em 0.083333em; /* 4 1 8 1 */
    -fx-effect: dropshadow( gaussian , rgba(0,0,0,0.2) , 12, 0.0 , 0 , 8 );
}
  • -fx-color の設定は次のようになっています(明るい灰色)
      -fx-base: #ececec;
      -fx-color: -fx-base;
    

ポップアップメニューの各メニュー項目はMenuItemクラスなので、modenaの設定を調べると次のように定義されています。

.menu-item {
    -fx-background-color: transparent;
    -fx-padding: 0.333333em 0.41777em 0.333333em 0.41777em;  /* 4 5 4 5 */
}
.menu-item > .left-container {
    -fx-padding: 0.458em 0.791em 0.458em 0.458em;
}
.menu-item > .graphic-container {
    -fx-padding: 0em 0.333em 0em 0em;
}
.menu-item >.label {
    -fx-padding: 0em 0.5em 0em 0em;
    -fx-text-fill: -fx-text-base-color;
}
.menu-item:focused {
     -fx-background: -fx-selection-bar;
     -fx-background-color: -fx-background;
     -fx-text-fill:  -fx-text-background-color;
}
.menu-item:focused > .label {
    -fx-text-fill: -fx-focused-text-base-color;
}
.menu-item > .right-container {
    -fx-padding: 0em 0em 0em 0.5em;
}
.menu-item:show-mnemonics > .mnemonic-underline {
    -fx-stroke: -fx-text-fill;
}

メニューアイテムは透過なので、背景のポップアップの色となります。

メニューアイテムの文字は、通常時、フォーカス時に別な色が設定されています。
通常時のテキスト色は次に示すようにCSSのladder関数で定義されます。

    -fx-text-base-color: ladder(
        -fx-color,
        -fx-light-text-color 45%,
        -fx-dark-text-color  46%,
        -fx-dark-text-color  59%,
        -fx-mid-text-color   60%
    );

  • -fx-color(=-fx-base=#ececec)は、明度92なので、-fx-text-base-colorの値は-fx-mid-text-color(#333)になります。
    ladder関数は、第1引数の色の明度に基づき、第2引数以降の任意個数のストップから構成されるグラディエーションの中から1つの値を決定します。明度が0%だとグラデーションの0.0側、明度が100%だとグラデーションの1.0側が使われます。

フォーカス時のテキスト色

    -fx-focused-text-base-color : ladder(
        -fx-selection-bar,
        -fx-light-text-color 45%,
        -fx-dark-text-color 46%,
        -fx-dark-text-color 59%,
        -fx-mid-text-color 60%
    );

  • -fx-selection-bar(=-fx-accent=#0096C9)は明度78なので、-fx-focused-text-base-colorの値は-fx-mid-text-color(#333)となります。
  • テキストの色指定で使われる個々の色定義
        -fx-dark-text-color: black;
        -fx-mid-text-color: #333;
        -fx-light-text-color: white;
    

メニューアイテム

メニューアイテム(MenuItemクラス)のCSS定義でフォントサイズを変更します。

.menu-item {
    -fx-font-size: 20;
}

popupmenu-2.png

スライダーの目盛りラベル

スライダー(Sliderクラス)で目盛りラベルのフォントサイズを変更します。

JavaFX CSSリファンレンスのSliderの項を見ても、目盛りラベルのプロパティは見当たりません。そこで、Slider項のサブストラクチャとしてaxis(目盛り)があるのを見つけ、Axis項のプロパティを調べます。Axis項はチャートに分類されていますが、SliderもAxisを使用しています。

.slider .axis {
    -fx-tick-label-font-size: 1em;
}

スライダーの目盛りだけを指定するため、セレクターにはSliderの階層下にあるAxisを指定しています。

テーブルの設定

セルのテキスト

ツール

Scene Builder

Scene Builderには、CSS Analyzer機能があります。「View]メニュー > [Show CSS Analyzer]をクリックします。

SceneBuilder_ViewMenu-1.png

すると、画面下部に選択した部品に適用されるCSSプロパティの一覧が表示されます。

SceneBuilder_CSSAnalyzer-2.png

上述は、Sliderの目盛りを調べているところです。

コード

CSS(外部ファイル)で適用したスタイルをコードで取得

CSSで指定したスタイルの情報は、個々のコントロールからは取得できません。そこで、ルートノード等からセレクターを指定して取得します。

        text3.getParent().lookup("#meiryoui").getCssMetaData().stream()
                .filter(p->p.getProperty().equals("-fx-font-family"))
                .findFirst()
                .ifPresent(System.out::println);
  • AnchorPaneにスタイルシートファイルを設定し、text3がAnchorPaneに貼られている場合のコード

参考文献

オラクル公式ドキュメント

1 JavaFX: JavaFX UIコンポーネントの操作 37 CSSによるUIコントロールのスタイル設定(Java SE 8ドキュメントの一部)
http://docs.oracle.com/javase/jp/8/javafx/user-interface-tutorial/apply-css.htm

2 JavaFX CSS リファレンス・ガイド(Java SE 8ドキュメントの一部)
http://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/doc-files/cssref.html


4ヶ月前に更新