質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

Q&A

1回答

4349閲覧

マウスカーソルの変更が反映されるタイミングについて

XCUBE

総合スコア101

JavaFX

JavaFXとは、Java仮想マシン上で動作するリッチインターネットアプリケーション (RIA) のGUIライブラリです。Swingとは異なり、FXMLと呼ばれる XMLとCSSを併用してデザインを記述します。

0グッド

0クリップ

投稿2019/02/12 05:42

編集2019/02/12 06:02

JavaFXで画面UIからの操作により、更新処理を実行しています。
その際、更新処理に時間が掛かるのでsetCursor(Cursor.WAIT)でマウスカーソルを変更して
「ただいま更新処理をしてますよ」というのを示したいと思っています。

操作により発生したイベント処理で
setCursor(Cursor.WAIT) → 更新処理 → setCursor(Cursor.DEFAULT)
と書いてみたのですが、更新処理中にマウスカーソルが変化せず狙い通りにいきませんでした。

更新処理をスレッドにすれば上手くいくのではないかと次のように書いたのですが、これでも上手くいきません。

java

1Scene scene = pane.getScene(); // コンテナよりsceneを取得 2Cursor bkCur = scene.getCursor(); 3scene.setCursor(Cursor.WAIT); // マウスカーソル変更 4 5ExecutorService service = Executors.newSingleThreadExecutor(); 6Future<Boolean> future = service.submit( () -> { // 更新処理スレッド 7 Thread.sleep(10000); // ダミー処理 8 return true; 9 } 10); 11 12Boolean thResult = future.get(); // スレッドの終了を待つ 13scene.setCursor(bkCur); // マウスカーソルを戻す 14

処理中にマウスカーソルを変更しても処理が終了して画面に制御が戻らないとカーソルに反映できないようですが、
処理中にマウスカーソルを変更するにはどうしたらよいでしょうか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

原因はFuture#getで結果を得ようとしている点です。getは別スレッドでの計算が完了するのを同期的に待つ機能ですのでこれを使ってしまうと別スレッドの実行が完了するまでJavaFXアプリケーションスレッド(以降単にアプリケーションスレッドと呼びます)が止まることになり、別スレッドとした意味がなくなります。つまりアプリケーションスレッドで時間がかかる処理を直接行うことと変わらなくなるわけです。

コードコメントに「スレッドの終了を待つ」とありますが、一般的にアプリケーションスレッドで何かを待つ処理をするのは不適切ですから、別スレッド側で(処理が完了したタイミングで)Platform.runLaterを用いてGUIの状態変更をするのが簡単と思います。

java

1Button startButton = new Button("start"); 2startButton.setOnAction(ev -> { 3 startButton.setDisable(true); // 実行中はボタンを押せなくする 4 Scene scene = startButton.getScene(); 5 Cursor currentCursor = scene.getCursor(); 6 scene.setCursor(Cursor.WAIT); 7 8 new Thread(() -> { 9 try { 10 Thread.sleep(10000); 11 } catch (InterruptedException e) { 12 ; // この例では割り込みは無視 13 } finally { 14 Platform.runLater(() -> { 15 scene.setCursor(currentCursor); // カーソルを元に戻す 16 startButton.setDisable(false); // ボタンを再び有効にする 17 }); 18 } 19 }).start(); 20});

なお、もし実行中のバックグラウンド処理の進行状況をProgressBarなどで表示するなどもう少し凝ったことをするならjavafx.concurrent.Task<T>を使うとよいと思います。

投稿2019/02/14 09:15

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

XCUBE

2019/02/18 09:34 編集

KSwordOfHaste様 サンプルコードまで提示いただいてありがとうございます。 なぜ時間の掛かる処理を別スレッドに切り出したかといいますとマルチスレッドにすることによって待ち時間の間にマウスカーソルが切り替わってくれるのではないかと期待したからでした。 やはりイベントハンドラ内で変更したマウスカーソルはイベントハンドラを抜けないと実際に変わらないってことですなんですね。 処理が終わるまで当該イベントだけでなく他の操作を一切できないようにしたいので処理が終わるまでイベントハンドラを抜けたくなかったのですが、それが出来ないとなると他の画面操作もsetDisable(false)だ抑制しなければならなくなり画面の変更による保守性が悪くなるので、なんとしてもイベントハンドラ内でマウスカーソルの切替えをできればと思っていました。 KSwordOfHaste様 の回答を受けてマウスカーソルで処理中を表現するのではなく、イベントハンドラ内でモーダルダイアログを表示させて処理中を表現することも検討しようと思います。
KSwordOfHaste

2019/02/19 01:30 編集

> 他の画面操作もsetDisable(false)だ抑制しなければならなくなり画面の変更による保守性が悪くなる 回答コードでボタンに対してsetDisableしたのは「このボタン以外の他の操作は可能」という想定です。「アプリケーションを終了させる以外の全ての操作を許す」想定なら、シーンのrootノードに対してsetDisableする方法も考えられます。あらゆる全ての操作を禁止するならXCUBEさんがおっしゃるように「しばらくお待ちください」的なメッセージダイアログを ・デコレーションなし(タイトルバーのクローズボタンを押されると困るため) ・アプリケーションモーダル で表示するのがよいと思います。ただその場合「なんの操作も受け付けなくなる」ことを示すためやはりカーソルをWAITにするのが自然と思います。 ただGUIアプリケーションはなるべくユーザーのストレスをなくせるようにしたいので場合によっては「時間のかかる操作をキャンセル」などなんらかのユーザー操作を受け付けた方がベターとは思います。それだけ作りに配慮が必要になりますが。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問