JavaFX アプリケーションを素敵に着飾ってみる

  • 9
    いいね
  • 0
    コメント

この記事は JavaFX Advent Calendar 2016 の2日目です。昨日は @khasunuma さんの「JavaFX の Color クラスを探る」、明日は @skht777 さんです。

概要

JavaFX アプリケーションの見た目を変更する方法、主に CSS の書き方について説明します。

:sun_with_face: JavaFX は CSS で見た目を変えられる

JavaFX は CSS により見た目を変更することが可能です。これにより、デザインと実装の分離が可能となっています。一般に浸透している CSS の記法を採用することで、 JavaFX の採用をより容易にする狙いがあるものと思われます(個人的な推測)。 なお、 CSS の記法は CSS2 準拠だそうです。

JavaFX とは何か?

  • Java で GUI アプリケーションを作るためのライブラリ
  • JavaFX が正しい表記(スペースが入らない)
  • Java 8 から標準の GUI ライブラリになった
  • 今年の Duke's Choice Award を受賞した HeapStats でも JavaFX が使われている(重要)
  • JavaFX 8 の前は2だった

CSS とは何か?

私があえて語るまでもないと思いますが、念のため書きます。間違っていたら編集リクエストください:bow:

  • Cascading Style Sheets の略
  • 見た目の設定を実装から分離して分業をしやすくするための仕組み
  • クラス単位、あるいは ID 単位で要素を指定し、適用したいスタイルを key: value; の形式で記述
  • 一般的には HTML の装飾で使用

実行環境

今回の記事を書く際に試した環境は下記の通りです。

Java SE 1.8.0_102
OS Windows 10
Gradle 3.0

どうやって CSS の書き方を覚えるか?

JavaFX 界のすごい人たちが口を揃えて言うには「Modena を見ろ」とのことです。

Modena とは?

JavaFX 8以降で標準となった CSS テーマです。白とグレーを中心とした、すっきりした見た目をしています。発音は「モディーナ」に近いようです。

Modena の見た目

modena.png

Caspian の見た目

ちなみに、JavaFX 2までの標準だった Caspian も引き続き利用することは可能です。

caspian.png

このように黒っぽさと立体感を感じる見た目で、メニューバーが黒かったり、シャドウが効いていたりします。

Modena の居場所

JDK8 ですと、 jfxrt.jar の中に入っているそうです。

Modenaの入っているJar
$JAVA_HOME/jre/lib/ext/jfxrt.jar

同じものを Gist に上げている方がいるようで、そちらを見てもよいでしょう。modena.css from jdk1.8.0_91

なお、空行含めて 3,427行あります。これを上から見て行ってもおそらく理解は難しいと思います。さすがに「Modenaを見ろ」は厳しすぎる、とはいえ、他の方が書かれた CSS を読む……というのも大して変わらないです。

一から書くのは面倒なので、ベースの色を3つ選択したら CSS を作るツールを以前作りました。
http://qiita.com/y_q1m/items/f56a8ba51bad6ed7f868

今回の記事ではこれを使って説明を致します。


:pencil: CSS の書き方

CSS ドキュメントを見ながら、細部を変えていくことで少しずつ覚えるとよいでしょう。このドキュメントは今年日本語化されたようです。ありがとうございます。

以下、具体的な CSS の適用方法と書き方について軽く説明します。

文字のサイズを変える

スタイルの指定には -fx- という Prefix が必要です。

コードから直接指定する

Node クラスのサブクラスにある setStyle メソッドを使えば、直接スタイルを指定することができます。例えば、フォントサイズを 40pt にしたい場合は下記の通りです。

コードで直接指定
codeArea.setStyle("-fx-font-size: 40pt;");

CSS ファイルにまとめて書いたのを反映する

ファイルに記述したスタイルをまとめて読み込ませるには、Scene オブジェクトが持っている StyleSheets にExternal form URL を渡すことで可能です。その際、CASPIAN か MODENA のどちらかを先に適用しておく必要があるようです(CON2476: Building JavaFX UI Controls参照)。

例えば、user_defined.cssという CSS ファイルを読み込ませるには下記のようにします。

CSS読み込み
final ObservableList<String> stylesheets = stage.getScene().getStylesheets();
if (stylesheets != null) {
    stylesheets.clear();
}

Application.setUserAgentStylesheet("MODENA");// CASPIAN か MODENA のどちらかを先に適用
stylesheets.addAll(Paths.get("user_defined.css").toUri().toString());

CSS ファイルに下記の通り記述し、読み込ませると

.text-area {
  -fx-font-size: 40pt;
}

下記のように TextArea ("Please input text"と表示されている箇所)の文字サイズが 40pt に拡大されます。

ss4.png

何か適当な画像を背景に設定する

CSSファイルから指定

例として、Dドライブ直下の icon.jpg という画像を背景に指定したい場合は下記の通りです。

画像をListCellの背景に指定
.list-cell {
  -fx-background-image: url('file:///D:/icon.png');
  -fx-background-position: center center;
  -fx-background-repeat: stretch;
}

icon.jpg

扇の画像です。

Icon.png

スクリーンショット

ss11.png

ちょっと鬱陶しいですね……使い方は考えないといけません。

Java コード上で指定

コード上から直接指定する場合は下記の通りです。

コード上から背景画像を指定
final String image = Paths.get("path/to/images/splash_bg.jpg").toUri().toString();
controller.background.setStyle(
    "-fx-background-image: url('" + image + "'); " +
    "-fx-background-position: center center; " +
    "-fx-background-repeat: stretch;"
);

ちなみに、画像をjarに同梱する場合は、画像を src/main/resources に配置し、下記のように指定することも可能です。

final String image = getClass().getResource("/splash_bg.jpg").toExternalForm();

参考

コメント

通常の CSS と同様、 /* */`` で囲うことによりコメントを記述できます。

コメント
.root {
  /*
  -fx-background: #EEEEFF;
   */
  -fx-background-image: url('file:///C:/Users/toastkidjp/Pictures/javaone1.jpg');
  -fx-background-position: center center;
  -fx-background-repeat: stretch;
}

色の指定

名前

色の名前で指定することができます。

背景色を赤に指定
-fx-background-color: red;

CSS でサポートされている色は大体使えるようで、Crimson/LightGoldenrodYellow/NavajoWhite/MediumSpringGreen といった色を使えることを確認しています。実際に使える色は「CSSで使用可能な名前付きの色(JavaFX CSSリファレンスガイド)」をご覧ください。

HTMLカラーコード

16進数でRGBを指定する方法です。Android のような透明度の指定はできません。

背景色を#FFFFFF(白)に指定
-fx-background-color: #FFFFFF;

RGBA

透明度を含めた色の指定が可能です。

背景色を白(透過50%)に指定
-fx-background-color: rgba(255.000000, 255.000000, 255.000000, 0.5);

擬似クラス

特定のイベント時に表示を変えることも可能です。JavaFX では disabled/focused/hover/pressed/show-mnemonic がすべての Control でサポートされています。また、ListView では even/odd を使うことができます。

ListView を例にとると、下記のように指定した場合

ListViewの要素の色変更
.list-cell:even {
    -fx-text-fill: #FFFFFF;
    -fx-background-color: Navy
}

.list-cell:hover {
    -fx-text-fill: #FFFFFF;
    -fx-background-color: Crimson;
}

.list-cell:selected {
    -fx-text-fill: #FFFFFF;
    -fx-background-color: Gold;
}

このようにできます。

ss6.png

class と id

HTML のように class や id での指定が可能です。class は Node クラスごとに固有のものが設定されていますのでそれを利用することができますし、
FXML やコード上から指定することも可能です。id も FXML やコードから指定します。

以下、FXML を使っての指定例を示します。

<TableView fx:id="table" prefHeight="130.0" prefWidth="259.0">
  <columns>
    <TableColumn styleClass="tbc" fx:id="personId" prefWidth="75.0" text="ID" />
    <TableColumn styleClass="tbc" fx:id="personName" prefWidth="75.0" text="Name" />
    <TableColumn styleClass="tbc" fx:id="isActive" prefWidth="75.0" text="Active" />
  </columns>
</TableView>

3つの TableColumn に同一の tbc というクラスを、 各列に左から personId, personName, isActive という id を指定しました。

class での指定例

classでの指定
.tbc {
    -fx-text-fill: crimson;
}

.tbc:even {
    -fx-text-fill: crimson;
}

スクリーンショット

ss8.png

id での指定例

idでの指定
#personId {
    -fx-background-color: crimson;
    -fx-text-fill: white;
}

スクリーンショット

ss9.png

root

この class を使うと、すべての Node に対し Style を適用させられます。
手始めにこれだけを変えてみて、見た目の変化を楽しむところから始めてみてもよいでしょう。

例えば、下記のように指定すると

root
.root {
    -fx-base: rgba(0.000000, 11.000000, 22.000000, 0.40);
}

このような表示となります。

ss5.png

Tips

指定が重複した場合はどうなるか?

例えば下記の場合、下の指定が適用されて緑っぽくなります。

.root {
    -fx-base: rgba(103.000001, 58.000000, 183.000004, 1.0);
}

.root {
    -fx-base: rgba(0, 58.000000, 0, 1.0);
}

スクリーンショット

ss13.png

表示したくない要素を display: none; で隠したい

どうやら CSS からではそういった操作ができないそうです。コード上から Node クラスの setManaged(false) を使えば実現できます。この話については以前記事を書いたので、よろしければそちらをご覧ください。

JavaFX アプリケーションに隠し Control を搭載する

表示

@FXML
private void showNode() {
    node.setVisible(true);
    node.setManaged(true);
}

非表示

@FXML
private void hideNode() {
    node.setVisible(false);
    node.setManaged(false);
}

CSS の足りないところ(by Mr. @hansolo_ said)

私は本職の Web デザイナーではないので、JavaFX の CSS で困った点はそれほどないのですが、エキスパートからするといろいろ足りていないようです。Gerrit Grunwald (@hansolo_) 氏のセッション CON1072: The Dark and Light Sides of JavaFX で、CSS Styling の暗黒面を語っていました。

  • -fx- という prefix のせいで Web 標準の CSS と互換性がない
  • 通常の CSS で使えるものが使えない
  • パフォーマンス面の問題がある
  • アニメーションを使えない
  • visibility 操作ができない

ちなみに、関係ない話ですが Grunwald 氏は今年の JavaOne 報告会@東京で「ハン・ソロさんがいる」と軽く話題になっていましたので、ご記憶の方もいらっしゃるかもしれません。

Others

Scenic View

JavaFX の Styling をするのには、すでに良いツールがありました。Scenic View は GUI で CSS を操作できるツールです。今年の JavaOne 2016でBOFセッションにて紹介されていました。詳細はそちらをご覧ください。

Scene Builder

GUI で部品を置きながら JavaFX アプリケーションの UI を作ることができるツールです。かつては公式で配布されていました。現在は Gluon 社のサイトで入手できます。このツールでも CSS の調整やデモが可能だと櫻庭さんから教えていただきました。

JFoenix

  • JavaFX で Material design を実装するためのライブラリ
  • 標準にはない Drawer/Toolbar/Snackbar が使える
  • Apache 2.0 ライセンスで提供
  • 既存のシーングラフ&実装からのマイグレーションが簡単

RichTextFX

  • 高機能な複数行テキスト編集コンポーネントを提供
  • 行番号表示やコードハイライトが可能

まとめ

  • Java で GUI アプリケーションを開発するなら JavaFX を使う
  • JavaFX は CSS で色を変えられる
  • CSS の書き方は使って覚える

デフォルトの Modena も見やすくてよいデザインですが、CSS やライブラリを駆使して、自分の理想とするイカしたデザインのアプリケーションを作ってみるのも面白いでしょう。

参考

リファレンス・ガイド

JavaOne 2016 関連

JavaFX のセッションが多数ありました。CSS と関連するセッションの資料へのリンクを記載いたします。

JJUG CCC 2016 Fall 関連

Color


いただいた質問について

自作の Control に独自のスタイルクラスは設定できるか?

自作のControlの場合、Nodeクラスが持っている styleClass に要素を

getStyleClass().setAll("custom-control");

で追加すれば、

.custom-control {
  /**/
}

で指定できるようになります。

FXML で直に指定できる場合は styleClass を使うことで追加が可能です。

TableColumnにスタイルクラス"tbc"を設定
<TableColumn styleClass="tbc" ...

Slider の目盛はどうやってデザインを変更するか?

.slider .axis の -fx-tick-label-font を使うと変更が可能です。デフォルトでは 8pt/システムフォントが設定されています。

Sliderの目盛文字を20ptに変更
.slider .axis {
  -fx-tick-label-font: 20 system;
}

編集例


おまけ

今回の記事を書く際に使用した JavaFX CSS お試し用アプリケーション

ビルド・実行には Java SE 1.8.0_40 以上の実行環境と Gradle が必要です。GitHub リポジトリ からコードをダウンロードし、$ gradle run で実行できます。

実行例(gitの場合)
$ git clone git@github.com:toastkidjp/javafx_css_generator.git
$ cd javafx_css_generator
$ gradle run

launch.png

起動するとこのように表示されます。

launch2.png

Ctrl+E で CSS 編集用の TextArea が開きます。ここに CSS を記述し、試すことができます。

launch3.png

Ctrl+Enter で TextArea の内容を反映します。

利用 OSS

JavaFX は 3rd Party Library の開発が盛んで、標準では用意されていないリッチな Control を提供するライブラリが多数存在しています。このツールでは 前述の JFoenix(Material design コンポーネント集) と、RichTextFX(行番号表示やコードハイライトが可能な TextArea) を利用致しました。

Library Author GitHub Repository License
JFoenix jfoenix https://github.com/jfoenixadmin/JFoenix Apache 2.0
RichTextFX Tomas Mikula https://github.com/TomasMikula/RichTextFX BSD 2 Clause