JavaFXで丸型ボタンを作ってみる (FXML + CSS + ベクター画像縛り)

はじめに

VAIO Tap 11 を購入したこともあり、Windows8 をよく使うようになったわけですが、Windows8 の Store App を使っていると、次のようなタッチでの利用を意識した丸型で大きめのボタンをよく見かけるようになりました。

で、これと同じようなものを JavaFX でも作ってみようとしました。その際に次のような条件を課すことにしました。

  • FXML と CSS の範囲だけで作る。
    • Java コード側にデザインに関するコードを含めないようにする。
  • アイコンにはビットマップではなくベクターの画像を使う。
    • スケールできるようにしたい。

以下、手順について順に示していきます。

ボタンの作成

まず、ボタンの外形については CSS を使えば簡単に円形にすることができます。
またアイコンについては、JavaFX の Button クラスには graphic プロパティというものがあり、このプロパティに任意の Node を設定することでボタンに画像を表示できるようになります。

というわけでまずは CSS の準備です。ボタンに適用するクラスを作成します。

.circle-button {
    -fx-pref-width: 4.0em;
    -fx-pref-height: 4.0em;
    -fx-background-radius: 2.0em;
    -fx-background-color: null;
    -fx-border-radius: 2.0em;
    -fx-border-color: black;
    -fx-border-width: 2.0px;
}

ポイントは次の通り。

  • background (背景) と border (境界) の両方を調整する必要があります。
  • ボタンの幅、高さと、background、border の角の丸みを調整する radius プロパティを揃えることで円形にします。

さらにマウスオーバー、クリック、無効化の状態に対応するため、hover、pressed、disabled 疑似クラスのスタイルも設定します。

.circle-button:disabled {
    -fx-border-color: rgb(0, 0, 0, 0.7);
}
.circle-button:hover {
    -fx-background-color: #dcdcdc;
}
.circle-button:pressed {
    -fx-background-color: black;
    -fx-border-color: white;
}

無効化の場合は半透明にし、マウスオーバーの場合はうっすらと背景に色をつけるようにしています。クリックされた時には色を反転させています。

このクラスをボタンに適用することで次のような見た目のボタンになります。

アイコンの作成

続いてアイコンに使うベクター画像についてです。JavaFXjavafx.scene.shape パッケージにある各種クラスを利用することでベクター画像を作ることができます。

ですが、凝った画像を Java コードや FXML コードでごりごり書きたくないですよね。 *1
できれば IllustratorInkscape などのベクターグラフィックツールで作成した画像を使ったり、あるいは ネット上でフリーで配布されている素材とかを使いたいところです。

実は JavaFXSVG 形式のパスを取り扱うことができます。先ほど言及した javafx.scene.shape パッケージには SVGPath というクラスがあります。
また、CSS でも Region クラス (Control や Pane などのスーパークラス) には -fx-shape というプロパティがあり、SVG のパス文字列を指定することができます。

以上を踏まえて Scene Builder を使ってベクター形式のアイコン画像を準備する手順について示します。

まず、使いたい SVG 画像をテキストエディタで開き、そのパス文字列をコピーします。

Scene Builder で SVGPath オブジェクトを追加し、その Content プロパティに先ほどコピーしたパス文字列を貼り付けます。すると表示がそのアイコンに変わるはずです。

ボタンにアイコンを設定する

それではボタンに対して準備した画像を設定します。
FXML 上で Button オブジェクトの graphic プロパティに対して先ほど用意した SVGPath オブジェクトを次のように設定すれば OK です。

<Button layoutX="162.0" layoutY="51.0" mnemonicParsing="false" styleClass="circle-button">
   <graphic>
      <SVGPath content="M10,16 10,0 0,8z" styleClass="button-icon-shape" />
   </graphic>
</Button>

これを Scene Builder 上で簡単に行う方法があります。次のように、Hierarchy ビューで Button に対して Shape オブジェクト (ここでは SVGPath オブジェクト) をドラッグアンドドロップすることができ、こうすると、Buttton の graphic プロパティにその Shape オブジェクトが設定されるようになります。

ちなみに CSS では Button クラス (正確には基底クラスの Labeled クラス) に -fx-graphic というプロパティがありますが、このプロパティには URI しか指定できないため、ビットマップ画像のパスを指定するしかありません。

イコン画像もマウスクリックに反応させて色を変えるようにする

これで大体できあがりなのですが、先ほどボタンの疑似クラス設定で、マウスクリック時に色を反転させるように設定したことを覚えているでしょうか?
イコン画像についてもそれに追随させて色を反転させることを考えます。

ここは CSS の機能を利用して実現します。次のように子孫セレクタを使って、クリックされたボタンの子孫に当たる SVGPath に対して、色を反転させる設定が適用されるようにしています。

.circle-button:pressed SVGPath {
    -fx-fill: white;
}

できあがりの例

こんな感じで JavaFXWindows Store App にあるような丸型ボタンを作ることができました。
以下に完成例のスクリーンショットを載せておきます (アイコンの画像は このサイト で配布されているものを使わせてもらいました) 。

この作成例のソースコードは gist にアップしてあります。
https://gist.github.com/aoetk/b5b9a03e1033057224aa

*1:Scene Builder がもうちょっとお絵かきツールとしての機能も強化してくれるといいのですが...。