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

# 基本実装
```text:フォルダ構成
`-src/main/
  |-java/
  | `-sample/javafx/
  |   `-Main.java
  |
  `-resources/
    |-main.fxml
    `-main.css
```

```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;
}
```

```java: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();
    }
}
```

# 普通に設定した場合
```xml: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" />
```

**実行結果**

![javafx.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/2f84e14b-a37e-b4d0-b27c-21272b2a4ca5.jpeg)

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

**Scene Budiler で見た場合**

![javafx.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/045592b8-af2b-c559-bf43-ef8db08ef286.jpeg)

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

## 説明
```xml:main.fxml
<Label stylesheets="main.css" ... />
```

- ノードに CSS ファイルを指定するには `stylesheets` 属性に CSS ファイルのパスを指定する
- このパスは、**クラスパスのルートからの相対パス**になる

[getStyleSheets() | Scene (JavaFX 8)](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/Scene.html#getStylesheets--)

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

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

# Scene Builder でも同じように見えるように設定する
```xml: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" />
```

**実行結果**

![javafx.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/75d73f23-5ecb-fd0e-5457-90be59302d1e.jpeg)

**Scene Budiler で見た場合**

![javafx.jpg](https://qiita-image-store.s3.amazonaws.com/0/28302/b878de95-5003-2e28-b951-1d514545a435.jpeg)

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

## 説明
```xml:main.fxml
<Label stylesheets="@main.css" ... />
```

- `stylesheets` のパス指定を `@` で始まるように指定する
- すると、このパスは、**その fxml ファイルからの相対パス**扱いになる

[場所解決 | FXMLの概要 | JavaFX 8.0](https://docs.oracle.com/javase/jp/8/javafx/api/javafx/fxml/doc-files/introduction_to_fxml.html#location_resolution)

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

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