一応やりたいだろうことは出来ますね。
画面更新に対して色々面倒な制約がありますが、ここに書ききれるものでもないので参考リンクを張ります。
1. ポイント1. JavaFXメインスレッドで画面更新を行う
JavaFXにおけるスレッドの扱い - 軽Lab
メインスレッドを止めてしまうThread.sleep()
により、メインスレッドが止まっている事、それから画面更新は処理を抜けてアイドル状態を作らないと起こらないらしい事。
つまりこの仕様のせいでラベルのテキストが更新されていなかったという事。
打開するには、空き時間にメインスレッドで遅延更新をするPlatform#runLater()
を上手く使う事。
2. ポイント2. Threadの代わりにどうやってタイマー処理をするのか
ScheduledExecutorService 使い方メモ
まあ、色々あるんだけどScheduledExecutorService系のものを使うのが良いと思う。
実行タイミングなどが違ったりするので用途に応じて使い分ける感じですね。
3. ではどう直すか?
3.1. 問題点の整理
java
1b.setOnAction(event -> {
2 for (int i = 3; i > 0; i--) {
3 label.setText(String.valueOf(i));
4 try {
5 Thread.sleep(1000);
6 } catch (Exception e) {
7 }
8 }
9 label.setText("start!");
10});
label.setText(String.valueOf(i));
先述の通りメインスレッド処理中では更新できない。遅延更新させる必要がある。
Thread.sleep(1000);
こちらもメインスレッドを止めるだけなので使えない。ScheduledExecutorService等を使う必要がある。
for (int i = 3; i > 0; i--) { … }
前述2つの指摘により、そもそもforループは使えないので、発想を変える必要がある。
ScheduledExecutorService
は実行する処理クラスにRunnable
を使えるので、これをimplements
した実行クラスを作ればいい。(まあ、匿名インナークラスでもいいけど)
3.2. ScheduledExecutorServiceを使う場合
最初に断っておくが実現方法はこれ以外にもある。ここで書くつもりもないけど…。原稿料くれってなるし。
興味があれば他のScheduleServiceについても調べてみると良いと思う。
ScheduledExecutorService - JavaDoc11
Runnableインターフェース
を使ったクラスを作って、それをどう実行するかというのがこのクラスの醍醐味。
一応、サボってこんな感じには書けるが、この場合は1秒間隔で延々とhello
と言い続けてしまう。
別途停止ボタンを置いて止める機構を作れればいいが今回の要件では使えない。
つまりカウントダウン終了時に自発的に止める工夫が必要となる。
java
1ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
2service.scheduleWithFixedDelay(() -> {
3 System.out.println("hello!");
4}, 1, 1, TimeUnit.SECONDS);
まあ、ぱっと浮かんだのはScheduledExecutorService
のタスクを止めるには、ScheduledExecutorService#shutdown()
を呼ぶ必要がある為、
サービスインスタンスを炊く制するタスクに持たせて、カウントダウン終了条件を満たしたらshutdown()
を呼ぶようにすれば良いだろう。
そうすると呼び出し側はこんなイメージになって。
java
1ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
2service.scheduleWithFixedDelay(new MyTask(~), 1, 1, TimeUnit.SECONDS);
呼び出される側(ラベル更新を行う実行犯)はこんな感じになる。
java
1class MyTask implements Runnable {
2 // クラスメンバその1
3 // クラスメンバその2
4 // クラスメンバその3
5
6 891011
12 public MyTask(ScheduledExecutorService service, int count, Label label) {
13 // クラスメンバの初期化処理を書く
14 }
15
16 @Override
17 public void run() {
18 // ラベルを更新する処理
19 // カウントダウンする処理
20 // 終了条件判定でshutdownさせるかどうかの処理
21 }
22}
以上です。
ちなみに、コードを書くためのヒントは出しますが
私の実装コードを現時点で出すつもりはありません。
悪しからず宜しくお願いします。