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

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

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

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

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

3376閲覧

textAreaで1行ずつテキストを表示させたいです。

YM_anoahiro

総合スコア21

JavaFX

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

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2019/01/07 07:54

前提・実現したいこと

練習としてjavafxを使用してコマンドプロンプトの模擬アプリを作ろうと思っています。 その中で本来のコマンドプロンプトでpingコマンドを使った時同様、 10.55.55.33 からの応答: バイト数 =32 時間 <1ms TTL=128 10.55.55.33 からの応答: バイト数 =32 時間 <1ms TTL=128 10.55.55.33 からの応答: バイト数 =32 時間 <1ms TTL=128 10.55.55.33 からの応答: バイト数 =32 時間 <1ms TTL=128 の部分のところを例えば1行1秒ずつでtextAreaに表示させたいのです。 ソースを載せるのでどこを直した方がいいか教えてください。 ド初心者なので多少のことは目をつぶって頂けるとありがたいです。

発生している問題・エラーメッセージ

コンパイルしてもエラーは出てないのですが、 実際に実行すると、4秒経った後に全部の本来表示させたい文が出てくるのです。

該当のソースコード

java

1import javafx.application.Application; 2import javafx.geometry.Insets; 3import javafx.scene.Scene; 4import javafx.scene.control.*; 5import javafx.scene.layout.*; 6import javafx.stage.Stage; 7import javafx.scene.paint.Color; 8import javafx.scene.text.Font; 9import java.awt.Dimension; 10import javafx.scene.control.TextArea; 11import java.util.*; 12 13public class sample extends Application { 14Label l1, l2; // ラベル 15TextField tx1, tx2; // テキストフィールド 16Button start, buttonSub, buttonMul, buttonDiv, buttonMod, bC; // ボタン 17TextArea textArea,ta2; // テキストエリア 18ChoiceBox<String> cb;//チョイスボックス 19RadioButton rb1,rb2,rb3;//ラジオボタン 20ToggleGroup ping; 21int num1, num2; 22 23public void start(Stage stage) { 24stage.setWidth(1200); 25stage.setHeight(700); 26 27 28l1 = new Label("pingコマンドデモ"); 29l1.setFont(new Font(40)); 30 31l2 = new Label("コマンド選択してください"); 32 33rb1=new RadioButton("ping 10.55.55.33"); 34ping=new ToggleGroup(); 35rb1.setToggleGroup(ping); 36rb1.setSelected(true); 37 38 39bC = new Button("Clear"); 40bC.setOnAction(event -> buttonClearPressed()); 41start = new Button("実行"); 42start.setOnAction(event -> buttonStartPressed()); 43 44textArea = new TextArea("実行結果が表示されます。\nC:¥Users¥f17K6○○○>"); 45textArea.setStyle("-fx-text-fill: white;-fx-font-size: 16;"); 46 47HBox hbox = new HBox(5); 48hbox.getChildren().addAll(start,bC); 49 50VBox vbox = new VBox(5); 51vbox.setPadding(new Insets(20, 25, 25, 25)); 52vbox.getChildren().addAll(l1,l2,rb1,hbox); 53 54BorderPane root = new BorderPane(); 55root.setLeft(vbox); 56root.setCenter(textArea); 57stage.setScene(new Scene(root)); 58stage.show(); 59textArea.lookup(".content").setStyle("-fx-background-color: black;");//色の変更 60} 61 62void buttonClearPressed() { 63textArea.clear(); 64textArea.setText("実行結果が表示されます。\nC:¥Users¥f17K6○○○>"); 65} 66 67void buttonStartPressed(){ 68 int ransu,a=0,b=0,c=0; 69 if ("ping 10.55.55.33"==((RadioButton)ping.getSelectedToggle()).getText()){ 70 textArea.appendText("ping 10.40.83.33\n10.40.83.33 に ping を送信しています 32 バイトのデータ:"); 71 72 for(int i=0;i<4;i++){ 73 try{ 74 Thread.sleep(1000); 75 }catch(InterruptedException e){ 76 System.out.println(e); 77 } 78 textArea.appendText("\n10.55.55.33 からの応答: バイト数 =32 時間 <1ms TTL=128"); 79 } 80 81 textArea.appendText("\n10.55.55.33 の ping 統計:\n パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)\n ラウンド トリップの概算時間 (ミリ秒):\n 最小 = 0ms、最大 = 0ms、平均 = 0ms"); 82 textArea.appendText("\n\nC:¥Users¥f17K6○○○>"); 83 84} 85} 86 87public static void main(String[] args) { 88launch(); 89} 90}

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

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

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

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

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

guest

回答2

0

ベストアンサー

4秒後に一度に変更内容が反映された原因

「単一のイベントハンドラーの処理の中でsleepしながらノードの状態を更新しようとしているから」といえます。

画面を構成する要素(Node)インスタンスの状態(プロパティー)を変更するとそれがディスプレイ上に反映されるのですが、その反映はプロパティーを変更すると同時に行われるわけではありません。ではいつ反映されるかというと、イベントハンドラーからイベントループへ戻った時点と考えれば概ねよいと思います。

要するにご質問のコードの動きは以下のようになったと考えられます。

text

1(A1) JavaFXランタイム内: マウスイベント検出 2(B2) JavaFXランタイム内: マウスイベントに対するハンドラー(buttonStartPressed)起動 3(C3) ハンドラー内: 4 TextAreaへテキストを追記 5 1秒sleep 6 TextAreaへテキストを追記 7 1秒sleep 8 ... 9 TextAreaへテキストを追記 10 <=イベントループへ復帰(return) 11(A2) Nodeの状態が変化していたとき、変更内容をレンダリングスレッドへ転送する。 12 つまりこの時点でようやく(C3)での変更の内容が画面上へ描画される

対処

イベントハンドラーは「ごく短い時間だけ必要な処理を行い、直ちにイベントループへ復帰」するのが原則です。ご質問のコードのようにハンドラーの中でsleepしてしまうと「このハンドラーが終了するまでイベントループが停止し、アプリケーションがイベントに適切に反応しなくなります。それは本質問の主題以上に悪影響を及ぼします。

対処の方法は以下の2通りが考えられます。

(A) 一定時間が経過したら別のイベントを発生させそのハンドラーの中で必要な動作をする
具体的にはTimelineクラスなどが使いやすいです。
(B) 別のスレッドでsleepなどによる処理シーケンスを実装し、そのなかで画面の更新をPlatform.runLaterで要求する

アニメーションのようにあらかじめ決まった時間で画面を更新したいなら(A)の方式が適切と思います。一方「イベントループでは検出できないタイミング(例えば別プロセスで実行中のプログラムが標準出力へ何かを出力した契機)で画面を更新したい場合、(B)の方法がやりやすいと思います。

以下に(B)を用いた簡単な例を挙げます。

java

1void buttonStartPressed() { 2 if (rb1.isSelected()) { 3 Thread thread = new Thread() { 4 @Override 5 public void run() { 6 Platform.runLater(() -> textArea.appendText("first\n")); 7 // for文をforEachに変更しています。Platform.runLaterで用いるlambda式から 8 // ループの制御変数iを参照するにはiがfinalでなくてはならず、forループが使いにくいからです 9 IntStream.range(0, 4).forEach(i -> { 10 try { 11 sleep(1000); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); // デバッグ用 14 } 15 Platform.runLater(() -> textArea.appendText("line" + i + "\n")); 16 }); 17 Platform.runLater(() -> textArea.appendText("last\n")); 18 Platform.runLater(() -> { 19 try { 20 join(); 21 } catch (InterruptedException e) { 22 e.printStackTrace(); // デバッグ用 23 } 24 }); 25 } 26 }; 27 thread.start(); 28 } 29}

投稿2019/01/07 16:17

編集2019/01/08 09:58
KSwordOfHaste

総合スコア18394

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

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

YM_anoahiro

2019/01/08 09:32

無事動きました!ありがとうございました!!!
KSwordOfHaste

2019/01/08 10:01 編集

しまった。コード間違えてました。上記ではコンパイルエラーに・・・ そのあたりはくみ取っていただき解決済みのようですが、一応コードを直しておきます。 --- 元のコードはnew Thread(() -> {...});のようにlambda式としてスレッド処理を書いたため本体の中でThreadに対するメソッド(sleep/join)を呼び出せないものになってました。回答のコードを匿名クラスに書き直しました。失礼しました。
guest

0

https://stackoverflow.com/questions/16868445/appending-text-to-a-textarea-over-time-with-delay

JavaFX does have a timer built in - it's called a Timeline. It's simple, straightforward, and provides extra functionality like Swing's Timer class, and, most importantly, executes code on the UI thread.

https://stackoverflow.com/questions/9966136/javafx-periodic-background-task/9966213#9966213

You can use Timeline for what matter:

省略

for background processes (which don't do anything to UI) you can use old good java.util.Timer:

こちらに書かれていますが、java.util.Timerを使用するのが良いのではないでしょうか。

投稿2019/01/07 15:12

CreeperSaviour

総合スコア129

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問