JCConf で JavaFX について発表してきた
この記事は、JavaFX Advent Calendar 2015 の 8 日目の記事です。
昨日は id:aoe-tk さんの JavaFX9に追加される機能が増えるかもしれません でした。
台湾の JUG である TWJUG が主催している JCConf で CfP をしていたので、軽い気持ちで応募したら受かっちゃいました。JCConf は、JJUG でいうところの CCC のようなカンファレンスです。
日本でも話したことがないことを話すつもりはないので、Swing から JavaFX のマイグレーションの話をすることにしました。
資料はもともと英語で作っているので、そのままでいいやと思っていたのですが... 見直してみたら、やっぱりここも直したい、あそこも直したいで半分ぐらい手を入れてしまいました。
そのせいで、喋りの準備が全然できなかったというのは、言い訳にしかすぎないんですけどね。
いちおう、原稿は作って、そのキーワードを抜き出したカンペを作ってスマホですぐに見られるようにしていたのですが、やっぱりそれを見る余裕はありませんでした ><
で、資料はこちら。
Swing がメインテナンスモードだし、もうこれから新しい機能は入らないから、Swing から JavaFX に移行することを考えようという内容です。
マイグレーションの例を 2 つ、ライブコーディングしようとしていたのですが、実際には 1 つ目の簡単な例だけでかなり時間を食ってしまって、2 つ目はライブではできませんでした。
そのせいもあって、後半はグダグダ。英語のプレゼンはもっと入念に練習しないとダメですね。
喋っている時は気がつかなかったのですが、Q&A の時に JRuby の Charles Nutter さんが聞いているのに気がつきました!!!
Watching @skrb talk about migrating from Swing to JavaFX at #jcconf. pic.twitter.com/OriXwwglMc
— Charles Nutter (@headius) 2015, 12月 4
話している時に気がつかなくてよかった!気がついていたら、緊張してなおさらグダグダになってしまうところでした。
講演の後、ちょっとだけ話をして、おもしろかったといってもらえたので、よかったです。
ちなみに、台湾での JavaFX の認知度は低かったようです。というか、やっぱりサーバーサイドの人がほとんどで、Swing を使ったこともないという人ばかりでした。セッションの後、TWJUG の @kojilin さんとも喋ったのですが、台湾ではデスクトップアプリを Java で作るということはあまりないようですね。
まぁ、日本でもそんなにメジャーというわけではないですが、こういうセッションをやるとかなりの割合の人が Swing を使っていたりするのですが...
今日は JavaFX の技術的な話はぜんぜんないですけど、まぁこういうエントリーがあってもいいでしょう ^ ^;;
明日の Advent Calendar は空きなので、誰か埋めて!!
JavaQne 2015
もうずいぶん日時が経ってしまいましたが、1 月 24 日に福岡で行われた JavaQne 2015 に参加してきました。JavaOne じゃなくて、JavaQne です。ちなみに Q は九州の Q です。
きしださんから JavaFX の話をということだったのですが、JavaFX の新しめのところを話してもキョトンとされるだけなのは重々承知しています。なので、比較的食いつきやすい Swing からの移行に関して話をしてきました。
ビックリしたのが Swing 経験者の数。数人いればいい方だと思ってたのですが、半分ぐらいの人が Swing を使っていた経験ありでした。
内容は JJUG CCC 2014 Fall で話したものの焼き直しです。でも、CCC では前半で時間を使いすぎて、後半がかなり駆け足になってしまったので、今回は前半は抑え気味にしました。それでも、最後はちょっと時間が足りなかった ><
それでも、そこそこ反応がよかったのでよしとしてください。
資料はこちら。
前半は JavaFX の紹介と、主な機能について。後半が Swing との差分とマイグレーションという 2 部構成にしました。
前半はおいておいて、後半。
Swing と JavaFX の一番の違いは、なんといっても FXML と CSS だと思っています。
GUI の構造を全部 Java で書かなくてはいけないなんて、ほんと苦痛でしかないです。コードも見づらいので、コードの保守もめんどうです。
Scene Builder でポトペタで FXML を作って、必要に応じて FXML を編集すれば OK。後はイベント処理部分をコントローラクラスに記述するだけ。これだけでかなり楽になります。
JavaFX の CSS はちょっとくせ者で、HTML の CSS と同じだと思っているとすぐにイタい目にあいます。JavaFX の部品のプロパティが分かっていないと書けないんですよね。
どういうプロパティがあるのかは Scnene Builder の CSS Analyzer を使えば分かります。CSS Analyzer はかなり便利でデフォルト値も分かるし、現在適用している値も分かります。
できれば、Scene Builder で CSS ファイルを直接編集できるといいのですが...
次は GUI 部品の話。Swing だとコンポーネント、JavaFX だとコントロールと呼びます。
単純な部品は Swing も JavaFX もだいたい同じです。Button や Label などは、プロパティもほぼ一緒ですし。
ちょっと変わってくるのが、ComboBox やダイアログ。JavaFX のダイアログは Java SE 8u40 から提供されますが、Swing の JOptionPane クラスのようなユーティリティクラスはないので、自分で組み立てます。とはいうものの、自由度は結構高いので、いろいろできます。
全然違うのが、JavaFX のコントロール名の最後に View がつく部品。ListView、TreeView、TableView、TreeTableView の 4 種類です。特に使用頻度が高い TableView については後述します。
レイアウトも Swing と JavaFX では違います。
Swing では、コンテナ + レイアウトマネージャ の組み合わせでレイアウトを行います。これに対して、JavaFX ではコンテナがレイアウト機能を含んでいます。
なので、レイアウトマネージャに対応した何たら Pane を探せば OK。たとえば、FlowLayout であれば FlowPane、BorderLayuot であれば BorderPane など。
実際にレイアウトを組み立てるのは FXML なので、クラス名が分かれば、後は Scene Builder でポトペタできます。
非同期処理は Swing が SwingWorker クラス、JavaFX が Service クラス、Task クラスで表します。
ということで、実際に Swing のサンプルを JavaFX に移植してみました。サンプルは Twitter のツィート検索ツールです。
Swing の GUI の構造から FXML を作成し、それをロードするメインクラスを作成します。次に、FXML に対応して、イベント処理を行うコントローラクラスを作成します。
このサンプルにはテーブルが含まれているのですが、ここが移植の一番めんどうなところです。
Swing の JTable は内部のモデルとして TableModel インタフェースを実装したクラスを保持しています。通常は DefaultTableModel クラスもしくは AbstractTableModel クラスのサブクラスとして実装します。
TableModel インタフェースの一番キモになるメソッドが getValueAt(int row, int column) です。つまり、テーブルモデル内でどのようにデータを保持しているかはおいておいたとしても、テーブルモデルを使う側からすると 2 次元の表の列と行を指定して、その値を取得できるようにすればいいわけです。
これに対して、JavaFX の TableView はモデルとして JavaBeans を使用します。そして、JavaBeans であるモデルクラスのプロパティとテーブルのカラムをバインドさせます。
JTable では単なる 2 次元の表だったのが、TableView ではカラムに意味を持たせるわけです。
そして、そのモデルクラスのリストを TableView に渡してあげると、モデルオブジェクトのプロパティの値を対応するカラムに表示します。
この考え方の違いを理解しないと、TableView 使いにくいになってしまいがち。でも、モデルとしての JavaBeans と、テーブルの対応が分かれば、TableView の方が理解しやすいと思います。
ただ、今の書き方だとカラムとプロパティのバインドがちょっとめんどうなんですよね。
非同期処理もやり方が違うだけで、やろうとしていることは変わりありません。Service/Task の書き方さえ分かれば、SwingWorker からの移行も簡単にできるはずです。
結局、GUI でやることなんてそんなにガラッと変わるわけではありません。GUI 部品を配置して、イベント処理を行うという基本的な考えは同じです。
なので、Swing を使っていたのであれば、JavaFX への移行は結構簡単にできるはずです。
JJUG CCC 2012 Spring
JJUG CCC では Swing から JavaFX のマイグレーションガイドという観点でプレゼンしてきました。
Swing と JavaFX は Java のソースコードレベルではそれほど違いはありません。しかし、いくつかはまりポイントもあります。
たとえば、イベントやバインド。
イベントは、Swing/AWT ではイベントに対応したリスナが存在しましたが、JavaFX ではリスナというはハンドラが 1 つあるだけです。1 つだけのハンドラ (EventHandler インタフェース) ですべてのイベントに対応するために、ジェネリクスでイベントを指定します。
また、たとえば Swing の MouseListener では mouseClicked メソッドや、mousePressed メソッドなど、リスナに複数のメソッドが定義されていました。これに対し、JavaFX ではハンドラを登録する Node クラスに onMouseClicked メソッドや onMousePressed メソッドなどが定義されています。このため、EventHandler インタフェースには handle メソッドだけが定義されています。
EventHandler インタフェースにメソッドが 1 つだけ定義されているということは、Java SE 8 で導入されるラムダ式でも記述可能ということです。イベント処理の登録は冗長な記述になるので、ラムダで書けるのはうれしいところです。
バインドは Swing には無い概念です。
変数 x と変数 y があった時、x を y にバインドすると、y の値が変更すると x も自動的に同期して値が変更する機能をバインドと呼びます。
JavaFX ではこの機能を導入するために、Java Bean を拡張したプロパティという機能を導入しています。プロパティ同志であれば、バインドができるようになっています。
バインドを使う典型的な例が MVC のそれぞれを結びつける場面です。イベントやオブザーバパターンを使っていたのが、バインドだとかなりすっきり書くことができます。
さて、その後、3 つのシナリオで Swing から JavaFX への移行を考えてみました。
はじめが Swing のアプリケーション中に JavaFX を埋め込む場合、次が Swing から JavaFX へ Java を使って移行する場合、最後に FXML を使う場合です。
はじめのシナリオは、Swing にはない JavaFX の機能を使用したい場合に有効です。たとえば、Web ブラウザやグラフ (チャート) などがあります。
2 番目のシナリオは、Swing をかける人であれば、それほど苦労せずに JavaFX を書けるようになるはずです。ただし、レイアウトの用に Swing と JavaFX で作法が違うものや、テーブルのようにまったく書き方が違うものがあるので、注意は必要です。
やはりお勧めは FXML です。
Java で書くと、シーングラフのツリー構造がソースからは読みにくいですし、すぐに複雑になってしまいます。FXML であれば XML なので、ツリー構造を表すにはうってつけです。
ただし、FXML はツールを使わないと、書くのがつらいのも事実。ということで、最後は Scene Builder のデモでした。
Swing をやる人に伝わったかなぁ?