表示領域の制御 - clip
エントリーがパタリと止まってしまいましたが、JavaFXに飽きた訳ではありませんw
このところは地味な改修とかが多くてブログのネタもなかっただけです。というわけで、これからは本当にちょっとしたネタを書いていく予定です。
さて、タイトルのclipと表示領域の制御についてです。JavFXではHTMLのようにGUIのコンポーネントは階層構造を持ちます(シーングラフ)。この考え方はIllustrator等のグラフィックツールにおけるグループ化やレイヤー分けの概念に近いものです。したがって、親コンポーネントの描画領域よりも子コンポーネントの描画領域が大きいというケースは十分に考えられます。また、次のようにある描画領域の内部にのみ他のノードを描画したいケースは多々あるでしょう。
Stage { scene: Scene { width: 200 height: 100 content: [ Group { layoutX: 10, layoutY: 10 content: [ Rectangle { width:100, height: 40, fill:Color.LIGHTYELLOW } Text { layoutY: 20, content: "Hello, Hello, Hello, Hello" } ] } ] } }
このような場合、Nodeクラスに定義されているclipが有効です。
Node#clip
clipはそのノードに対して切り抜くシェイプを指定します。つまり、指定したシェイプで『型抜き』を行う訳です。
したがって上のサンプルを意図通りに型抜きしたい場合、次のようなコードをGroupに追加します。
Group { layoutX: 10, layoutY: 10 content: [ Rectangle { width:100, height: 40, fill:Color.LIGHTYELLOW } Text { layoutY: 20, content: "Hello, Hello, Hello, Hello" } ] clip: Rectangle { width:100, height: 40} }
実行するとこうなります。
また、clipで指定するノードは矩形でなくても構いません。円形にクリッピングすることも星形にクリッピングする事も簡単に出来ます。
注意点
コードの重複を気にしていくと、次のように記述したくなるかもしれません。
var rect: Rectangle = Rectangle { width:100, height: 40, fill:Color.LIGHTYELLOW }; // 略 Group { layoutX: 10, layoutY: 10 content: [ rect, Text { layoutY: 20, content: "Hello, Hello, Hello, Hello" } ] clip: rect }
しかし、このコードは実行時エラーを発生させます。
Exception in trigger:
java.lang.IllegalArgumentException: illegal assignment of group.content: group=Group node=Rectangle
これは、JavaFXで配置するシーングラフの各ノードは複数回、Stage(Scene)に配置する事は出来ない事に起因します*1。ここで仕様しているclipは1つのノードとしてシーングラフ上に配置されている為、矩形の使い回しはできないのです。
次のようなコードで重複を回避するのが妥当でしょう。
var rect: Rectangle; // 略 Group { layoutX: 10, layoutY: 10 content: [ rect = Rectangle { width:100, height: 40, fill:Color.LIGHTYELLOW }, Text { layoutY: 20, content: "Hello, Hello, Hello, Hello" } ] clip: Rectangle { width: bind rect.width, height: bind rect.height } }
初期化のタイミングの関係でclipのRectangleが先に初期化される為、contentのrectの幅・高さを反映する為にbindを使っています。rectの大きさが不変であれば、postinitなどで遅延初期化するなどの方法でも構いません*2。