JavaFX Scene BuilderでのContainers(土台)部の違いについて

JavaFX Scene BuilderでのContainers(土台)部の違いについて

Java を勉強してみたくて GUI アプリを試作してるんですが、まず JavaFX のコンテナ部分でいきなりつまずいたのでまとめておきます。


関連記事

  1. 初めてJavaを触った人間がEclipseでJavaFXのGUIアプリを起動するまで
  2. JavaFX Scene BuilderでのContainers(土台)部の違いについて ←NOW!
  3. JavaFXでウィンドウにボタンを配置してクリックでメッセージを出力する
  4. JavaFXでインプットダイアログの結果をアラートで表示する
  5. JavaFXでテキストフィールドに値を入れたり取得したり

順番に見てもらったほうがわかりやすいと思います。

書いたときの環境

  • JDK 8u121
  • Eclipse4.6 NEON
  • Scene Builder 8.3.0
  • Windows7/10

です。

土台の使い方でいきなりつまずく

前述の記事で、Eclipse で JavaFX Project を新規作成するときに UI の言語を FXML にして、こんな感じで設定してみました。

ここの Root-type で選んだものがデフォルトのコンテナになるわけですね。FXML を選択した時点で BorderPane になっていたのでそのままはじめたのですが。

Scene Builder で開く

まずは Eclipse で、前回作った新規 JavaFX Project の Form.fxml を右クリックして、Scene Builder で開いてみます。

するとこんな感じで開きました。左下を見ると BorderPane というコンテナはちゃんとある感じはするのですが…、真ん中になにか、出てきてくれていないものなの…??(私の環境だけ?)

たぶん大きさが 0 になっちゃってて右側のプロパティとかで設定すればいいのかなという気もするけど、そもそも BorderPane がどういうものかまったくわかってなかったので、いったんリセットすることに。

左下の Document の BorderPane を右クリックして、Delete しちゃう。

何もない状態になりました。「Drag Library items here…」と出てるので、ここへコンテナをドラッグすればよさそう。

一番シンプルな Pane にしてみる

Containers を開いて、Pane をドラッグ。

表示されました。

今度は Controls を開いて、このコンテナの中へボタンをひとつドラッグしてみます。

出ましたね。

いろいろ試したのですが、Pane が一番シンプルだしコントロールも置いた場所に配置されるし(置くと自動で整列してくれて、思った場所に配置できないコンテナもあるので)、とりあえず初心者はまずはこれで練習すればいいんじゃないかなと思いました。

別のコンテナの上に Pane を重ねて、という使い方もあって、そういうときにも Pane は使えそうです。

コードを書き換える

Scene Builder でコンテナを変更しちゃったので、このままでは実行してもエラーになってしまいます。Eclipse 上の Form.fxml は右クリックから Scene Builder で開けますが、ダブルクリックすると Eclipse 上でコードを開くことができます。変更点を修正します。

Form.fxml(元)

<?xml version="1.0" encoding="UTF-8"?>
	
<?import javafx.scene.layout.BorderPane?>
	
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.FormController">
	<!-- TODO Add Nodes -->
</BorderPane>

最初は BorderPane だったので、こうなっていたはず。5行目の「fx:controller=”application.FormController”」で、FormController.java と結びついています。

これが、Scene Builder でコンテナをいったん削除して変更したので以下のようになっています。

Form.fxml(変更後)

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.Pane?>

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <Button layoutX="55.0" layoutY="48.0" mnemonicParsing="false" text="Button" />
   </children>
</Pane>

コンテナが BorderPane から Pane になり、Pane の中にボタンが追加されているのがわかりますね。でも、コンテナを再作成したこの Form.fxml には FormController.java との結びつきがなくなってしまっているので、このままでは使えません。

<Pane (略) fx:controller="application.FormController">

上の6行目の末尾へ、こんな感じに追記して FormController から使えるようにします。

Main.java(元)

package application;
	
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.fxml.FXMLLoader;


public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			BorderPane root = (BorderPane)FXMLLoader.load(getClass().getResource("Form.fxml"));
			Scene scene = new Scene(root,400,400);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}

それともうひとつ。Main.java は新規 JavaFX Project を作成した時に選択したコンテナのコードが書かれているので、コンテナを変更した場合はここも修正が必要です。今回は BorderPane を削除して Pane にしたので、ハイライトの BorderPane という部分を、

Main.java(修正)

package application;

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


public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			Pane root = (Pane)FXMLLoader.load(getClass().getResource("Form.fxml"));
			Scene scene = new Scene(root,400,400);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		launch(args);
	}
}

このように Pane に書き換えれば OK です。コンテナを作り直したとしても、最初と同じ種類のコンテナならここはそのままで大丈夫です。

(個人的には、今度から新規にプロジェクト作るときは AnchorPane にしとこうと思いました。)

それと、15行目。デフォルトでこう書かれているのですが、このままだと Scene Builder でせっかく大きさを変えても、こちらの 400×400 が優先されてしまうので、ここは消しておいたほうが良いです。

Main.java(修正)

package application;

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


public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			Pane root = (Pane)FXMLLoader.load(getClass().getResource("Form.fxml"));
			Scene scene = new Scene(root);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

	public static void main(String[] args) {
		launch(args);
	}
}

これで、Scene Builder で設定した Pane の大きさがそのまま反映されます。

その他のコンテナ(わかるだけ)

AnchorPane

Pane の上位版みたいな。ただの Pane に慣れてきたらこっちのほうが使えそう。他のコンテナの中にデフォルトで AnchorPane が入ってることも多いです。

Pane との違いを見てみましょう。

ただの Pane の右側に、ボタンが置いてあるとします。この状態で Pane の幅を短くすると、

ボタンが見切れます。当たり前っちゃ、当たり前なんですけどね。

では今度は、AnchorPane の上にボタンを置いてみます。

AnchorPane 上に置いたコントロールを選択すると、右側 Layout の「Anchor Pane Constraints」で場所を固定することができます。このボタンを右から 30px に固定してみます。

コントロールが固定されたので、さっきと同じように AnchorPane の幅を短くしてみても、

ボタンは右側 30px を保ったまま一緒に動いてくれるので、見切れません。

これは Scene Builder 上だけの話じゃなくて、実際アプリを起動したユーザーがウィンドウサイズを変更したときにも適用されるので、わりと重宝しそう。コントロールの固定をしなければ Pane と同様に使えそう。

AnchorPaneの注意点

こちらのページの「まずはFXMLによるGUIのレイアウトを行う」という項目に書かれているとおり、開発環境で AnchorPane でギッチギチにレイアウトしてしまうと、OSなどが違う環境で使おうとしたときに、デフォルトのフォントが違ったりしてコントロールの大きさが変わってしまい、結果めっちゃ崩れるという事態が想定されます。

こういう「綺麗に見えてるのは実は自分のPCだけ」っていう事態(わりとよくある)は悲しいので、他のコンテナの特性も上手に組み合わせながら、自動調整されても大丈夫なような、ゆるっとした作りにしておかないといけないですねー。

HBox、VBox、FlowPane

この3つは、コントロールを整列させて使いたいときに便利です。HBox は横並び、VBox は縦並び、FlowPane はどっちもいける感じ。

HBox の上にコントロールを配置していくと、どんどん右へ並びます。間に挿入することもできます。

並べたら、右側 Layout の Margin で等間隔に余白を設定できます。Margin は外余白、Padding は内余白です。このへん、CSS をかじったことがあれば理解しやすいですね。

VBox は縦並びです。テキストフィールドあたり、こういう感じで並べることありますね。

ではここからは FlowPane との違いについて。

この図は HBox なのですが、コントロールが並んでいる状態で Box 幅を縮めると、

コントロール幅が一緒に縮まってしまいます。VBox も同様らしい(試してないけど)。

そうなるのが嫌な場合、FlowPane 上にコントロールを並べておけば、幅を縮めると、

FlowPane の大きさに合わせて再配置してくれる、という感じみたいです。

HBox、VBox、FlowPane については、一番下の土台として使うというよりは、

こんな感じに、土台となるコンテナに重ねて使うのがいいんじゃないかなと思います。メニューみたいなのを横並びで右上固定したいときなんか、AnchorPane と組み合わせると相性よさそう。

BorderPane

BorderPane は、こんな感じに5つの領域に分かれている Pane ということらしい。「Top」は MenuBar とか入れるのに良さそう。

ScrollPane

ScrollPane をドラッグすると、すでに AnchorPane が載った状態です。

※ScrollPane (empty) っていうのは、何も載ってない状態。自分で Pane や AnchorPane を載せるってことだと思います。

この AnchorPane 上にコントロールを載せていくわけで、AnchorPane の大きさを土台の ScrollPane よりもはみ出させると、スクロールバーが出てきます。

もちろん横方向にも。

SplitPane

SplitPane は縦区切りと横区切りがあり、すでに2つの AnchorPane が載った状態です。

図みたいに、右の Pane の上に ScrollPane を載せてみたら、左は少ないコンテンツ、右は多いコンテンツ、みたいに使えそう。

Accordion

コンテンツを区切って、アコーディオン形式で別々に表示させることができます。Accordion という土台の上に TitledPane というのを載せて、更にそれぞれに AnchorPane が載ってます。ここにコンテンツを作るわけですね。

TabPane

こちらはタブ形式で別コンテンツを表示できるコンテナ。Accordion に似てます。Tab というコンテナ部品を使って、それぞれ AnchorPane を載せた上で、コントロールを配置していくようです。

GridPane

最後にグリッド。縦横等間隔に配置したい場合でしょうかね。

グリッドを増やしたい場合は、Document の GridPane を右クリックして図のように。Row は横方向で Above が上、Below が下へ増えます。Column は縦方向で Before が左、After が右へ増えます。

増えました。

公開日:2017/02/28
更新日:2017/03/24

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください

コメントは承認制ですので、反映までしばらくお待ち下さい。(稀にスパムの誤判定にて届かないこともあるようですので、必要な際はお問い合わせからお願い致します。)

YouTubeでQ&Aコンテンツを企画しています

運営しているYouTubeチャンネルで、ご相談やご質問を募集しています。動画のコメントやお問い合わせページからお気軽にご相談をお寄せください。