一般的なアドバイス
抽象的な概念から直接取り組もうとするのではなく、既存のコードで JavaFX に実装されたこれらのパターンの例を見て、そこでどのようにコーディングされているかを確認することをお勧めします。気に入ったパターンが見つかったら、コードでそれらをエミュレートできます。
アプリケーションまたはシーン全体に MVC パターンを適用する大規模なプログラミングと、特定のコントロール タイプにパターンを適用する小規模なプログラミングには違いがあります。あなたの質問は後者のケースにより関連しているように思われるので、この回答では主にそれを考慮します。
JavaFX コントロール - スキン、動作、およびパブリック API
JavaFXの既存のコントロール コードを見てください。の場合Button
、次のようになります。
- javafx.scene.control.Button - コントロールを操作するためのパブリック API。
- javafx.scene.control.skin.ButtonSkin - コントロールのビジュアル ビュー。
- javafx.scene.control.behavior.ButtonBehavior - イベント バインディング (キー/マウス イベントなど)。
はButtonBehavior
抽象化 API を提供するため、キー、マウス、およびタッチの組み合わせについて、ボタンをさまざまなプラットフォームおよびユーザー固有のイベント マップにバインドできます。
を使用ButtonSkin
すると、パブリック API や動作を変更することなく、コントロールの視覚的な実装を完全に入れ替えることができます。
Button
パブリック API は、ボタンのユーザーがコントロールの実装に対する視覚的または動作上の変更とは無関係にプログラムできる安定した API を提供します。
抽象化を取り除く
スキン API とビヘイビアー API は、ビヘイビアーとルック アンド フィールの実装の詳細を抽象化するのに最適ですが、コントロールの実装者にとって複雑さとオーバーヘッドが追加されます。作成しているコントロールが本当にこの複雑さを必要とするかどうかを検討し、別のより単純なアプローチを評価する必要があります。
最も簡単な方法は、既存のペインを拡張し、すべてのロジックを 1 つの拡張クラスに配置することです (または、コントロール ノードを構築するファクトリ メソッドを提供することさえできます)。抽象化が失われ、単純な実装の互換性と関心の分離の利点が失われますが、実装は非常に単純です。この単純な拡張メカニズムの例は、Oracle Mastering FXML チュートリアルのカスタム コントロールの例です。
私が使用したもう少し洗練されたアプローチは、パブリック API とコントロールの状態情報をカプセル化するクラスと、イベントまたは UI レンダリングを処理する別のスキン クラスを用意することです。標準 JavaFX コントロールの動作/スキン/パブリック API アプローチと同じくらい概念的なオーバーヘッドを追加することなく、JavaFX 固有のロジックとコードを基になるコントロール状態とパブリック API から明確に分離するため、このアプローチが気に入っています。このアプローチを使用したサンプル コードは、このTic-Tac-Toe game にあります。
スキン/ビヘイビアとパブリック API 間の通信
コントロールのパブリック API を含むクラス内でJavaFX プロパティ メカニズムを利用します。プロパティは、コントロールのパブリック API を定義するだけでなく、ReadOnlyWrappersなどの型を介して内部コントロールの状態をカプセル化できます。
スキンはバインディングとリスナーをプロパティに適用できるため、リスナーが起動されると、スキンはそれ自体の自動更新をトリガーして、新しいコントロールの状態を反映できます。コントロールのユーザーは、コントロールの内部状態をリッスンまたはバインドして、状態の変化に応じてアクションを実行できます。このアプローチの例は、ボタンが選択されているかどうかに応じてスキンがトグル ボタンの外観を変更するToggleButton の selected プロパティです。
スキンを作成するときは、コントロールを含むパブリック API への後方参照を使用してスキンと動作を初期化します (たとえばSymbolSkin
、SymbolBehaviour
への参照を持ちますSymbol
)。マウス クリックは、SymbolSkin または SymbolBehavior の mouseclickhandlerによってインターセプトされ、パブリック API で選択されたプロパティをシンボルに切り替えることができます。その後、シンボルで選択されたプロパティへの変更をリッスンするユーザー コードは、そのユーザー コードが厳密でなくても有効になります。シンボルのスキンまたは動作に結合されています。
パブリック APIは、シーン グラフで利用できる単純なノードとしてスキンを返すSymbol
単一のメソッドを公開するだけで済みます。getSkin()
これにより、スキンと動作の実装は、Symbol
パブリック API を使用するクラスの呼び出しから隠されます。
Region を拡張して CSS を利用する
コントロール スキンを拡張することによりRegion
、コントロールは CSS を介してスタイル設定可能になります。このアプローチは、コントロールの多くの視覚的側面 (塗りつぶし、背景、境界線、形状など) をJavaFX の豊富な CSS スタイル言語で操作できることを意味するため、強くお勧めします。
これを行うときは、コントロール スキン内のすべてのノードに個別の css スタイル クラスを装備するようにしてください。これにより、コントロールのビジュアル コンポーネントへのフックが提供され、これらのコンポーネントのスタイルを設定するために使用できます。複雑なコンポーネントをスタイリングするこのアプローチのサンプルは、CSS を使用したチャートのスタイリングに関する Oracle チュートリアルです。
Symbol
質問のようにさまざまなシンボルを定義するには、単一のコントロールを作成できます。SymbolBehaviour
ユーザー イベントを処理するための と、SymbolSkin
拡張するだけの を定義しますRegion
。各シンボル インスタンスには独自のスタイル クラスを割り当てることができ、パブリック シンボル API は、このスタイル クラスをシンボル スキンの領域に設定するコンストラクターまたはファクトリ メソッドを提供できます。css 指定子を使用し-fx-shape
て、svg パス文字列に基づいてシンボルの形状をスタイルします。
css スタイルクラス名自体は、SymbolSkin
実装にハードコーディングし、パブリック API の一部として文書化できます (標準コントロールの CSS リファレンス ガイドで行われているように)。
コントロールの既定のスタイルを定義する既定の css テンプレートを使用して、コントロールを出荷します。
FXML に関する考慮事項
調整が必要な多くのサブコントロールで構成される大規模なアプリケーションまたはシーンがある場合、FXMLのようなものを使用してシーンを宣言的な方法で定義できます。これにより、UI デザインを命令型プログラミング コード ベースから切り離すことができ、ビューで命令型コードを書き始める必要がなくなります。
FXML を使用した真の MVC アーキテクチャの場合、FXML ファイルとシーン実装用のバッキング コントローラーだけでなく、シーンのスワップ インとアウトのためのより高度な制御メカニズム、およびおそらく次のようなより高度なイベント処理メソッドも必要になるでしょう。イベントバスとしてですが、それはこの質問の範囲外です。
関連している
問題のドメインをよりよく理解するのに役立つ、わずかに異なるが関連する質問があります ( JavaFX 2.0 - スタイル/テンプレートの既存のコントロール)。