JavaFx の3つの矩形境界 LayoutBounds, BoundsInLocal, BoundsInParent の違い


はじめに

JavaFx のさわり始めに、必ず混乱する 3つの矩形境界 LayoutBounds, BoundsInLocal, BoundsInParent について説明します。


Transformation と effect

テキスト Text を作成し、回転とドロップシャドウ効果を付けたものを考えます。

// テキスト
var text = new Text("Text");
text.setFont(new Font(30));
text.setTextOrigin(VPos.TOP);

// 回転
text.setRotate(30);

// ドロップシャドウ
DropShadow ds = new DropShadow();
ds.setOffsetY(3.0f);
text.setEffect(ds);

var pane = new StackPane(text);
stage.setScene(new Scene(pane, 320, 240));
stage.show();

この時、 LayoutBounds, BoundsInLocal, BoundsInParent のそれぞれは以下のようになります。

オレンジ色が LayoutBounds, 緑色が BoundsInLocal, 青色が BoundsInParent に該当します。

  • オレンジ色 LayoutBounds [x:0.0 y: 0.0 width:55.3 height:39.9]
    • テキストノードの座標系におけるジオメトリ(テキスト形状)の領域(図形ジオメトリの strokeWidth (線の太さ)の外周を含む)
  • 緑色 BoundsInLocal [x:-9.0 y: -6.0 width:73.3 height:57.9]
    • テキストノードの座標系における、ノードの矩形境界で、ジオメトリに対する clip および effect で設定される効果を含む
  • 青色 BoundsInParent [x:111.9 y: 79.1 width:92.4 height:86.8]
    • 親ノード(ここでは StackPane)座標系における、テキストノードの矩形境界
    • transforms scaleX scaleY rotate layoutX layoutY translateX translateY による座標変換が適用されたもの


Plain

回転やドロップシャドウ効果などを適用しない、単純なテキストノードの場合は以下のようになります。

var text = new Text("Text");
text.setFont(new Font(30));
text.setTextOrigin(VPos.TOP);

var pane = new StackPane(text, rect);
stage.setScene(new Scene(pane, 320, 240));

この場合は、LayoutBounds と BoundsInLocal は同じになります。

  • LayoutBounds [x:0.0 y: 0.0 width:55.3 height:39.9]
  • BoundsInLocal [x:0.0 y: 0.0 width:55.3 height:39.9]
  • BoundsInParent [x:132.0 y: 100.0 width:55.3 height:39.9]

BoundsInParent も同じ領域を親の座標系から見ただけの値となります。


Transformation

以下のように回転のみを適用した場合は以下のようになります。

var text = new Text("Text");
text.setFont(new Font(30));
text.setTextOrigin(VPos.TOP);

text.setRotate(30);

var pane = new StackPane(text, rect);
stage.setScene(new Scene(pane, 320, 240));

こちらも、LayoutBounds と BoundsInLocal は同じになります。

  • LayoutBounds [x:0.0 y: 0.0 width:55.3 height:39.9]
  • BoundsInLocal [x:0.0 y: 0.0 width:55.3 height:39.9]
  • BoundsInParent [x:125.7 y: 88.8 width:67.8 height:62.2]

BoundsInParent は回転により矩形領域が拡大されています。


effect

最後にドロップシャドウ効果だけを適用した場合です。

var text = new Text("Text");
text.setFont(new Font(30));
text.setTextOrigin(VPos.TOP);

DropShadow ds = new DropShadow();
ds.setOffsetY(3.0f);
text.setEffect(ds);

var pane = new StackPane(text, rect);
stage.setScene(new Scene(pane, 320, 240));

この場合は、LayoutBounds はドロップシャドウが適用されていないジオメトリの矩形領域、BoundsInLocal はドロップシャドウが適用された、ノードの矩形領域となります。

  • LayoutBounds [x:0.0 y: 0.0 width:55.3 height:39.9]
  • BoundsInLocal [x:-9.0 y: -6.0 width:73.3 height:57.9]
  • BoundsInParent [x:123.0 y: 94.0 width:73.3 height:57.9]

BoundsInParent は、BoundsInLocal と同じ領域を親の座標系から見ただけの値となります。


まとめ

  • LayoutBounds
    • ノードのレイアウト計算に使用する必要がある矩形境界
    • サイズ変更可能なノード・タイプの場合は常に 0,0 width x height (ボタンのようなControl や Region、またはWebView)
    • Shape、TextまたはGroup のような、レイアウトに応じたサイズ変更が不可なノード・タイプの場合はジオメトリ・プロパティに基づいて計算された値
    • クリップ clip、効果 effect または変換 Transformation は含まない
  • BoundsInLocal
    • ローカル座標系における、そのNodeの矩形境界
    • クリップ clip、効果 effect を含む
  • BoundsInParent
    • そのノードの親座標系における、Nodeの矩形境界
    • 変換 Transformation を含む(transforms scaleX scaleY rotate layoutX layoutY translateX translateY)