FX - CSSファイルの場所を fxml ファイルからの相対パスで指定する


基本実装

フォルダ構成
`-src/main/
  |-java/
  | `-sample/javafx/
  |   `-Main.java
  |
  `-resources/
    |-main.fxml
    `-main.css
main.css
.label {
    -fx-font-size: 25pt;
    -fx-text-fill: yellow;
    -fx-underline: true;
    -fx-padding: 10px;
    -fx-background-color: skyblue;
    -fx-font-family: consolas;
}
Main.java
package sample.javafx;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {
    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        FXMLLoader loader = new FXMLLoader(this.getClass().getResource("/main.fxml"));

        Parent root = loader.load();
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

普通に設定した場合

main.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>

<Label stylesheets="main.css" text="Style Sheet" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" />

実行結果

ちゃんとスタイルシートが反映されている。

Scene Budiler で見た場合

スタイルシートの設定が反映されてない。

説明

main.fxml
<Label stylesheets="main.css" ... />
  • ノードに CSS ファイルを指定するには stylesheets 属性に CSS ファイルのパスを指定する
  • このパスは、クラスパスのルートからの相対パスになる

getStyleSheets() | Scene (JavaFX 8)

URLは、[scheme:][//authority][path]形式の階層URIです。
URLに[scheme:]コンポーネントがない場合、URLは[path]コンポーネントのみとみなされます。
[path]の前の「/」文字はすべて無視され、[path]はアプリケーションのクラスパスのルートへの相対パスとして扱われます。

  • つまり、実行時はクラスパスのルートから main.css を見つけられるので正しくスタイルが適用される
  • しかし、 Scene Builder で見た場合は、 Scene Builder のクラスパスからは main.css を見つけられないので、スタイルが適用されない
  • これだと、折角 Scene Builder でグラフィカルに画面を作れるメリットが失われてしまっている

Scene Builder でも同じように見えるように設定する

main.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Label?>

<Label stylesheets="@main.css" text="Style Sheet" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" />

実行結果

Scene Budiler で見た場合

Scene Builder で見た場合もスタイルが適用されている。

説明

main.fxml
<Label stylesheets="@main.css" ... />
  • stylesheets のパス指定を @ で始まるように指定する
  • すると、このパスは、その fxml ファイルからの相対パス扱いになる

場所解決 | FXMLの概要 | JavaFX 8.0

場所解決演算子(属性値への @ 接頭辞で表される)は、属性値を単純な文字列ではなく、現在のファイルを基準にした相対的な場所として処理する必要があることを指定するために使用されます。

  • 結果、 Scene Builder から見た場合も main.css を見つけることができ、スタイルが適用されるようになる