
Web では Material Design Icons や FontAwesome などのアイコン ・ セットに人気が集まっています。これらのアイコンは画像ではなく Web フォントとして作成されており、 自由に大きさや色が変えられるという特徴があります。
アイコンにフォントではなく画像を使っていた時代は、 サイズや色ごとに何種類も用意しておかなければならず大変でした。便利になったものです。
Web だけでなく、 デスクトップアプリケーションでもサイズや色が自由に変えられるアイコン使いたいですよね? JavaFX なら簡単に Material Design Icons や FontAwesome など様々なアイコンが使えちゃうんです! もちろん、 CSS でサイズや色を自由自在に変えられますよ。
今日は、 JavaFX で様々なアイコン ・ パックが使えるようになるライブラリ Ikonli を紹介します。(Swing でも Ikonli を使用することができますが、 今回は JavaFX での使用方法のみ説明します。)
Ikonli ライブラリを使う手順
JavaFX で Ikonli バージョン 11.3.4 を使う場合、 以下の 2 つのライブラリが必須です。(バージョンによってファイル名のバージョン部分は異なります。)
- ikonli-core-11.3.4.jar
 - ikonli-javafx-11.3.4.jar
 
上記に加えて、 使いたいアイコン ・ パックごとに固有のライブラリを追加します。たとえば、 Material Design Icons を使う場合は以下のライブラリを追加します。
- ikonli-materialdesign-pack-11.3.4.jar
 
FontAwesome を使うなら以下のライブラリを追加します。
- ikonli-fontawesome5-pack-11.3.4.jar
 
複数のアイコン ・ パックを同時に使うこともできます。好きなだけアイコン ・ パックのライブラリを追加してください。
Ikonli のライブラリ (JAR ファイル) は、 上記 URL から直接ダウンロードすることができますが、 JAR ファイルを個別にダウンロードする方法よりも、 Gradle で依存ライブラリを指定する方法をオススメします。
Gradle を使っている場合は、 build.gradle に以下のように依存関係を記述します。
build.gradlerepositories {
	jcenter()
}
dependencies {
	implementation 'org.kordamp.ikonli:ikonli-javafx:11.3.4'
	implementation 'org.kordamp.ikonli:ikonli-materialdesign-pack:11.3.4'
}
ikonli-core は明示的に指定しなくても大丈夫です。ikonli-javafx が ikonli-core に依存しているので、 ikonli-javafx を指定すれば ikonli-core も自動的に適用されます。
上記の例では ikonli-materialdesign-pack を指定していますが、 FontAwesome が使いたいなら ikonli-fontawesome5-pack を指定します。アイコン ・ パックごとのモジュール名は Ikonli のサイトで確認できます。
FXMLでアイコンを指定する
Ikonli のライブラリ (JAR) が参照できたら使い方は簡単です。
アイコン本体である FontIcon クラスは javafx.scene.Node を先祖に持っているので、 シーングラフの大体どこでも使うことができます。(他ノードの親にはなれませんが。)
基本的には、 Button クラスや MenuItem クラスの graphic プロパティに FontIcon を指定することが多いと思います。編集ボタンに鉛筆のアイコンを表示する場合は↓こんな感じです。
FXML<?import javafx.scene.control.*?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
・・・ 省略 ・・・
<Button fx:id="btnEdit" text="編集">
	<graphic><FontIcon iconLiteral="mdi-pencil"/></graphic>
</Button>
iconLiteral に使いたいアイコンの名前を指定するだけです。Ikonli のサイトから、 それぞれのアイコン ・ パックの Cheat-Sheet というリンクを開けば、 アイコンの見た目とその名前 (name) を調べることができます。
- Material Design Icons の Cheat-Sheet (例)
https://aalmiray.github.io/ikonli/cheat-sheet-materialdesign.html 
アイコンの名前にはプリフィックスが付いており、 他のアイコン ・ パックとアイコンの名前が重複しないようになっています。Material Design Icons なら mdi-、 FontAwesome5 なら fab- といった具合です。このプリフィックスのおかげで、 複数のアイコン ・ パックを同時に導入しても一意にアイコンを特定できるんですね。
とりえあえずサンプルプログラム
まずは、 何も考えずに FontIcon を FXML に追加したサンプルプログラム全体です。
SampleApp.javapackage com.example;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class SampleApp extends Application {
	public static void main(String[] args) {
		launch(args);
	}
	@Override
	public void start(Stage primaryStage) throws Exception {
		primaryStage.setTitle("JavaFX でアイコンを使うサンプル");
		FXMLLoader loader = new FXMLLoader(getClass().getResource("SampleApp.fxml"));
		Parent root = loader.load();
		Scene scene = new Scene(root);
		primaryStage.setScene(scene);
		primaryStage.show();
	}
}
SampleApp.fxml<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<?import javafx.geometry.Insets?>
<?import org.kordamp.ikonli.javafx.FontIcon?>
<StackPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
		   stylesheets="@SampleApp.css"
		   prefWidth="360" prefHeight="180">
	<BorderPane>
		<top>
			<MenuBar>
				<menus>
					<Menu text="ファイル">
						<MenuItem fx:id="menuFileOpen"
								text="ファイルを開く...">
							<graphic><FontIcon iconLiteral="mdi-folder"/></graphic>
						</MenuItem>
						<MenuItem fx:id="menuFileSaveAs"
								text="名前を付けて保存...">
							<graphic><FontIcon iconLiteral="mdi-content-save"/></graphic>
						</MenuItem>
						<SeparatorMenuItem/>
						<MenuItem fx:id="menuFileExit"
								text="終了">
						</MenuItem>
					</Menu>
				</menus>
			</MenuBar>
		</top>
		<center>
			<ImageView>
				<Image url="/img/duke.png"></Image>
			</ImageView>
		</center>
		<bottom>
			<HBox alignment="CENTER_RIGHT" spacing="10">
				<padding><Insets top="0" right="10" bottom="10" left="0"/></padding>
				<Button fx:id="btnAdd"
						text="新規作成">
					<graphic><FontIcon iconLiteral="mdi-plus"/></graphic>
				</Button>
				<Button fx:id="btnEdit"
						text="編集">
					<graphic><FontIcon iconLiteral="mdi-pencil"/></graphic>
				</Button>
				<Button fx:id="btnDelete"
						text="削除">
					<graphic><FontIcon iconLiteral="mdi-delete"/></graphic>
				</Button>
			</HBox>
		</bottom>
	</BorderPane>
</StackPane>
SampleApp.css.root {
	-fx-font-family: "Meiryo";
	-fx-font-size: 12px;
}
.button {
	-fx-min-width: 90px;
	-fx-alignment: center-left;
}
このサンプルプログラムを実行した結果がこちらです。

なんだかアイコンがテキストよりも一回り小さいですね…。
アイコンをCSSでカスタマイズしよう
というわけで、 CSS でアイコンの大きさを調整してみましょう。
- JavaとCSSの「クラス」は違うもの?
 - Java の文脈で出てくる 「クラス」 と CSS の文脈で出てくる 「クラス」 は異なるものです。JavaFX では混同を避けるために CSS の文脈で出てくる 「クラス」 のことを 「CSS スタイルクラス」 または 「スタイルクラス」 と呼んでいます。
 
JavaFX の CSS では Java のクラス名を CSS の要素名として使うことができます。FontIcon クラスに CSS プロパティを適用するには、 CSS の要素名として FontIcon を指定します。
FontIcon には 3 つのプロパティがあります。
| プロパティ名 | 説明 | 
|---|---|
| -fx-icon-code | アイコンを識別するリテラル (名前) です。 | 
| -fx-icon-size | アイコンのサイズ。単位はピクセルです。 | 
| -fx-icon-color | アイコンの色。カラー名称や 16 進トリプレット表記で指定します。 | 
アイコンのサイズと色を変える場合はこんな感じになります。(アイコンの黒が強調され過ぎているような気がしたのでほんの少し明るい色にしてみました。)
SampleApp.css に追加する内容FontIcon {
	-fx-icon-size: 17;
	-fx-icon-color: #202020;
}
さて、 これでもう一度、 サンプルプログラムを実行してみましょう。

どうですか? さっきよりも文字とアイコンの大きさのバランスがとれてますよね。分かりにくいですが黒色も少し明るくなりキツさが低減されてます。
- アイコンの大きさをいろいろと試した結果、 テキストの大きさ 12 ピクセルに対して 
FontIconの大きさ 17 ピクセルがバランスが良さそうでした。 
メニューも展開してみましょう。うん、 まあ、 悪くはないですね。

次に、 メニューにフォーカスを当ててみると…

うーん、 これは残念。フォーカスの当たっているメニューの文字色は反転して白になっているのにアイコンは黒のままです。
フォーカス状態に合わせてアイコンの色を変えよう
ご安心ください。Ikonli はきちんと JavaFX プロパティに対応しているので、 CSS 擬似スタイルクラスと連動してアイコンの色を変えることだって簡単にできちゃうんです。
SampleApp.css に追加する内容.menu-item:focused FontIcon {
	-fx-icon-color: -fx-selection-bar-text;
}
メニューアイテムを表わすスタイルクラス .menu-item にフォーカス状態を示す :focus 擬似スタイルクラスが付いているときの下位にある FontIcon の色を指定しています。指定している -fx-selection-bar-text はビルトイン変数で既定では選択状態のテキストに使われる色を表わしています。
この状態でサンプルプログラムを実行するとこうなります。

いいですね! フォーカスの当たっているメニューのアイコンが白くなっています。
ついでに、 フォーカスが当たっていないメニューアイコンの色も変えてみましょうか? :focus 擬似スタイルクラスが付いていないときの色を指定するだけです。
SampleApp.css に追加する内容.menu-item FontIcon {
	-fx-icon-color: -fx-selection-bar;
}
色指定にはビルトイン変数 -fx-selection-bar を使ってみました。これは、 JavaFX のアクセントカラー (既定では鮮やかな青) と同じになります。
この時点で CSS 全体はこうなっています。
SampleApp.css.root {
	-fx-font-family: "Meiryo";
	-fx-font-size: 12px;
}
.button {
	-fx-min-width: 90px;
	-fx-alignment: center-left;
}
FontIcon {
	-fx-icon-size: 17;
	-fx-icon-color: #202020;
}
.menu-item FontIcon {
	-fx-icon-color: -fx-selection-bar;
}
.menu-item:focused FontIcon {
	-fx-icon-color: -fx-selection-bar-text;
}
サンプルプログラムを実行してみます。

雰囲気が明るくなりました。
作成したサンプルプログラムは以下のリンクからダウンロードできます。(Gradle プロジェクト形式になっています。)
JavaFX でアイコン ・ フォントを使えるようにする Ikonli ライブラリの紹介は以上です。