Java The Nightのデモでお見せしたFX GlassFish Monitorの作りについての解説です。まずは反響が大きかった見映えのところから説明したいと思います。
一番目に付いたのはウィンドウ枠だと思います。OSのウィンドウ枠は全く見えず、周囲が何か光っていますね。
JavaFXではコンポーネントにドロップシャドウエフェクトを追加することができ、今回もそれを利用しているのですが、OSのウィンドウ枠に相当する Stage クラスには適用することはできません。
そこで次のような方法で実現しました。
図示するとこんな感じです。
メインウィンドウ (監視項目のツリーが並ぶウィンドウ) について、Stage の上に Scene を組み立てている部分のJavaコードと、FXML のコードを示しておきます。
@Override
public void start(Stage stage) throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("view/MainView.fxml"));
loader.load();
Parent root = loader.getRoot();
MainViewController controller = loader.getController();
controller.setParentStage(stage);
Scene scene = new Scene(root, 924, 700, Color.TRANSPARENT);
stage.initStyle(StageStyle.TRANSPARENT);
stage.setScene(scene);
stage.show();
}
<StackPane id="StackPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="700.0" prefWidth="924.0" xmlns:fx="http://javafx.com/fxml" fx:controller="aoetk.fxglassfishmonitor.view.MainViewController"> <children> <Rectangle arcHeight="5.0" arcWidth="5.0" fill="#1e90ff00" height="690.0" stroke="$x1" strokeType="INSIDE" width="914.0"> <effect> <DropShadow blurType="GAUSSIAN" spread="0.7"> <color> <Color blue="0.878" green="1.000" red="0.000" fx:id="x1" /> </color> </DropShadow> </effect> </Rectangle> <BorderPane fx:id="containerPane" onMouseDragged="#handleMouseDragged" onMousePressed="#handleMousePressed" prefHeight="200.0" prefWidth="200.0" styleClass="container"> <center> <ScrollPane prefHeight="200.0" prefWidth="200.0"> <content> <Pane fx:id="drawRegion" prefHeight="200.0" prefWidth="200.0" /> </content> </ScrollPane> </center> <top> <HBox fx:id="boxTitle" prefHeight="50.0" prefWidth="200.0"> <children> <Text fill="$x1" fontSmoothingType="LCD" stroke="WHITE" strokeType="OUTSIDE" strokeWidth="0.0" text="FX GlassFish Monitor" HBox.hgrow="NEVER"> <font> <Font name="System Bold Italic" size="28.0" /> </font> </Text> <Region prefHeight="200.0" prefWidth="200.0" HBox.hgrow="ALWAYS" /> <Button fx:id="btnExit" mnemonicParsing="false" onAction="#handleBtnExitAction" styleClass="close-button" text="Exit" HBox.hgrow="NEVER" /> </children> <padding> <Insets bottom="20.0" left="10.0" right="10.0" top="10.0" /> </padding> </HBox> </top> <StackPane.margin> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" /> </StackPane.margin> </BorderPane> </children> <stylesheets> <URL value="@../asset/style.css" /> </stylesheets> </StackPane>
Rectangle とレイアウトコンテナ (BorderPane) の貼り合わせには StackPaneを使っています。
StackPane にマージンを指定していて、その上に置いたコンテンツがドロップシャドウの幅の分だけ隙間を空けるようにしています。
BorderPane の onMousePressed と onMouseDragged にイベントハンドラを設定しています。これは Stage を透明にしたために、そのままではウィンドウ枠が消えてウィンドウの移動ができなくなるため、自分でドラッグ移動のイベントを実装しているのです。
スタイルシートはこんな感じです。
.root { -fx-base: #212020; } .container { -fx-background-color: rgba(0, 0, 0, 0.7); } .close-button { -fx-border-color: white; -fx-border-width: 2px; -fx-border-radius: 5px; -fx-background-color: transparent; -fx-text-fill: white; -fx-font-size: 16px; -fx-cursor: hand; }
container クラスがレイアウトコンテナに適用するもので、色を黒で透明度を 70% に設定しているだけです。
close-button クラスはExitボタンに適用したスタイルで、背景を透明にしてあのような見た目にしているのが分かりますね。
と言うわけで見映えについての解説でした。大して手数を掛けずに実現可能だと言うことが分かりますね。
コード全体についてはもう少し整理してからGithubのURLを公開する予定です。もうしばらくお待ちを。
解説に使った図はScene Bulderを使って描きました。が、やっぱりお絵かきにはまだまだ機能不足ですね。Rectangle を平行四辺形に変形する部分は直接FXMLを手打ちしました...。
5/14 (火) に開催されたJava Day Tokyoに参加し、さらにその中のセッションの1つである、Java The Nightに登壇しました。
まさかこんな大きなイベントで自分が発表する側に立つことになるとは思わず、とても緊張しましたが良い経験になりました。
このエントリではイベントの感想についてまとめたいと思います。
Java The Nightで自分は「監視ツールでみるJavaFXとJava EEの魅力」と題して発表しました。セッション資料はSlideShareにアップしています。
Java Day Tokyo 2013 Java the Night 監視ツールでみるJavaFXとJava EEの魅力 from Takashi Aoe
登壇することになった経緯ですが、Oracle寺田さんからTwitterのダイレクトメッセージで突如お願いされましたw
寺田さんからの要望は、「デモの際におもしろ、おかしく、やっていただくことはできますでしょうか。」でした。
随分ハードル高いなあと思いつつも、折角の機会なので登壇させて頂くことになりました。
発表の内容としては、JavaFXで作ったGlassFishの監視アプリケーションのデモを通して、自分がJavaFXやJava EEの魅力と思っている点について伝えるというものでした。
インパクト重視という要望だったので、JavaFXで作るアプリは派手めな、中二病っぽい感じの路線で行くことにしました。
JavaFXについてここで伝えたかったことは、プログラムを使って何かやりたいタスクがあったときに、JavaならばJavaFXが加わったことで、このように綺麗なGUIで成果をアウトプットできるようになるということです。
CUIもいいけど、GUIでやると楽しいですよ。
このアプリケーションのルックスについては予想以上に反響があったようですが、実はそんなに手数を掛けなくてもこのような見た目にすることが可能です。この点については後ほど別エントリで解説します。
Java EEについては、運用フェーズにおける監視という側面からの利点を伝えようとしました。Java EE APサーバーはいずれもサーバー上で稼働するサービス、アプリケーションに対して豊富な監視オプションを提供しています。
Webアプリケーションフレームワークはともすると開発の側面ばかりに目が行きがちですが、ソフトウェアのライフサイクル全体で考えると運用も重要です。その点も考慮して選択を考えてもらったらと思います。
それでは自分が参加した各セッションについて軽く感想を書いていきます。
基調講演ではJava SE、Java FX/Embedded、Java EE、コミュニティについて、それぞれのOracleのキーパーソンから現状と今後の展望について説明するというものでした。
特に自分の印象に残ったのが、OracleがM2Mを重視しているように見えたことです。今後は様々なデバイスがネットワークでつながるようになるため、確かに次にソフトウェア開発の分野でホットになるのはここかも知れません。そして恐らくこの分野でもライバルになるのはAndroidでしょうね...。
Pro JavaFX 2の著者の一人であるStephen Chinさんによる、Raspberry Pi上でのJavaFXアプリケーションの実行についてのセッションでした。
目の前でJavaFXアプリケーションを構築して、それをRaspberry Piに移植動かすところまでを見せてもらいました。
驚いたのは、本当にそのままのJavaFXアプリケーションが動いているということです。エフェクトとかも普通に動いていました。質問したところ、動かないのはWebViewとMediaViewだけとのことです。
Raspberry Pi向けのJava SEのプロファイルは結構小さいのですが、それでもJavaFXアプリケーションがここまで動くというのには色んな可能性を感じさせてもらいました。
Eclipse、NetBeans、IntelliJ IDEAというJava界三大IDEについて、Eclipse派代表として竹添さん、NetBeans派代表としてきしださん、IntelliJ派代表として今井さんが語り合うというとても楽しいセッションです。
モデレータの山本裕介さんがIntelliJユーザーと言うこともあり、ややIntelliJにバイアスが掛かっていたような気がしましたが。(^^;;
スライドが三者三様でこちらもそれぞれの個性が出ていて面白かったです。竹添さんはきっちりPowerPointで、今井さんはrstテキストで、そしてきしださんは安定の手書き資料w
なお、自分は基本的にNetBeans派ですが、IntelliJもちょこちょこ触りますし *1 、もちろん仕事の必要上Eclipseも結構触ります。
ディスカッションで自分の印象に残ったのは以下の点です。
こちらもStephen Chinさんによるセッションです。Groovy、Clojure、Scala、Visage *2 、JRubyでのJavaFXのサポート状況について順に説明してもらいました。
ちなみにChinさんはScalaFXとVisageのコミッタをされています。
JavaFXのサンプルアプリケーションとしてよく使われる、Vanishing Circleを例に、他の言語で実装した例を見せてもらいました。
特に自分がいいなと思ったのがGroovyFXです。@FXBindableアノテーションを付けることで、JavaFX形式のプロパティを生成してくれるのはとても嬉しい!
自分の以前のエントリでも解説しましたが、JavaFX形式のプロパティの記述はちょっと面倒なのです。
ScalaFXもとてもScalaらしいアプローチでDSLを設計していて、こちらも好感が持てました。
VisageはJavaFX Script時代から言語仕様が強化されているのですね。
なお、Chinさんは日本の漫画やアニメが相当好きなようで、各言語についてアニメに例えてらっしゃいました。以下の通りですが自分のよく知らないモノもあるw
JavaFXエヴァンジェリストであり、Pro JavaFX2の著者の一人である、Jim Weaverさん *3 による、JavaFXのマルチタッチ関連APIの解説と、タブレット向けアプリケーションを作る上での注意点について説明する
タブレットのターゲットはWindows8でした。実際にSurface Proを操作しながら解説していました。
マルチタッチ関連APIの解説の内容は自分が先日JavaFX勉強会で行ったものとほぼ同内容でしたw
タブレット向けアプリケーションを開発する上での注意点は、やはりコントロールの大きさでした。そのためにデザインにはなるべくCSSを活用し、まずはrootクラスのフォントを32px程度にするのが良いとのことでした。
結構説明が早く終わってしまったので、質問がいっぱい出ていました。自分は高解像度端末におけるスケーリングの対応について聞いたのですが、現時点では端末に合わせて自分でサイズを調整するしかないようです。でも、後で気付いたのですが、確かJavaFX8で導入されるModenaテーマはスケーリングの変化に対応していたような?
最後は自分も登壇したJava The Nightです。みなさん実に色んな持ちネタを披露してもらって、とても楽しめました。
驚いたのはほとんどの人がJavaFXを使っていたことです!自分が考えている以上にJavaFXがJava開発者の間で認知度を上げているのかも知れません。
最後に寺田さんから発表されたJava7のAPIドキュメント日本語化のニュースは驚きました。Oracle本体を説得して日本語化にこぎつけた日本Oracleの皆様方には感謝です!
このように、聴講、発表共にとても楽しい一日を過ごすことができました。このような素晴らしい場を提供して頂いた日本Oracleの皆様には厚く御礼申し上げます。ありがとうございました。
*1:特にJavaFXサポートが入ってからは、JavaFXサポート機能がなかなか強力なので結構触るようになりました。
*2:OracleがディスコンにしてしまったJavaFX Scriptをオープンソース化したものです
このエントリはJavaFX Advent Calendarの26日目のエントリとなります。前日は id:skrb / @skrb さんによる「JavaFX で Merry Christmas!」です。25日を過ぎちゃいました。まさか1日目と最終日を担当することになるとは。
25日分を突破するわ、海外のJavaFXエンジニアの方々に注目されてエントリを英語に翻訳するようになるわで、まさかの盛り上がりとなりましたねえ。
さて、今回のエントリですが、同じくAdvent Calendarの13日目に@mike_neckさんがJavaFXでGroovyのVetoableが機能するか試してみたというエントリを書かれて、GroovyのBindable and Vetoable transformationを利用して、Model、View、Controllerを綺麗に分離する方法を紹介されていました。
ですが、JavaFX自体にもModel、View、Controllerを綺麗に分離するためのバインディングと呼ばれる機能が用意されています。このエントリではその機能を用いて上記ブログエントリのサンプルを再実装することで、バインディング機能について紹介してみたいと思います (なので先にみけさんのエントリを読んでおいてくださいね) 。
バインディングとは、簡単に言うとあるデータと別のあるデータを結び付ける機能のことです。あるJavaBeansオブジェクトのプロパティが変化したら自動的に他のJavaBeansオブジェクトにその値を伝達できるようにします。機構の実現にはObserverパターンを利用しています。
この機構を用いることで、Modelオブジェクトのプロパティに対して、Viewに使用するコンポーネントのプロパティを「バインド」しておけば、Modelの値が変化したら自動的にViewの表示内容が変わるようになり、典型的なMVCパターンの構造を組むことができるようになりますね。
WPF等のXAML系フレームワークやFlexなど、最近のGUIフレームワークは大抵このバインディング機構が備えられています。JavaScriptライブラリでもknockout.jsのようにバインディング機構を備えたライブラリが色々出てきています。
JavaFXのバインディングは他のGUIフレームワークには余り見られない強力な機能が備えられています。ただし、既存のJavaBeans仕様を拡張したAPIを用いて実現しているため、記述は少々面倒だったりします。サンプル実装を通して紹介していきたいと思います。
それでは実際にバインディングを用いて再実装したサンプルを示します。全ソースコードはgistにアップしています。
https://gist.github.com/4363405
まずはModelからです。
public class Person { // nameプロパティ private StringProperty name = new SimpleStringProperty(); // 外部に公開するプロパティ public StringProperty nameProperty() { return name; } // JavaBeans仕様と互換を持たせるためのgetter、setter public final String getName() { return name.get(); } public final void setName(String name) { this.name.set(name); } // messageプロパティ (read only) private ReadOnlyStringProperty message = new ReadOnlyStringPropertyBase() { { name.addListener(new InvalidationListener() { // nameプロパティの変化を観察し、変化したらこのプロパティも値が変化したことを通知する @Override public void invalidated(Observable o) { fireValueChangedEvent(); } }); } @Override public String get() { String value = Person.this.getName(); if (value.length() > 0) { return "Hello I'm " + value + "."; } else { return ""; } } @Override public Object getBean() { return Person.this; } @Override public String getName() { return "message"; } }; // 外部に公開するプロパティ public ReadOnlyStringProperty messageProperty() { return message; } // JavaBeans仕様と互換を持たせるためのgetter public final String getMessage() { return message.get(); } }
まずは簡単な name プロパティから見てみましょう。なにやらいつものJavaBeansのプロパティとはちょっと違いますね。
// nameプロパティ
private StringProperty name = new SimpleStringProperty();
// 外部に公開するプロパティ
public StringProperty nameProperty() {
return name;
}
// JavaBeans仕様と互換を持たせるためのgetter、setter
public final String getName() {
return name.get();
}
public final void setName(String name) {
this.name.set(name);
}
JavaFXのプロパティは **Property 型 ( ** にはラップする値のクラスが入る) でラップします。そしてこの Property 型の get/set メソッドで値のやり取りをします。
外部に公開するときは "(プロパティ名)Property()" という名前のメソッドを宣言します。また、既存のJavaBeans仕様と互換性を持たせたい場合はこのように getter/setter も用意しておきます (ただし、メソッド内では Property を通してやり取りする) 。*1
Property 型は abstract クラスなので、継承して get/set 時の処理を実装することになりますが、単純に値の受け渡しだけをする場合は Simple**Property というデフォルト実装が用意されています。
この Property オブジェクトが「バインド可能」なオブジェクトになるわけです。
続いて message プロパティです。こちらは外部から値を設定するのではなく、name プロパティの値に依存したプロパティとなっています。なので、リードオンリーなプロパティとして実装してみました。
// messageプロパティ (read only)
private ReadOnlyStringProperty message = new ReadOnlyStringPropertyBase() {
{
name.addListener(new InvalidationListener() {
// nameプロパティの変化を観察し、変化したらこのプロパティも値が変化したことを通知する
@Override
public void invalidated(Observable o) {
fireValueChangedEvent();
}
});
}
@Override
public String get() {
String value = Person.this.getName();
if (value.length() > 0) {
return "Hello I'm " + value + ".";
} else {
return "";
}
}
@Override
public Object getBean() {
return Person.this;
}
@Override
public String getName() {
return "message";
}
};
// 外部に公開するプロパティ
public ReadOnlyStringProperty messageProperty() {
return message;
}
// JavaBeans仕様と互換を持たせるためのgetter
public final String getMessage() {
return message.get();
}
リードオンリーなプロパティの場合、オブジェクトの内部状態に応じた値を返すことになるので、多くの場合作り込みが必要になります。JavaFXでリードオンリーなプロパティを実装する方法は大きく分けて次の2つの方法があります。
ここでは前者の方法を用いて実装してみました。バインド可能なプロパティを用意する場合、次の処理を実装する必要があります。
まず、初期化処理で InvalidationListenerなるものを name プロパティに対して登録していますね。これは name プロパティの値の変化を観察しています。message プロパティは name プロパティの値に依存していますから name プロパティの変化を検知した場合、このように fireValueChangedEvent() メソッドをコールして、自身に登録されたリスナに対して変更を通知します。
そして、3つのabstractメソッドを実装しています。1つめの get() が値を返す処理を実装していますね。name に何も入っていない時は空文字を返し、値が入っているときは "Hello I'm " を付けて返しています。
getBean() メソッドはプロパティのオーナーのインスタンス (ここでは Person インスタンス) を返し、getName() はプロパティ名を文字列で返します。
注目すべき点は InvalidationListener です。これは観察しているプロパティの値が変化したことだけを知らせます。これがミソです。
実はJavaFXのバインディングでは遅延評価が基本となっており、実際に値が取り出された時に初めて算出するようになっています。
今回は単純に1つの値を受け渡すだけですが、実際にバインディングを使用するときは複数の値を組み合わせて算出したり、あるいは取得した値から複雑な描画処理を行ったりする可能性があります。
そこで、JavaFXでは観察されている値が変化したときは、変化したことを知らせるフラグだけを立てておき、本当にその値が必要とされるときになって、フラグが立っていたら実際の値を算出するようになっているのです。実際に値を取り出す前にデータソース側が何度変化していても、計算するのはその時の1回だけです。
私はJavaFXのこの点がすごく気に入っています。以前Flexで開発していたことがあったのですが、Flexのバインディングは即時評価であるため、濫用するとパフォーマンスの低下を招きやすく、折角の機能が余り使えなくて残念な思いをしていました。
さて、ここまでのコードは長かったですが、プロパティ側の準備ができたら後は簡単です。まずはFXMLから。
<AnchorPane id="AnchorPane" prefHeight="200.0" prefWidth="320.0" xmlns:fx="http://javafx.com/fxml" fx:controller="aoetk.bindingsample.SampleController"> <children> <Label layoutX="35.0" layoutY="31.0" text="Your name" /> <TextField fx:id="txtName" layoutX="129.0" layoutY="28.0" prefWidth="177.0" /> <Label fx:id="name" layoutX="35.0" layoutY="133.0" /> <Label fx:id="message" layoutX="129.0" layoutY="133.0" /> </children> </AnchorPane>
特に変わったところはありませんね。注目して欲しいのはmike_neckさんのエントリでは TextField にイベントを定義していましたが、ここでは定義していません。
続いてControllerです。
public class SampleController implements Initializable { @FXML private TextField txtName; @FXML private Label name; @FXML private Label message; private Person person; // 初期化時に必要なバインドを行う @Override public void initialize(URL url, ResourceBundle rb) { person = new Person(); person.nameProperty().bind(txtName.textProperty()); name.textProperty().bind(person.nameProperty()); message.textProperty().bind(person.messageProperty()); } }
初期化処理を行う initialize() メソッド内でバインディングを行っています。値の変更を反映する側のプロパティの bind() メソッドを呼び出し、引数に変更元のプロパティを渡します。
まず最初に、Person#name に対して、テキストフィールドの text プロパティをバインドしています。こうすることで、テキストフィールドへの入力が name プロパティに勝手に反映されることになります。
次の2行でラベル name に対して Person#name を、ラベル message に対しては Person#message をバインドしています。
これだけでテキストフィールドの入力内容をラベルに反映する処理を実装することができました!
ちなみにControllerでバインドを行っているのは、現時点ではFXMLは単純なバインディングしか記述できないためです (FXML内で宣言した変数のみバインドが書ける) 。将来的には複雑なバインドも記述できるようにするそうです。
ともあれ、バインディングを活用すれば容易にModelとViewの値を結びつけ、しかも疎結合にできる (ModelはViewの事を一切知りません) ことがこのサンプルで分かると思います。
なお、プロパティの定義に使った **Property 型は **Expression 型を継承しています。Expressionという名前から想像できるように、様々な演算を行うためのメソッドが用意されています。これを利用することで、バインドする値を様々に加工したり、複数の値を組み合わせてバインドすることができるようになります。
これを利用すると、先ほどの例を次のようにして同じ機能を実現することが可能です。*2
@Override
public void initialize(URL url, ResourceBundle rb) {
person = new Person();
person.nameProperty().bind(txtName.textProperty());
name.textProperty().bind(person.nameProperty());
// message.textProperty().bind(person.messageProperty());
message.textProperty().bind(
new When(person.nameProperty().isEqualTo(""))
.then("")
.otherwise(new SimpleStringProperty("Hello I'm ").concat(person.nameProperty()).concat("."))
);
}
流れるようなインターフェースで条件分岐やら文字列の結び付けが可能になっていることが分かります。ちょっと見辛いですけどね。
このようにある程度複雑なプレゼンテーションロジックも Expression 型の備えるメソッドで実現が可能になっています。詳しくはJavaFXのAPIドキュメントで Expression 型のメソッドを確認してみてください。
これまで見てきたように、JavaFXには強力なバインディング機構があり、コンポーネント間の関係を疎結合にしつつ、関連する値を結びつけることが可能になります。遅延評価や流れるインターフェースを用いた演算など、なかなか強力な機能が備わっています。
難点はちょっと記述が面倒な点ですね。このあたりはJavaの表現力の限界なので致し方ないところではありますが。GroovyFXやScalaFXでは言語の表現力を活かして書きやすくしてくれています。個人的にはScalaFXのバインディングの書き方は分かり易くていいなあと思っています。*3
*1:既存のJavaBeans仕様を満たす必要がない場合は省略するのもありです。
*2:最終的に実現する機能は同じですが、意味合いは大きく異なることに注意してください。この例では文字列を結合する処理がプレゼンテーション層に存在することになります。対して message プロパティを利用する例では、文字列を結合する処理はドメイン層に属することになります。
This blog entry is the first entry in Japan JavaFX Advent Calendar 2012.
I made a presentation about multi-touch support in JavaFX at 8th Japan JavaFX workshop. I write additional information for the presentation in this entry.
Presentation material is below.
Developing multi-touch application in JavaFX from Takashi Aoe
And source code of sample application is below.
https://gist.github.com/4143183
JavaFX2.2 introduces API related multi-touch. I was very surprised when Developer Preview released because the description of the API has been added to JavaDoc casually without notification in release notes.
Multi-touch support is described as follows in the entry entitled ”What’s new in JavaFX 2.2” in The JavaFX Blog.
Multi-touch support for touch-enabled devices. As of today this is mostly relevant for desktop-class touch screen displays and touch pads, this will enable the adoption of sophisticated UIs on embedded devices running Java SE Embedded on ARM-based chipsets, such as kiosks, telemetry systems, healthcare devices, multi-function printers, monitoring systems, etc. This is a segment of the Java application market that is usually overseen by most application developers, but that is thriving.
I think main target of multi-touch support is embedded devices. It's my opinion, Oracle is probably going to be taking the initiative in the development of embedded devices user interface before Android move into the same domain.
Of course, I think it is intended for the development of iOS/Android/WindowsPhone/WindowsRT application.
As I explained in the workshop, TouchEvent handling the basic touch operation and GestureEvent handling more abstract events are added to javafx.scene.input package.
And properties to register a handler for these events are added to Scene and Node.
The following is a list of items I didn't speak for a time limit in workshop.
I showed three samples in workshop. There are videos that had been recorded in preparation to the failure of the demonstration.
I wrote compressed souece code in the presentation material because of space limitation. So I hope you check the source code uploaded to gist.
I describe below additional explanation.
@Override
public void initialize(URL url, ResourceBundle rb) {
fonts = Font.getFamilies();
pagination.setPageCount(fonts.size() / FONTS_PER_PAGE);
pagination.setPageFactory(new Callback<Integer, Node>() {
@Override
public Node call(Integer idx) {
return createPage(idx);
}
});
lvFonts.setItems(FXCollections.observableArrayList(fonts));
}
private VBox createPage(int idx) {
VBox box = new VBox(5.0);
int page = idx * FONTS_PER_PAGE;
for (int i = page; i < page + FONTS_PER_PAGE; i++) {
Label lblFont = new Label(fonts.get(i));
box.getChildren().add(lblFont);
}
return box;
}
As you see, API that enables to develop multi-touch application easily have been added in JavaFX2.2. Unfortunately, fully available environment is Windows8 devices only (furthermore, only in desktop mode), Let's use everyone!
JavaFX Advent Calendarの1日目を担当することになってしまった@aoetk / id:aoe-tkです。
実は前日の第8回JavaFX勉強会にて、JavaFXでのマルチタッチプログラミングについての発表を行いました。このエントリではその内容のフォローアップをしたいと思います。
当日の発表資料は以下です。
JavaFXでマルチタッチプログラミング from Takashi Aoe
また、デモに使ったサンプルアプリケーションのコードもgistにアップしています。
https://gist.github.com/4143183
発表でもお話ししたように、JavaFX2.2になってタッチ関連のAPIが追加されました。Developer Previewの時に、特にリリースノートでの通知がなく、さりげなくJavaDocに追記されていたので驚いたのを覚えています。
JavaFX2.2新機能紹介ページ (日本OracleのエンベデッドJavaチームによる日本語訳です) では次のように紹介されています。
タッチ操作可能な機器のためのマルチタッチサポート。これは現段階では主にデスクトップクラスのタッチスクリーンやタッチパッド向けですが、将来的にはARMベースのチップ上にJava SE Embeddedが搭載されているさまざまな組み込み機器に洗練されたUIを導入することを可能にします。例えばキオスク端末、テレメトリシステム、ヘルスケア機器、多機能プリンタ、監視システムなどです。これらは、多くのアプリケーション開発者にはまだあまり注目されていないJavaアプリケーションの市場セグメントですが、近年活況を呈しつつあります。
当日の発表でも少し触れましたが、主に組み込み機器をメインターゲットにしているように見受けられます。こういったセグメントにもこれからAndroidが進出してくるでしょうから、その前にしっかり押さえておこうとOracleは考えているのでしょう。
もちろんiOSやWindows8/RT/Phone、Android向けの開発も視野には入れているとは思いますが。
さて、追加されたAPIの内容についてですが、発表でも説明したように、javafx.scene.input パッケージに基本的なタッチ操作を扱う TouchEvent と、タッチ操作を組み合わせたより抽象度の高い GestureEvent というイベントが追加されています。
そして、Scene 及び Node にこれらイベントに対するハンドラを登録するためのプロパティが追加されています。
以下に時間の関係で当日の発表で話せなかったことを列挙します。
デモでは次の3つのサンプルをお見せしました。デモが失敗したときに備えて録画しておいた動画がありますので、それも一緒にアップしておきます。
スライドではスペースの都合上、コードをかなり圧縮して載せていました。上のgistにアップしたコードの方を良く確認してもらえたらと思います。
以下にちょっと補足を。
@Override
public void initialize(URL url, ResourceBundle rb) {
fonts = Font.getFamilies();
pagination.setPageCount(fonts.size() / FONTS_PER_PAGE);
pagination.setPageFactory(new Callback<Integer, Node>() {
@Override
public Node call(Integer idx) {
return createPage(idx);
}
});
lvFonts.setItems(FXCollections.observableArrayList(fonts));
}
private VBox createPage(int idx) {
VBox box = new VBox(5.0);
int page = idx * FONTS_PER_PAGE;
for (int i = page; i < page + FONTS_PER_PAGE; i++) {
Label lblFont = new Label(fonts.get(i));
box.getChildren().add(lblFont);
}
return box;
}
このようにJavaFX2.2ではマルチタッチを容易に開発可能なAPIが追加されています。今のところまともに使える環境はWindows8くらい (しかもデスクトップモード) なのがちょっと悲しいですが、みなさんもどんどん使ってみてください。