はじめに
この文書ではRPiCarを操作するユーザインタフェース(UI)をJavaFXで開発する例を述べます.JavaFXでUIを作成するとき,SceneBuilderを用いると簡単かつ効率的に行なえます.最初にどのようなUIを目指すのか示した後,ステップバイステップでUIを作成する手順を示します.
環境
目指すUI
まずは目指すUIを示します.下の図をご覧ください.上から順番に説明していきます.
距離
まずは前方の物体までの距離です.ここはレーザ式距離センサで得た結果を表示してます.
フォトリフレクタ
距離の下にあるのがフォトリフレクタにより得たRPiCar下の状況です.赤く点灯した場合には白色,消灯している場合には黒色がフォトリフレクタの下にあることを示すようにします.
カメラ
フォトリフレクタの下にある画像はカメラにより撮影されたものです.画像の下にある撮影ボタンを押すことで設営できるようにします.
ビーパとライト
撮影ボタンの左にはビーパボタン,右にはライト点灯ボタンがあります.ビーパボタンを押すとクラクションが鳴動し,ボタンを離すと音が鳴りやむようにします.ライト点灯ボタンはオスとライトが点灯し,ボタンを離しても押されたままにしつつ,ライトの点灯し続けるようにします.再びライト点灯ボタンを押すとライトが消灯するようにしましょう.
モータの制御
残りのコンポーネントはすべてモータを制御するときに用います.まず,上下矢印ボタンはそれぞれ前進と後退をさせるものです.さらに左右にある丸い矢印ボタンは左右の旋回をさせるものです.これら4個のボタンはいずれも押したら押されたままになるようにします.他の動作をさせたいときには新たに行いたい動作のボタンを押すと以前押されていたボタンが解除されるようにします.なお,すでに押されていたボタンを再び押してもボタンの押し状態は解除されないようにします.何もしない状態,つまり停止させるには上記4個のボタン中央にある停止ボタンを押すようにします.
次に,先ほどの5個のボタンの左右にある垂直スライドバーで左右のモータ速度を制御できるようにします.ただし,前進などの上記4動作をする場合,左右モータの回転数を一致させないと正しい動作となりません.一方,例えば大きな弧を描きながら曲がっていくような動作をさせる場合,左右モータの回転数を一致させないこともあります.従いまして,速度のスライドバーは前者の動作時には連動させ,後者の動作時には非連動させるようにします.この連動/非連動を切り替えるため,一番下に連動のチェックボタンを設置します.なお,非連動の動作の場合には前進などの4ボタンはインアクティブにします.
SceneBuilderによるユーザインタフェースの作成
ではSceneBuilderにより,上記のUIを作成していきましょう.まずは全体の骨格を作り,すべてのコンポーネントを配置しましょう.その後,細かなプロパティを修正するような流れで開発を進めていきます.下の図は当面の目標である全体の骨格とすべてのコンポーネントを配置した様子です.このようになるよう,少しずつ進めていきます.
ではScene Builderを立ち上げます.下の図はScene Builderを立ち上げた直後の様子です.今回は上側にのメニューバーを伴うアプリケーションをもとに作成します.
下の図はメニューバーとAncherPaneのみコンポーネントがある状態を表します.このうちAnchorPaneは今回使わないため,まずはこれを削除します.画面左側にはコンポーネントをツリー構造で表されていますので,そこでAnchorPaneを選択し,Delキーで削除しましょう.
まだ全然できていませんが,ひとまず保存しましょう.ここではjp.ac.nagano_nct.ashida_labパッケージにアプリケーションを作成したいため,同名のフォルダを作成し,そこへ保存してください.ファイル名はRPiCarController.fxmlとしておいてください.なお,この後出てくるボタントップに使う画像が含まれるimagesフォルダも同じフォルダに置くことにします.
前方までの距離を表示するコンポーネントの追加
次にPaneを追加しましょう.Paneとは,ウィンドウをいくつかの領域に分割するときに用いるコンポーネントです.分割の仕方によりさまざまなPaneがあります.例えば垂直方向で分割する,水平方向で分割する,マス目状に分割するなどがあります.今回は全体としては垂直方向で分割するPaneを配置し.更に前進などを行うボタン群にはマス目状にコンポーネントを配置できるPaneを入れ子構造で置くようにします.このようにPaneは何層にも入れ子構造にして思い通りの位置にコンポーネントを配置していきます.
では垂直方向にコンポーネントを配置できるVBoxに別のPaneを追加しましょう.VBoxは垂直方向にコンポーネントを配置するときに用いられるPaneです.名前にはPaneと付きませんが.Paneクラスを継承しています.現在,一番トップにあるPaneがVBoxになっています.まずはMenuBarの下にFlowPaneを追加しましょう.下の図のようにContainersの中にあるFlowPaneをVBoxへドラッグ・アンド・ドロップで追加します.FlowPaneはこのPaneの境界で折り返されるように内包したコンポーネントを配置します.今回ははこのFlowPaneにLabelコンポーネントを置き,そのラベルにRPiCarの前方にある障害物等までの距離を表示します.
ではそのLabelコンポー年とを追加しましょう.下の図のようにControls内にあるLabelコンポーネントをFlowPaneへドラッグ・アンド・ドロップします.
次に追加したラベルの位置を中央になるように変えましょう.こう聞くとLabelコンポーネントのプロパティを変えるように感じるかもしれませんがそうではありません.FlowPaneのプロパティにある,そのPane内のコンポーネントの配置位置を変えることでLabelコンポーネントの位置を変えます.ということで,下の図のようにFlowPaneを選択し,右側のPropertiesにあるAlignmentをCENTERへ書てください.
次にFlowPaneの高さをその中に入っているLabelコンポーネントの高さと一致させましょう.これもFlowPaneに関する設定になりますが,先ほどとは異なりLayoutに関するものとなります.このため,下図のようにLayoutを選択し,その中にあるPref HeightをUSE_COMPUTED_SIZEにします.この意味は,FlowPaneの好ましい高さをその中に含まれるコンポーネントの高さと一致させるということです.ここまででRPiCarの前方にあるものまでの距離を表示できるようになりました.
フォトリフレクタの検知結果を表示
次にフォトリフレクタによるRPiCarの下の状態を表示するためのコンポーネントを追加しましょう.先ほどはFlowPaneを追加し,さらにその中へLabelコンポーネントを追加したという流れでした.今回はFlowPaneを追加し,その中に3つのCircleを追加することにします.まずは新たなFlowPaneの追加です.下の図のようにFlowPaneを追加します.前回行ったFlowPaneの追加では,VBoxにドラッグ・アンド・ドロップしましたが,下の図ではツリー構造の一番下に追加しています.いずれも同じ場所に追加されますが,前者の場合にはVBoxの中の一番下へ追加すること,後者はVBoxの中の,任意の場所に追加することになります.ただし,今回の例ではたまたまVBoxの一番下へ追加しただけであり,もしVBoxの下の一番上へ追加したい場合には,その場所を表すオレンジの水平線が現れている場所でドロップすればよいです.
さて,追加されたFlowPaneにCircleを追加していきましょう.JavaFXにはプリミティブな図形を描画するためにいくつかのコンポーネントが用意されています.その一つがCircleです.これを3つ追加しましょう.下の図のように,SceneBuilderの左側にあるShapeを選択し,その中のCircleを画面中央の位置へドラッグ・アンド・ドロップします.コンポーネントの追加方法について,これまではツリー構造に対するものを説明してきました.今回はUIのプレビュー内に置く方法で行いました.もちろんこれまでと同様にツリー構造へドラッグ・アンド・ドロップすることもできます.お好きな方法でコンポーネントを追加してください.
追加されたCircleは大きすぎるため,サイズを調整しましょう.下の図のように画面右のLayoutを選択し,その中のRadius(半径)を100から10にします.これでサイズが小さくなったはずです.同様にあと2個,Circleを追加してください.
3個のCircleを追加した結果が下の図です.ただこのままではFlowLayoutがCircleにフィットしていないこと,また3個のCircleがセンタリングされていないことが問題です.これら2つの問題を解決します.
まずはフィットさせましょう.下の図のように,まずはCircleを含むFlowPaneをツリー構造で選択したのち,画面右のLayoutを選択し,その中のPref HeightをUSE_COMPUTED_SIZEにします.
次にセンタリングです.下の図のように,FlowPaneを選択し,画面右のPropertiesの中のAlignmentをCENTERにします.
撮影画像の表示
次は撮影した画像を表示するコンポーネントを追加しましょう.再びFlowPaneを下図のように追加してください.
そして,追加したFlowPaneにImageViewを追加します.下の図のようにControlsにあるImageViewをFlowPaneにドラッグ・アンド・ドロップしてください.
追加されたImaveViewはFlowPaneの左側に偏っていますので,これをセンタリングします.もうお分かりかもしれませんが,下の図のようにFlowPaneのPropertiesにあるAlignmentをCENTERにしてください.
ここまででImageViewが追加さました.最終的にはカメラで撮影した画像をこのImageViewに表示するため,この段階で画像を表示する必要はありません.しかし画像が表示されていないため,ただの空白のように見えてしまいます.そこでここでは仮に画像を表示しておきます.皆さんが持っている画像を適宜使ってください.下の図のようにImageViewを選択し,Propertiesの中のImageを選択します.こののち,ファイルセレクタが現れますので,手持ちの画像を選択してください.
うまくいくと,下のように画像が現れるはずです.
ビーパ,撮影,ライトボタンの追加
続いてビーパ,撮影,ライトボタンの追加をしていきましょう.この3つのボタンは1つのFlowPane内にあり,横並びになっています.横並びといえばHBoxも使えそうですが,こちらの場合にはボタンが領域全体に広がってしまいます.今回はボタンサイズをボタントップのアイコンサイズにフィットさせたいため,FlowPaneを用いることにします.ではFlowPaneを追加しましょう.下図のように追加してください.
次にButtonコンポーネントを追加します.まずはビーパのためのボタンです.下の図のようにControlにあるButtonコンポーネントをFlowPaneにドラッグ・アンド・ドロップします.
追加されたボタンにはただButtonと書かれています.この文字をスピーカのアイコンに替えましょう.ボタントップにアイコン(画像)を表示するには,前述のImageViewをButtonの配下に置きます.下の図のようにControlsにあるImageViewをButtonの配下にすべくドラッグ・アンド・ドロップします.
次に,アイコンの画像を選択します.以下の図はボタンの配下にあるImaveViewを選択し,画像を選ぶためのボタンを押した様子です.ここで選択する画像はこちらからダウンロードしてください.ダウンロードした圧縮ファイルを解凍するとimagesフォルダ内に入った画像が得られます.このimagesフォルダは,だいぶ前に説明した通り,PRiCarController.fxmlファイルと同じフォルダにおいてください.今回はその中のbeeper.pngを使います.下の図のようにImageViewを選択し,Properties内のImageを変更します.ここではbeeper.pngを選択してください.
下の図はビーパのアイコンが表示されている様子です.このままではビーパの右側に「button」という文字が残ってしまっています.これをまずは消しましょう.
下の図をご覧ください.先ほど追加したButtonコンポーネントがツリー構造に現れています.このButtonコンポーネントの右側に「Button」と書かれています.これがボタントップに書かれる文字列です.今回はこの文字列は不要ですので削除します.Delキーで文字列を削除してください.
次にボタンのサイズを小さくします.このためには,ImageViewのサイズを小さくします.まずはツリー構造からImageViewを選択し,画面右側のLayoutの中のFit Heightをデフォルトの150から50に変更してください.これでボタンのサイズが小さくなるはずです.
同様にして撮影ボタンを追加していきましょう.Buttonコンポーネントを追加,ImageViewを追加,ボタントップの画像を追加,Buttonという文字列を削除,サイズを50に変更という5ステップでできますね.なお,撮影のためのアイコンはsnap.pngを選択してください.下の図は撮影ボタンを追加した様子です.
同じFlowPaneにはヘッドライトを点灯させるときに用いるボタンを追加します.ただしこのボタンは撮影などのボタンとは異なり,押したら押しっぱなしになり,もう一回押すと元に戻るような動きをさせたいですね.この場合にはToggleButtonコンポーネントを用います.下の図はToggleButtonコンポーネントを追加している様子を表しています.
追加されたToggleButtonコンポーネントはボタントップが「ToogleButton」となってしまっています.先ほどのButtonコンポーネントと同様にImaveViewを追加してボタントップを画像にしましょう.下の図はImaveViewを追加している様子です.
追加したImageViewに画像を設定しましょう.今回はhead_light.pngを指定します.下の図は画像を追加したのちの様子を表しています.
ボタントップに文字列は不要ですので,「ToggleButton」という文字列を削除してください.加えて,ImageViewのFit Heightを50にしましょう.下の図はそれらの設定を行った様子を表しています.
あと2つの手続きをします.まずはセンタリングです.先ほどの3つのボタンをセンタリングしましょう.下の図のようにFlowPaneを選択し,Propertiesの中のAlignmentをCENTERにしてください.これですべてのボタンがセンタリングされます.
これらのボタンへの捜査の最後にフィッチングです.ボタンらを包み込むようなFlowPaneにすべく,下の図のようにFlowPaneを選択し,Layoutの中のPref HeightをUSE_COMPUSED_SIZEにすればフィッティングされます.
足回りの操作用コンポーネントの作成
最後に足回りの操作用コンポーネントを作成していきましょう.少しここは複雑です.まずは概要を説明します.足回りの操作用コンポーネント全体でみると,BorderPaneで構成されています.BorderPaneには右・左・下・上・中央の5領域があり,それぞれに別のコンポーネントもしくはPaneを追加していきます.5領域に配置されたコンポーネントの中では中央のものがが最も大きく配置され,それ以外の領域については最小の大きさになるように調整されます.まずはこのBorderPaneを追加しましょう.下の図はBorderPaneを追加した様子です.Containersの中にあるBorderPaneが追加されている様子が分かるでしょうか.
では左右の領域にVBoxを追加しましょう.これらのVBoxにはLabelコンポーネントと速度を調整する垂直方向に伸びたSliderコンポーネントの2つを縦方向に配置します.下の図はVBoxを左側に置いた様子を表しています.
同様にして右側にもVBoxを置いた様子が下の図です.ツリー構造では,BorderPaneの左右領域にそれぞれVBoxがあることが分かります.
それでは追加したVBoxにLabelと垂直なSliderコンポーネントを追加しましょう.下の図は左側のVBoxにLabelを追加したのち,垂直なSliderコンポーネントを追加している様子を表しています.
同様にして,右側のVBoxにもLabelとSliderコンポーネントを追加した様子を下の図で示します.
上記の図ではLabelとSliderコンポーネントが左に寄ってしまっていますのでこれをセンタリングします.センタリングといってもそれぞれのVBox内でのセンタリングです.このため,VBoxのPropertiesにあるAlignmentをCENTERにすればよいです.下の図は左側のVBoxについてセンタリングした様子を表しています.これと同様に,右側のVBoxについてもセンタリングしてください.
ここまでで速度調整をするためのコンポーネントが配置できました.次に進行方向を決定するコンポーネントを配置していきましょう.先ほど追加したBorderPaneの中央に3行3列のGridPaneを追加したのち,前進,後退,左旋回,右旋回,停止をするButtonコンポーネントを配置していきます.
まずはGridPaneを追加しましょう.下の図のようにGridPaneをBorderPaneのCENTERへ追加している様子を示しています.
次にGridPaneを3行3列に変更します.デフォルトでは3行2列になっています.そこでGridPaneを右クリックし,現れるポップアップメニューにあるGridPaneを選択し,さらにその中の前に列を追加を選択します.これで3行3列のGridPaneが出来上がります.
次にボタンを追加していきます.十字になるように5個のButtonコンポーネントを追加していきます.下の図はButtonコンポーネントをGridPaneの中央に配置している様子です.
同じ方法であと4個のボタンを配置してください.ただし,ここで追加する4個のボタンはToggleButtonにしてください.下の図は左旋回させるためのToggleButtonコンポーネントを追加している様子です.同様に前進,後退,右旋回のToggleButtonコンポーネントを追加してください.
下の図は全部で5個のボタンを配置し終えた様子です.この段階ではまだボタントップがアイコンになっていませんし,位置も左に偏っています.この後この2つの対応をしていきます.
まずはボタントップをアイコンにしましょう.下の図は5個のボタン全てにImageViewを追加した様子です.
追加したImageViewにアイコンを設定していきましょう.下の図は中央にあるボタンにアイコンを設定しようとしている様子です.中央のボタンの場合,Button(1,1)と書かれています.この(1,1)が位置を表しています.さて,中央のボタンにはブレーキの役割を果たさせますので,自動車がブレーキをかけているようなアイコンであるbrake.pngを選択します.
同じ方法で他のImageViewにもアイコンを追加していきます.下の表のように,位置と対応するアイコンに気をつけながら追加してください.
位置 | アイコン |
Toggle Button(0,1) | left_rotate_arrow.png |
Toggle Button(2,1) | right_rotate_arrow.png |
Toggle Button(1,0) | up_arrow.png |
Toggle Button(1,2) | down_arrow.png |
下の図は5個のアイコンを設定し終えた様子を表しています.
しかしこのままでは,「Button」「ToggleButton」という文字列が残っていることと,アイコンのサイズが大きいため,ボタンが重なってしまっています.そこでまずは「Button」「ToggleButton」という文字列を削除します.下の図はツリー構造に現れている「Button」「ToggleButton」文字列を消すことを意図したものです.訂正線で書かれている文字列を削除してください.
Button文字列を削除し終えた状態を表したものが下の図です.先ほどよりはいくらか重なりが減りましたが,根本的にアイコンが大きすぎるため,まだ問題が残っています.
下の図は左旋回のアイコンサイズを変更し終えた様子です.該当するImageViewを選択し,右側のLayoutにあるFit Heightのサイズを50にしてください.
同様に他のボタンについてもFit Heightを50にしてください.下の図はすべてし終えた様子です.位置に問題はありますが,サイズは良くなりました.
最後に位置を調整しましょう.GridPaneの中にあるコンポーネント位置は,列もしくは行単位で行うこととなります.具体的には左旋回するButtonコンポーネントが含まれている,左端の列については右寄せにしますし,前進,後退,ブレーキのButtonコンポーネントが含まれる,中央の列についてはセンタリングします.下の図は左端の列を選択し,右寄せにしている様子です.
同様にして真ん中の列についてはCENTER,右端の列は左寄せにしてください.さらに,行についても設定します.一番上の行はBOTTOM,真ん中の行はCENTER,一番下の行はTOPにしてください.下の図はすべての設定をし終えた様子を表しています.
ボタンの位置について,きれいに揃いましたが,それでもまだボタンの重なりが発生してしまっています.この対策として,ウィンドウ全体の高さを変更します.下の図のように,ツリー構造の最も上に位置するVBoxを選択し,左側のLayoutにあるPref Heightを550にします.これですべてのコンポーネントが重ならずに表示できるはずです.
コンポーネントの才知についてはこれが最後になります.CheckBoxコンポーネントの追加です.このCheckboxコンポーネントは左右モータを同期させるか,同期させないかを決めるために設置します.位置はBorderPaneの下になります.下の図はCheckBoxコンポーネントを追加している様子を表しています.
これですべてのコンポーネントを配置し終えました.下の図のように,プレビューメニューの中にあるウィンドウにプレビューを表示を選択してみてください.これまで作ったコンポーネントが別ウィンドウとしてプレビューできます.
スペースの調整,固定できる文字列の設定,色の設定
コンポーネントが代替配置できたところで見た目をもう少しよくしていきましょう.当面の目標は下の図のようになることです.前方までの距離を単位付きで表示できること,フォトリフレクタが反応したときの色をオレンジにすること,左右モータ速度のキャプション,そして連動させるためのCheckBoxのキャプションを変更します.
まずは前方までの距離について設定していきましょう.現在は1つのLabelコンポーネントがあるだけですが,距離を表すLabelコンポーネントと単位を表すLabelコンポーネントに分けようと思います.このため,もう1個のLabelコンポーネントを追加してください.下の図はその様子を表します.
ツリー構造に追加されたLabelコンポーネントのうち,上側(こちらが左に表示されます)が距離,下側(こちらが右に表示されます)が単位にします.デフォルトでは「0mm」となるようにしておきたいため,上側のLabelコンポーネントの文字を0,下側の文字をmmにします.下の図はそのように設定した結果です.
上記のままでは0とmmの間がややつまり過ぎており余裕がありません.そこで0とmmの間にスペースを置くことにします.今回は0の右側に15のスペースを空けます.それには下の図のように,0と書かれているLabelコンポーネントを選択し,右側のLayoutの中にあるMarginを15に変更します.このMarginには4個の数字を入力するところがあります.左から上側,右側,下側,左側の各スペースを設定できるようになっています.今回は0の右側に15のスペースを空けるため,下の図のようになったわけです.
次にフォトリフレクタの検知し結果を表示するCircleの色を変えましょう.まずは左端のCircleを選択してください.そして,下の図のように右側のPropertiesの中のFillを選択してください.
次に色を入力します.今回は赤255,緑213,青0にします.これを16進数で表すと,#ffd500となります.これを設定している様子が下の図です.
同様の操作を真ん中と右側のCircleにも行った結果が下の図です.
上の状態ではCircleが近づきすぎています.そこでスペースを空けましょう.今回は真ん中のCircleを選択し,左右に30のスペースを空けます.下の図はその様子を表しています.
次に,クラクションなどのボタンが集まる列のボタンにスペースを作ります.フォトリフレクタと同様に,撮影ボタンの左右にスペースを空けます.ただし今回は20空けます.ここで注意すべきことは,撮影ボタンの選択は左側にあるツリー構造から行ってください.言い方を変えると,プレビューにあるカメラマークを選択してもImageViewを選択されてしまい,Buttonコンポーネントが選択できません.このような理由から,ツリー構造から選択するようにしてください.
次に左右モータの速度を操作するSliderを修正していきましょう.まずはキャプションについてです.現在は左右それぞれに1個だけLabelコンポーネントがあります.これをそれぞれ2個に変更し,上側を「左」と「右」にし,下側をその時の速度にします.デフォルトで速度を0にしますので,下側のLabelコンポーネントは0にしましょう.
ではLabelコンポーネントの追加です.下の図は左側の速度を調整するSliderの上に新たなLabelコンポーネントを追加している様子です.既に存在するコンポーネント(ここではLabelとSlider)の間に追加する場合,この図のような感じで行います.
下の図は右側の速度を調整する方にもLabelコンポーネントを追加するとともに,文字列を修正したものです.
次にSliderコンポーネントを修正しましょう.下の図は左側のSliderを選択し,Propertiesの中のMinを-100,Show Tick Marksにチェックを入れた様子です.このようにすると今回の目標である-100~100までの値を入力できるだけでなく,目盛りもつけることができます.
下の図は右側のSliderコンポーネントも修正した様子です.だいぶできてきました.
最後に連動のCheckBoxを修正しましょう.現在はチェックボックスが左側,文字列が右側にあります.これを逆にするには下の図のように,CheckBoxを選択し,右側にあるPropertiesの中のNode OrientationをRIGHT_TO_LEFTにします.
後はCheckBoxと書かれていた文字列を「連動」に替えます.文字列の変更方法には,ツリー構造の中にある変更したいコンポーネントの文字列をダブルクリックする方法と,プレビューにある文字列をダブルクリックする方法があります.どちらでも構いませんので,連動と文字列を変えてください.下の図は変更した様子です.これで目標としていたUIのレイアウトが完成しました.
コンポーネントに名前を付ける
次に作成したコンポーネントに名前をつけましょう.これにより,後ほど行うプログラムにて,この名前でコンポーネントを指定して操作できます.従いまして,すべてのコンポーネントに名前を付ける必要はなく,プログラムで操作するもののみ付けます.名前の付け方は「そのコンポーネントの特性」+「コンポーネント名」にここではします.また,最初の単語の頭文字は小文字のキャメルケースで名前を付けます.例えば,RPiCarの前方にある物体までの距離を表示するLabelの場合はdistanceLabel,左旋回するToggleButtonの場合はrotateLeftToggleButtonのようになります.
下の図は名前を付けるコンポーネントに数字を振ったものです.この後に,それぞれの数字が振られたコンポーネントの名前を表にして示します.
下の表は各コンポーネントの名前と番号の対応表です.
番号 | 名前 |
1 | distanceLabel |
2 | leftPhotoReflectorCircle |
3 | centerPhotoReflectorCircle |
4 | rightPhotoReflectorCircle |
5 | pictureImageView |
6 | hornButton |
7 | takePictureButton |
8 | headLightToggleButton |
9 | leftSpeedLabel |
10 | leftSpeedSlider |
11 | rightSpeedLabel |
12 | rightSpeedSlider |
13 | goForwardToggleButton |
14 | rotateLeftToggleButton |
15 | rotateRightToggleButton |
16 | goBackToggleButton |
17 | stopButton |
18 | synchronizeMotorCheckBox |
さて,コンポーネントの名前を変える方法ついて説明します.下の図は距離を表示するためのLabelについて名前を付けている様子です.名前はfx:idとして付けます.コンポーネントを選択して右側のCodeにあるfx:idに名前を書きます.同様に名前を付けてください.ただし,注意してほしいのはButtonとToggleButtonです.プレビューの画面上で選択するとImageViewが選択されてしまいます.このため,ツリー構造でButtonとToogleButtonを選択するようにしてください.
プログラムの記述
UIができましたので次にプログラムを書いていきましょう.
コントローラクラス名の設定
まずはコントローラクラス名を設定します.作成したUIをJavaで動作させる時,ここで設定したコントローラクラスをmainメソッドから呼び出して使う流れになっています.今回はRPiCarControllerという名前を付けます.下の図をご覧ください.画面左側にあるドキュメントの下にコントローラというタブがあります.ツリー構造の下側にあるため,小さくなっている可能性がありますので注意してください.このコントローラを開くと,中にController classを記述するところがあります.ここにコントローラクラス名を書きます.この例ではjp.ac.nagano_nct.ashida_labパッケージの下にあるため,jp.ac.nagano_nct.ashida_lab.RPiCarControllerとなっています.
イベントの記述
例えばボタンが押されたらライトを点灯するなどのように,「何かが発生」したら「何かを行う」,のような手順でプログラムで書いていきます.ここで,「何かが発生」と説明したものをイベント,「何かを行う」メソッドをイベントハンドラといいます.イベントにはいろいろなものがあります.例えば,そのコンポーネント上でマウスが動いたとか,キーが押されたとか,配置が換わったとかのように多種多様です.ただし,ButtonやToggleButtonの場合には「ボタンが押された」というような最も標準的なイベントがあり,これをOnActionと呼んでいます.
下の図はヘッドライトのToggleButtonが押されたときに行ってほしいメソッドを書く場所を表しています.右側にあるCodeの中にOnActionというところがあります.ここに行ってほしいメソッドを書くことでToggleButtonが押されたときにこのメソッドを呼び出してくれるようになります.この例では,handleButtonActionメソッドが呼び出されるようになります.
まだイベントを取り扱うべきすべてのコンポーネントについて,上記のようなイベントハンドラを書いていませんが,ここで仮にプログラムを生成してみましょう.下の図のように表示メニューにあるサンプル・コントローラ・スケルトンの表示を選択してみましょう.
上記の結果,下に示すJavaのスケルトンコードが生成されます.先ほど名付けたコンポーネントとともにイベントハンドラであるhandleButtonActionメソッドがあります.あとはこの生成されたJavaのプログラムをIntelliJなどのIDEにもっていくとともに,handleButtonActionに行いたい処理,この場合にはヘッドライトを点灯する処理を書いてあげればよいのです.
package jp.ac.nagano_nct.ashida_lab; import javafx.event.ActionEvent; import javafx.fxml.FXML; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.Label; import javafx.scene.control.Slider; import javafx.scene.control.ToggleButton; import javafx.scene.image.ImageView; import javafx.scene.shape.Circle; public class RPiCarController { @FXML private Circle centerPhotoReflectorCircle; @FXML private Label distanceLabel; @FXML private ToggleButton goBackToggleButton; @FXML private ToggleButton goForwardToggleButton; @FXML private ToggleButton headLightToggleButton; @FXML private Button hornButton; @FXML private Circle leftPhotoReflectorCircle; @FXML private Label leftSpeedLabel; @FXML private Slider leftSpeedSlider; @FXML private ImageView pictureImageView; @FXML private Circle rightPhotoReflectorCircle; @FXML private Label rightSpeedLabel; @FXML private Slider rightSpeedSlider; @FXML private ToggleButton rotateLeftToggleButton; @FXML private ToggleButton rotateRightToggleButton; @FXML private Button stopButton; @FXML private CheckBox synchronizeMotorCheckBox; @FXML private Button takePictureButton; @FXML void handlHeadLightToggleButtonAction(ActionEvent event) { } }
そのほかのイベントハンドラを設定していきましょう.Slider以外についてはすべてOn Actionにイベントハンドラを追記してください.下の表は以前示しましたコンポーネントの番号とメソッドをまとめたものです.
番号 | イベントハンドラの場所 | メソッド |
6 | On Action | handleHornButtonAction |
7 | On Action | handleTakePictureButtonAction |
8 | On Action | handleHeadLightToggleButtonAction |
10 | ||
12 | ||
13 | On Action | handleGoForwardToggleButtonAction |
14 | On Action | handleRotateLeftToggleButtonAction |
15 | On Action | handleRotateRightToggleButtonAction |
16 | On Action | handleGoBackToggleButtonAction |
17 | On Action | handleStopButtonAction |
18 | On Action | handleSynchronizeMotorCheckBoxAction |