2013年 7月
JavaFX NetBeans
今日は FXML を使って JavaFX でお約束の Hello World を創っていきます。
JavaFX Scene Builder を使えば Android アプリをつくるようにできるらしいのですが
私は JavaFX Scene Builder を一度も使ったことないし、設定項目の多いプロパティもよく解らないので適当にやってみます。(ヲヒ
メニューバーから[ファイル]-[新規プロジェクト]を選択します。
そして今度はプロジェクトの項目は JavaFX FXML Application を選択し、[ 次> ] ボタンを押します。
FXML を使うので FXML 名を記入します。
そして [ 終了 ] ボタンを押します。
NetBeans IDE によって下図のようにプロジェクトが作成されます。
Hello.fxml
HelloController.java
HelloWorld4FXML.java
が作成されているのが確認できます。
HelloWorld4FXML.java
HelloController.java
Hello.fxml
それではこのまま動かしてみましょう。
Click Me! と書かれたボタンを押すと Hello World! とラベルに表示されます。
それと標準出力にも You clicked me! と出力されます。
GUI の設計は FXML でイベントコントロールは HelloController.java (コントロールクラス)で行ってますね。
さて、NetBeans IDE が自動生成してくれたコードを動かすだけでは面白くないので少し変更してみます。
GUI を少し変更したいので JavaFX Scene Builder を起動します。
Hello.fxml ファイルをダブルクリックするか、右クリックからのコンテキストメニューで [ 開く ] を選択します。
JavaFX Scene Builder が現在のプロジェクトの情報をもとに起動します。
右側にあるインスペクタで選択されたコンポーネントのプロパティを設定できるようです。
設定項目多すぎて解りません。(>_<。)
Java SE 8 がリリースされたら JavaFX のリファレンス本が出版されるだろうから詳細はそれ待ちってことにしよう。
今は直感的操作にたよります。
とりあえず、グリグリしてこんな具合にしてみました。(センスないなぁ・・・
Hello.fxml はこのようになりました。
何やら赤いバッジがついてますが気にしない(ヲヒ
HelloController.java を次のように変更してボタンを押すたびに表示を変更するようにしてみました。
実行結果はこのようになります。
標準出力にも期待通りの出力がされました。
今回初めて JavaFX Scene Builder を使ったのですが複雑なハイテク技術満載の日本製家電製品を使いこなせない一般ユーザーの気持ちに似たものを感じました。
それぞれのコンポーネントのプロパティやエフェクト等を知らないと使いこなせないです!
やっぱり地道に情報収集して少しずつしっかり覚えていかなければいけないようです。
私の場合、ゆっくり楽しみながらがモットーなので面白くないと思った時点でストップして気が向いたら再開すればいいだけのことなので気楽です。
おそらく Java SE 8 がリリースされたらそれらの書籍とともに JavaFX の書籍も出版されるだろうし、
JavaFX Scene Builder を使って開発するのがスタンダードになるだろうからそれまでに予備知識として少しでも慣れておくことを目的としよう!(後ろ向き発言
TAGS: JavaFX,NetBeans |
2013年7月27日4:53 AM |
JavaFX NetBeans
冷やし中華はじめました!
JavaFX はじめました!
と言っても Java SE 8 のコアライブラリとしての JavaFX 8 の日本語の情報がまだあまり見当たらないのでボチボチとはじめます。
とりあえずは JavaFX 2.x あたりの情報を参考にしていくことになります。
まず、JavaFX とは?
どす黒い黒歴史そのものです。
始まりから現在に至るまで無かったことにとか、まるっきり別物のような変貌を遂げてきた歴史があります。
まぁ、これは仕方の無いことと言えばそれまでなんでしょうが・・・
ここへきて、今までの悪行を水に流してもらおうと Java SE 8 のコアライブラリにしてしまえってのは流石ですね。
つまり、Java SE 8 からは安心して使えるよって解釈していいんだよね、きっと!
そういうことでボチボチとゆっくり慣れることにしようと思います。
それでは早速はじめることにしましょう。(^_^)
開発環境は
JDK™ 8 Early Access Releases
NetBeans IDE 開発版
Scene Builder 1.1 Developer Preview
を使っていきます。
それぞれが開発版という不安定なものを使うけど、Java SE 8 のリリースまでには半年以上もあるからトラブルも笑って楽しみましょう。(^_^;)
上記の開発環境のインストールが完了したら、NetBeans IDE の [ ツール ] → [ オプション ] メニューから Java を選択して JavaFX Scene Builder を統合させます。
これで快適な GUI 設計が可能になるはずです。(まだ一度も試してませんけど・・。(^_^;)
今回は、JavaFX Scene Builder は使う予定はないので追々試してみたいと思います。
それでは、お約束の Hello World! を創りましょう!
メニューバーから[ファイル]-[新規プロジェクト]を選択します。
新規プロジェクトウィンドウが表示されるので、カテゴリ[JavaFX]、プロジェクト[JavaFXアプリケーション]を選択し [ 次 > ] ボタンをクリックします。
新規 JavaFX アプリケーションウィンドウが表示されますので下図を参考に必要項目を記入して [ 終了 ] ボタンを押してください。
NetBeans IDE がとても親切なコードで迎えてくれます。
これがウザいと思うなら、先ほどの新規 JavaFX アプリケーションウィンドウの アプリケーション・クラスの作成のチェックを外せば OK です。
このまま実行してみましょう。
真ん中にボタンが一つあるだけアプリが立ち上がりました。
押してみます。
標準出力に、Hello World! って出力されてます。
Swing とはイベント処理が少し違うようですが同じようなものですね。(矛盾した表現 (^_^;)
Java SE 8 では Lambda 式を使うことができます。
NetBeans IDE は、Lambda 式が使えるよって親切に教えてくれます。
せっかくだから素直に変更させていただきました。
すっきりしましたね。
でも、型も省略してほしかったよ。
仕方ないので手動で変更w
これが未来の Java のコードなんですね。
肝心のコードの説明は面倒なのと、まだ良く理解できてないのでパスということで・・・(>_<)
だいたいのことは解るけど、JavaFX を始めるにあたり参考にしているサイトの情報も古くなりつつあるので・・・
Java SE 8 がリリースされて、情報が安定してから学習し直せばいいやってのりでやってます。
ここまでは NetBeans IDE が創ってくれたコードなのでそれだけでは面白くないのでラベルの表示とボタンのイベント処理を変更してみました。
ソースコードは下記のように変更しました。
間違い等あるかもしれませんが、その時は優しくそって教えてくださいませ!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
package jp.yucchi.hello.world; import javafx.application.Application; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.stage.Stage; /** * * @author Yucchi */ public class HelloWorld extends Application { private int cnt; @Override public void start(Stage primaryStage) { StackPane root = new StackPane(); VBox vbox = new VBox(); root.getChildren().add(vbox); StackPane topPane = new StackPane(); vbox.getChildren().add(topPane); Label label = new Label("JavaFX より愛をこめて!"); topPane.getChildren().add(label); StackPane bottomPane = new StackPane(); vbox.getChildren().add(bottomPane); Button btn = new Button(); btn.setText("Say 'Hello World'"); bottomPane.getChildren().add(btn); btn.setOnAction(event -> { cnt++; if ((cnt & 1) == 0) { label.setText("はろ~ わーるど! " + cnt); } else { label.setText("Hello, World! " + cnt); } }); Scene scene = new Scene(root, 300, 250); primaryStage.setOpacity(0.7); primaryStage.setTitle("Hello World!"); primaryStage.setScene(scene); primaryStage.show(); } public static void main(String[] args) { launch(args); } } |
実行結果は次のようになります。
ウィンドウが薄くなっているのは何かの間違いでなく、
primaryStage.setOpacity(0.7);
と設定しているからです。
ラベルのテキスト文字の表示をボタンが押されるたびに変更とカウントをしました。
レイアウトが酷いとツッコミがあると思うけどこれは超面倒なコードを書くのが嫌なのでわざとです。
この問題を解決するのには、JavaFX Scene Builder を使えば従来の Swing アプリケーションを
NetBeans IDE で開発するようにポトペタと楽に実際の配置を眼で確認しながら構築できるようになるはずです。
今回は初めての JavaFX ということでちゃんと動いてめでたし、めでたし!
TAGS: JavaFX,NetBeans |
2013年7月26日10:43 AM |
Computer
RATOC RS-EC32-U3R を導入しました。
これは USB3.0 外付け HDD システムです。
これを何故導入したかというと最近 HDD がやたら故障して大切なデータを失うことが連発したからです。
こまめにバックアップとればいいのだけれど・・・ついついさぼってしまいます。
この機械の良いところは RAID1 を構築できることと、ホットスワップ、自動リビルドができることです。
RAID1 は問題ないとしてもホットスワップは機械の構造上ちょっと危険な雰囲気がただよってます。
何故かというと構造上 HDD をケースに差し込んで蓋で押さえて固定するようになっているからです。
蓋をしない状態だと HDD がぐらぐらの状態で不安定なんですよね。
そのかわりにカートリッジを使わない構造のおかげで非常にコンパクトになってます。
まぁ、私の場合ホットスワップと自動リビルドなんてなくても手動でいい人なんで問題ないです。
だいたいそこまで求めるならスペアを装備できるようにして故障時には自動で切り替え構築しなおす機能を求めますよね。
RAID の設定、電源連動機能の設定、異常時のビープ音の設定は本体で設定できます。
RAID の設定や管理は付属のソフトで簡単にできてしまいます。
また省エネ設定やログの記録、異常時にはメールを送信してくれます。
ただしメールの送信日時はおかしいです。(^_^;)
お値段の割には高機能で至れり尽くせりです。
私がこれを導入するにあたり一番心配したのが静音性です。
4センチのファンがついてるので高周波で五月蠅い音がしないかと・・・
静音性は問題なしでした。(^_^)
とても静かでファンの回ってる音は聞こえませんでした。
故障して回ってないのかと心配して手をかざしてみたくらいです。
ちゃんと HDD の熱を逃がしてくれてます。
久しぶりにコストパフォーマンスに優れた一品に出会えて感動してます。
完成度が非常に高くてついつい、もう一台購入してしまいました。
TAGS: Computer |
2013年7月25日9:06 PM |
Java
Java8 の目玉機能は並行処理を容易にするために採用された Lambda に注目が集まってます。
その他にも便利な機能が追加されているのですが何故か人気の無い? CompletableFuture を試してみました。
これも外国語のサイトからの情報を元に解らないままゴニョゴニョしてみました。
ちなみに CompletableFuture の情報はグーグル先生に聞いてみても新しい情報は数件しかヒットしませんでした。
誰かが日本語で優しく解説してくれるのを待っていたのですが Lambda の人気の高さからか見向きもされない可愛そうな子となってます。(ヲヒ
CompletableFuture っていったい何者なの?
これまでは非同期処理の返り値を取るためには ExecutorService、 Callable、Future インターフェースを使っていました。
この CompletableFuture を使えばそれらを簡単にできちゃうよって優れもののようです。
それでは試してみましょう。
だいたいの流れをサクッと説明すると、
それぞれ、countHoge() , countFuga() , countChome() と言うメソッドで時間のかかる計算結果を取得するものとします。
それぞれ 1 秒、3 秒、7 秒と計算時間を要します。
返り値は、1 、3 、7 とします。
もちろん ExecutorService を利用します。
それぞれ CompletableFuture.supplyAsync() にて CompletableFuture を生成します。
CompletableFuture.allOf() メソッドにてそれぞれをひとまとめにします。
thenRun() メソッドにて 処理を開始し、計算結果を返します。
あとは get() メソッドにて計算結果を取得すればいいだけです。
返り値を利用して新たに CompletableFuture<T> を作ることも可能です。
この CompletableFuture クラスには 50 種類ほどのメソッドが用意されてるのでかなり自由度が高くいろんなことができそうです。
ちなみに良く解らないのに適当に創ったコードなので間違いがあると思いますが笑って許してくださいませ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
package jp.yucchi.trycompletablefuture; public class SomeWorks { public int countHoge() { try {Thread.sleep(1_000);}catch(InterruptedException e){throw new RuntimeException(e);} return 1; } public int countFuga() { try {Thread.sleep(3_000);}catch(InterruptedException e){throw new RuntimeException(e);} return 3; } public int countChome() { try {Thread.sleep(7_000);}catch(InterruptedException e){throw new RuntimeException(e);} return 7; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
|
package jp.yucchi.trycompletablefuture; import java.lang.management.ManagementFactory; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; public class TryCompletableFuture { private static final SomeWorks works = new SomeWorks(); private static ExecutorService executor; private static CompletableFuture<Integer> hoge; private static CompletableFuture<Integer> fuga; private static CompletableFuture<Integer> chome; private static CompletableFuture<Void> doAllWorks; public static void main(String[] args) { int procs = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors(); if (procs < 3) { procs = 3; } executor = Executors.newFixedThreadPool(procs); hoge = CompletableFuture.supplyAsync(() -> works.countHoge(), executor); fuga = CompletableFuture.supplyAsync(() -> works.countFuga(), executor); chome = CompletableFuture.supplyAsync(() -> works.countChome(), executor); doAllWorks = CompletableFuture.allOf(hoge, fuga, chome); workCompletableFutures(); try { System.out.println(hoge.get()); } catch (ExecutionException | InterruptedException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); } try { System.out.println(fuga.get()); } catch (InterruptedException | ExecutionException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); } try { System.out.println(chome.get()); } catch (InterruptedException | ExecutionException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); } CompletableFuture<String> monad = hoge.thenApply(r -> r * r * Math.PI).thenApply(Object::toString); try { System.out.println("monad = " + monad.get()); } catch (InterruptedException | ExecutionException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); } while (true) { if (doAllWorks.isDone()) { System.out.println("executor.shutdown()"); executor.shutdown(); try { if (!executor.awaitTermination(20, TimeUnit.SECONDS)) { System.out.println("executor.shutdownNow()"); executor.shutdownNow(); break; } } catch (InterruptedException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); executor.shutdownNow(); break; } break; } } } private static void workCompletableFutures() { long startTime = System.nanoTime(); System.out.println("<--- START --->"); doAllWorks.thenRun(() -> { try { if ((hoge.get() + fuga.get() + chome.get()) == 11) { System.out.println("<--- DONE --->"); } else { System.out.println("<--- ERROR --->"); } } catch (ExecutionException | InterruptedException e) { throw new RuntimeException(e); } long time = System.nanoTime() - startTime; System.out.println("処理時間は、" + (int) (time * 1e-9) / 3_600 + "時間" + (int) ((time * 1e-9) / 60) % 60 + "分" + (int) (time * 1e-9 % 60) + "秒" + Double.toString((time * 1e-9 % 60) % 1).substring(2)); }); } } |
出力結果は次のようになります。
<— START —>
1
3
7
<— DONE —>
処理時間は、0時間0分6秒9916577070000008
monad = 3.141592653589793
executor.shutdown()
処理時間からそれぞれの処理が平行実行されていることが解りますね。(^_^)
プロファイラで確認してみました。
thenRun() メソッドを使用すると上記のような結果となりますが
thenRunAsync() メソッドというものもあります。
これは ForkJoinPool.commonPool() を使っているようです。
若干 thenRun() メソッドと動作が違います。
こちらはメソッド内の処理が ExecutorService に全て乗らない場合があります。
登録されたタスクが終了した時点で shutdown 開始するとshutdown 開始までに ExecutorService に乗っていれば当然処理されるのですがタイミングが悪いと間に合わず未処理となってしまいます。
37 行目から 60 行目の計算結果取得処理をコメントアウトしてそれぞれ実行してみると良く解ります。
thenRun() メソッドの場合は次のように全て実行され出力されます。
<— START —>
<— DONE —>
executor.shutdown()
処理時間は、0時間0分6秒9965874390000007
thenRunAsync() メソッドを使用した場合は次のように一部処理されずプログラムが終了する場合があります。
<— START —>
executor.shutdown()
<— DONE —>
このあたりは微妙に違うので注意が必要ですね。
ついでに、thenRunAsync() メソッドを使用した場合のプロファイラでみてみました。
ForkJoinPool.commonPool() が存在してますね。
これらの使い分けのシチュエーションが思いつきません。(^_^;)
さて、時間のかかる処理をするのはいいけどあまりにも時間がかかりすぎた場合はデフォルト値を返すようにしたい場合がありますよね。
そんな時のために get(long timeout, TimeUnit unit) メソッドと complete(T value) メソッドが用意されてます。
プログラムに次のコードを追加して動かしてみましょう。
|
workCompletableFutures(); try { System.out.println(fuga.get(2, TimeUnit.SECONDS)); } catch (InterruptedException | ExecutionException | TimeoutException ex) { Logger.getLogger(TryCompletableFuture.class.getName()).log(Level.SEVERE, null, ex); fuga.complete(99); } |
fuga.get(2, TimeUnit.SECONDS) 2 秒でタイムアウトして fuga.complete(99) で fuga に 99 を設定します。
もちろん例外もスローされます。
ではプログラムを実行して確認してみましょう。
<— START —>
1
99
7 08, 2013 12:13:28 午前 jp.yucchi.trycompletablefuture.TryCompletableFuture main
SEVERE: null
java.util.concurrent.TimeoutException
at java.util.concurrent.CompletableFuture.timedAwaitDone(CompletableFuture.java:376)
at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1555)
at jp.yucchi.trycompletablefuture.TryCompletableFuture.main(TryCompletableFuture.java:39)
<— ERROR —>
7
処理時間は、0時間0分6秒9896285360000006
monad = 3.141592653589793
executor.shutdown()
ちゃんとタイムアウトして例外を投げてそして fuga に 99 をセットしてますね。
fuga の値が 99 になることによって hoge, fuga, chome の合計値が 11 と等しくならないので <— ERROR —> と判定され出力されてます。
もう、ExecutorService、 Callable、Future インターフェース の時代はオワコンかな?
ざっと確認したけど間違ってる可能性が高いので日本語で誰かが詳しく解説してくれるのを待つとしましょうか。
かなり CompletableFuture っていけてる気がします!
Java8 早くリリースしておくれ!
TAGS: Java |
2013年7月8日12:14 AM |