JavaFXとJavaのコラボレーションことはじめ


java/JavaFX Script

JavaFXとJavaのコラボレーションことはじめ

このページでは、JavaFXで、Javaのクラスを使用するための第一歩について紹介する。
[追記]
このページを見てくださった方から連絡を頂き、 JavaFX ScriptからJavaのクラスを使用する方法について 違う方法のご紹介を頂きました。(追記090916
ありがとうございます。
[さらに追記]ここ
考えてみれば、当たり前の気がしてきた、というメモ。
[さらに追記2]ここ
結局、Null Pointer Exceptionが出ないっていうことが原因だったのだ、というメモ
(詳しくHackしてないので)なぜかは、わからん。。。

Summary

  • JavaFXからJavaのクラスはシームレスに使える。
    • しかし、static修飾子がついていないと思ったとおりに動かない。

想定する開発環境

NetBeans6.*+JavaFX1.0

実践

テンプレートのソースをもとに、Javaで書いたクラスを使用したサンプルを作っていく。

プロジェクトを作る。

  • ファイル->新規プロジェクト
    • JavaFX Scriptアプリケーションを選択する。
    • MyJavaFXCollaborationという名前にしておく。
    • 完了。

初期のテンプレートの状態では、以下のようなソースができているはずです。

	/*
	 * Main.fx
	 *
	 * Created on 2009/08/16, 12:40:23
	 */
	
	package myjavafxcollaboration;
	
	import javafx.stage.Stage;
	import javafx.scene.Scene;
	import javafx.scene.text.Text;
	import javafx.scene.text.Font;
	
	/**
	 * @author tatsuya
	 */
	
	Stage {
	    title: "Application title"
	    width: 250
	    height: 80
	    scene: Scene {
	        content: [
	            Text {
	                font : Font {
	                    size : 16
	                }
	                x: 10
	                y: 30
	                content: "Application content"
	            }
	        ]
	    }
	}

この状態で、主プロジェクトを実行(F6)すると、

result1.PNG

のようなウィンドウができる。

ちなみに、このようなスクリーンショットは、ウィンドウをアクティブにして[Alt]+[Print Screen]を押すことで取得できる。


少し準備

Javaのプログラムを書く前に、.fx側で使いやすいように準備しておく。

	/*
	 * Main.fx
	 *
	 * Created on 2009/08/16, 12:40:23
	 */
	
	package myjavafxcollaboration;
	
	import javafx.stage.Stage;
	import javafx.scene.Scene;
	import javafx.scene.text.Text;
	import javafx.scene.text.Font;
	
	/**
	 * @author tatsuya
	 */
	
	var label:String = "Hello, World!";
	
	Stage {
	    title: "MyJavaFXCollaboration"
	    width: 250
	    height: 80
	    scene: Scene {
	        content: [
	            Text {
	                font : Font {
	                    size : 24
	                }
	                x: 10
	                y: 30
	                content: label;
	            }
	        ]
	    }
	}

大事な部分は、Textのcontentアトリビュートに、直接、値を入れるのではなく、 labelという変数を介しているところである。
labelには、"Hello, World!"という値が入っているので、この状態で実行すると

result2.PNG

のようになる。

パッケージにjavaのソースを追加する。

現在のプロジェクトのパッケージにJavaのソースを追加する。

  • 図のように、現在のパッケージ(myjavafxcollaboration)上で右クリックをする。
  • 新規->Javaクラス
AddJavaClass.PNG
  • クラス名をFooとして完了。

すると、以下のようなソースができる。

	/*
	 * To change this template, choose Tools | Templates
	 * and open the template in the editor.
	 */
	
	package myjavafxcollaboration;
	
	/**
	 *
	 * @author tatsuya
	 */
	public class Foo {
	
	}

JavaFXから使うための公開関数get()を定義して次のように書き換えておく。

	public class Foo {
	
	    private String bar = "bar";
	
	    public String get() {
	        return bar;
	    }
	}

JavaFX側で、Javaのクラスを使用する。

さて、.fxファイルの方に戻って先ほど作ったFooクラスを使ってみる。
get()関数は、String型の変数を返すので、そのままlabelに代入できる。

	var label:String = "Hello, World!";
	var foo:Foo;
	
	label=foo.get();

予想通りならば、"Hello, World!"が"bar"で上書きされて表示されるはずである。

コンパイル、そして実行(1度目)

実行結果

result3.PNG

修正

なにも表示されなかった。。。
なおかつ、コンパイルエラーもでないというややこしい現象である。

結論から言えば、
外から参照されるJavaクラスのなかの変数(実質的に公開関数も) にstatic修飾子をつけて宣言しておく。
Javaでは、static変数は、static関数からしか参照できない。

	public class Foo {
	
	    private static String bar = "bar";
	
	    public static String get() {
	        return bar;
	    }
	}

まだ、詳しく調べたわけではないが、 メモリ管理うんちゃらの問題だと思う。


コンパイル、そして実行(2度目)

result4.PNG

追記090916(javaソースの宣言でstaticを用いない方法)

上記の方法では、既存のjavaでかいたクラスを書き換える(static修飾子)をつける必要があった。

しかし、JavaFXのソース側だけで対応できるとの情報を頂いたのでここに追記として掲載する。

	var label:String = "Hello, World!";
	//var foo:Foo;
	var foo = new Foo();
	
	label=foo.get();

このように記述すればよい。

この方法の方が、メジャーなのかもしれない。

さて、JavaFX風の宣言(var foo:Foo;)とJava風の宣言(var foo = new Foo();)が、 実行に違いを生んでいたようだ。

バグなのか、哲学なのか。。。ちょっと気になるところだ。

さらに追記

var foo:Foo;

var foo = new Foo();
の違いであーだこーだ言ってたが、

JavaFXでは、

右辺から方が推測できるとき、以下のfoo2のように略記できる。

	var foo1 = new Foo();
	
	var foo2 = foo1;

また、foo1のほうも

	var foo1:Foo = new Foo();

を略記してあるものとみなせる。

・・・つまり、

ちゃんとインスタンス化してその参照を管理してるかどうかなのかな。。。

javaで、

	Foo foo;

とかしたら、NULLオブジェクトができるが、

どうやら、JavaFX Scriptの方では、

プリミティブ型も、javaとは違う初期値を与えらているらしいので、

もしかしたら、

staticでないほうの

	var foo:Foo;
	foo.get(); 

javaでいうNullPointerException?みたいな状態なのかもしれない。

メモ

JavaFX ScriptがGUIの(プログラマにとっての)操作性を主眼においているとすれば、 処理的な部分は、Javaで書くのが自然な棲み分けだろう。

さらに追記2

(Javaの)常識的に考えれば、

上記(本文中)、

	var label:String = "Hello, World!";
	var foo:Foo;
	
	label=foo.get();

は、

明らかに、Nullオブジェクト(?)に対するメソッド呼び出しだ。 (メソッドがstatic宣言されていない限りは!

しかし、

JavaFX Script上で、このように記述された場合、

実行時にNullPointerException?発生しない

ちなみに、

インスタンスfooに関して、

foo == null 

の値は、

true

となります。


メモ2

参考まで。

参考