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

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

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

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

Java

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

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

解決済

マルチスレッドを用いた際の複数アニメーション描画・JavaFX(Exception in thread、duplicate children added)

magutyan0814
magutyan0814

総合スコア2

JavaFX

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

Java

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

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。

3回答

1評価

0クリップ

561閲覧

投稿2022/01/08 11:57

編集2022/01/19 14:45

前提・実現したいこと

SceneBuilderとJavaFXで、4つの四角から円が流れていくアニメーションを作成しようとしています。
マルチスレッド機構を必ず使い、制作したいです。

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

スレッドを2つ以上同時にstart()させると以下のようなエラーメッセージが出てきます。
また、表示されるウインドウにはアニメーションをつけている円以外(各GUI要素・四角)は表示されます。円は一つも表示されません。
duplicate children added: から、複数の図形を描画する際のgetChildren().add(machine)で追加できないような問題が起きていると思うのですが、解決方法がわかりません。

Exception in thread "Thread-4" Exception in thread "Thread-3" java.lang.IllegalArgumentException: Children: duplicate children added: parent = BorderPane@61af5816 at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:561) at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:205) at application.Material.run(Material.java:55) java.lang.IllegalArgumentException: Children: duplicate children added: parent = BorderPane@61af5816 at javafx.graphics/javafx.scene.Parent$3.onProposedChange(Parent.java:561) at javafx.base/com.sun.javafx.collections.VetoableListDecorator.add(VetoableListDecorator.java:205) at application.Material.run(Material.java:55)

該当のソースコード

Mainクラス、Materialクラス(アニメーションを持つ円)、Machineクラス(通過点の四角)でできています。
MaterialクラスにThreadクラスを継承させ、run()のオーバーライドでアニメーションを設定しPlay()させています。
エラー発生部分はMainクラス内のmatR.start();matB.start();の辺りと考えられます。

Java

package application; import java.net.URL; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.layout.Pane; import javafx.stage.Stage; import javafx.scene.shape.*; import javafx.scene.paint.*; public class Main extends Application { // @FXML // private Circle circle1; public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { //Pane setup URL location = getClass().getResource( "Main.fxml" ); FXMLLoader fxmlLoader = new FXMLLoader( location ); Pane root = (Pane) fxmlLoader.load(); final int width = 600; final int height = 400; //path setup final int startRedX = 100; final int startRedY = 100; final int moveWidth = 350; final int moveHeight = 200; Path pathRB = new Path(); pathRB.getElements().add(new MoveTo(startRedX, startRedY)); pathRB.getElements().add(new LineTo(startRedX + moveWidth, startRedY)); Path pathBG = new Path(); pathBG.getElements().add(new MoveTo(startRedX + moveWidth, startRedY)); pathBG.getElements().add(new LineTo(startRedX + moveWidth, startRedY + moveHeight)); Path pathGY = new Path(); pathGY.getElements().add(new MoveTo(startRedX + moveWidth, startRedY + moveHeight)); pathGY.getElements().add(new LineTo(startRedX, startRedY + moveHeight)); Path pathYR = new Path(); pathYR.getElements().add(new MoveTo(startRedX, startRedY + moveHeight)); pathYR.getElements().add(new LineTo(startRedX, startRedY)); //machine setup Machine machineRed = new Machine(); Machine machineBlue = new Machine(); Machine machineGreen = new Machine(); Machine machineYellow = new Machine(); machineRed.set(root,Color.RED,80,70); machineBlue.set(root,Color.BLUE,440,70); machineGreen.set(root,Color.GREEN,440,280); machineYellow.set(root,Color.YELLOW,80,280); machineRed.view(); machineBlue.view(); machineGreen.view(); machineYellow.view(); //material setup //threads Material matR = new Material(); Material matB = new Material(); Material matG = new Material(); Material matY = new Material(); matR.set(root, pathRB); matR.colorSet(Color.RED); matB.set(root, pathBG); matB.colorSet(Color.BLUE); matG.set(root, pathGY); matG.colorSet(Color.GREEN); matY.set(root, pathYR); matY.colorSet(Color.YELLOW); // MaterialThread matRthread = new MaterialThread(matR); // MaterialThread matBthread = new MaterialThread(matB); matR.start();//エラー発生? matB.start(); // matG.start(); // matY.start(); // matR.move(); // matB.move(); // matRthread.start(); // matBthread.start(); primaryStage.setScene( new Scene( root , width , height ) ); primaryStage.show(); } }

Java

package application; import javafx.scene.shape.*; import javafx.animation.*; import javafx.util.Duration; import javafx.scene.layout.Pane; import javafx.animation.PathTransition; import javafx.scene.paint.*; public class Material extends Thread{ protected Circle circle = new Circle(10); protected Pane root; protected Path path; protected PathTransition animation; protected Color color; public void set(Pane root, Path path /*,double x, double y*/){ this.root = root; this.path = path; } public void colorSet(Color color){ this.color = color; circle.setFill(color); } public void move(){ animation = new PathTransition(); animation.setNode(circle); animation.setDuration( Duration.seconds( 4 ) ); animation.setPath( path ); animation.setInterpolator( Interpolator.LINEAR ); animation.setAutoReverse(false); animation.setCycleCount(0); root.getChildren().add(circle); animation.play(); } @Override public void run(){ this.animation = new PathTransition(); this.animation.setNode(this.circle); this.animation.setDuration( Duration.seconds( 4 ) ); this.animation.setPath( this.path ); this.animation.setInterpolator( Interpolator.LINEAR ); this.animation.setAutoReverse(false); this.animation.setCycleCount(0); this.root.getChildren().add(circle); this.animation.play(); } } // class MaterialThread extends Thread{ // private Material material; // public MaterialThread(Material material){ // this.material = material; // } // @Override // public void run(){ // this.material.move(); // } // }

Java

package application; import javafx.scene.shape.*; import javafx.scene.layout.Pane; import javafx.scene.paint.*; public class Machine{ protected int width = 80; protected int height = 60; protected int x,y; protected Rectangle machine = new Rectangle(x,y,width,height); protected Pane root; protected Color color; protected Thread t; public void set(Pane root, Color color, int x, int y){ this.x = x; this.y = y; this.machine = new Rectangle(x,y,width,height); this.root = root; this.color = color; } public void view(){ machine.setFill(color); root.getChildren().add(machine); } }

追記

FXML

<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.Slider?> <?import javafx.scene.layout.AnchorPane?> <?import javafx.scene.layout.BorderPane?> <?import javafx.scene.layout.HBox?> <BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Main"> <top> <HBox prefHeight="15.0" prefWidth="600.0" BorderPane.alignment="CENTER"> <children> <Button mnemonicParsing="false" text="Start" /> <Button mnemonicParsing="false" text="Stop" /> </children> </HBox> </top> <bottom> <Slider BorderPane.alignment="CENTER" /> </bottom> <center> <AnchorPane prefHeight="331.0" prefWidth="600.0" BorderPane.alignment="CENTER" /> </center> </BorderPane>

試したこと

・マルチスレッド機構を用いずにMaterialクラスにrun()と同じ内容のメソッドを作成したうえでそのメソッドを同じように複数呼び出すと同時にアニメーション描画することが出来ました。
・調べている中でGroupを用いると直りそうな気がしましたが、まだよくわかっていなのできちんとしたアドバイスをいただきたいです。

追記
先程、Mainクラス内で複数のstart()の間にthread.sleep(..)を挟んで実行するとうまくいきました。これがなぜなのかもわからず、、皆様の知恵を貸してくだされば大変助かります。よろしくお願い致します。

補足情報(FW/ツールのバージョンなど)

JavaFX Scene Builder 17.0.0

解決後の追記

皆さんのご協力で何とか解決いたしました!
ベストアンサーですが、追記依頼のコメント内でご指摘頂いた皆さんにも宛てるつもりでshiketaさんの回答につけさせていただきます。
本当にありがとうございました!

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

TN8001

2022/01/08 15:37

普通はUIスレッド以外からUIをいじると IllegalStateException: Not on FX application thread が出るんですが確かに IllegalArgumentException: Children: duplicate children added が出ますね。。。 sleepを入れると動いちゃうほうがイレギュラーだと思います^^; とはいえ、これThreadの意味全くなくないですか? Materialのコンストラクタでplayまでしちゃっても、見た目?は何も変わらないと思うのですが。
magutyan0814

2022/01/08 15:48

コメントありがとうございます! そうなんですね、、どのスレッドからUIをいじるかでもエラーが出るのですね。勉強になります。 Threadですが、実は学校課題の条件でマルチスレッド機構を必ず使わなければならず、初期開発段階ですがどんな感じだろうと思って使ってみたらこのエラーにぶつかった形です。最終的にスレッドが使えないと困るため質問させて頂きました。 仰る通り、materialコンストラクタ内で全て済ませてもいいのです。(実際動きました)ですが、この後図形の四角に丸が当たったら丸をその色に塗り替えて別pathでアニメーションplayというようにまた開発を進めていく予定のため、threadを試したいのもありこのように作成しました。
TN8001

2022/01/08 16:23

なるほどこの後もあるわけですね。 少なくとも add(circle) はコンストラクタに移せるはずです。 それで duplicate children added はなくなると思います。 が、今度は play でエラーが出ると思います(手元ではArrayIndexOutOfBoundsExceptionが出たりしました) Platform.runLater(() -> { animation.play(); }); のようにUIスレッドに回せばエラーは出なくなりました(playがだめなのか作成もダメなのかは未確認)
jimbe

2022/01/08 17:01

> Threadですが、実は学校課題の条件でマルチスレッド機構を必ず使わなければならず マルチスレッドと動作結果(表示)以外に、課題として何が条件として決まっているのでしょうか。
magutyan0814

2022/01/09 03:21 編集

@TN8001 さん ご指摘ありがとうございます。結論から言うと確実に動くようになりました。本当にありがとうございます。 回答のshiketaさんの意見も併せて直してみたところ、IllegalArgumentExceptionのエラーはなくなりました。しかしやはり、TN8001さんと同じようにArrayIndexOutOfBoundsExceptionが出てしまっていました。(時々エラーが出ずに動いたり、全く動かなかったりします。そこの理由は本当にわかりません。) そこで、教えて頂いた Platform.runLater(() -> { animation.play(); }); をrun()内play()の代わりに使うと百発百中で動くようになりました!初めのご指摘通り別スレッドからGUIをいじるときに出るエラー文はIllegalStateExceptionらしくエラー文が食い違っていますが、別スレッドからアニメーションを動かそうとしていたのは一因だったのかもしれません。 ArrayIndexOutOfBounceは何の配列に対して出ていたか本当にわかりませんが、ひとまず動いて一安心できました。本当にありがとうございました。 もし何かこのArrayIndexOutOfBounceに関してなんとなく原因がわかるようでしたら、教えて頂けると助かります。ありがとうございました。
magutyan0814

2022/01/09 03:16

@jimbi さん 他には条件はありません!マルチスレッド同士で同期機構をつけると尚良い、という風に言われています。
jimbe

2022/01/09 04:37

> マルチスレッド同士で同期機構をつけると尚良い マルチスレッドにすることと同期機構をつけることは同じではありませんが、マルチスレッドだけで良いのでしょうか。
magutyan0814

2022/01/09 05:00

@jimbe さん 今はまだ初期開発段階で、当たり判定などある程度のところまで作ってから同期機構をつけようと思っています。 もしかしたらこのままでは同期機構で問題が出そうなところ等ありますかね、、?
jimbe

2022/01/09 05:28 編集

同期で問題といいますか、そもそも先にコメントで書かれていますように、現状スレッドの意味がありません。その上で同期させるといっても、結局コードに同期のコードが書いてあるだけでプログラムとしては意味が無いものとなり得ます。 課題が何をさせようとしているのか、何の為にスレッドを使い、何の為に同期が必要なのかをはっきりさせないと、ただ長いだけのプログラムになります。 例えば、円を移動させるのに PathTransition を使っていますが、これを自作で行うとしたらどうでしょう。 何を同期させるか(スレッドそのものか、フィールドアクセスか)ははっきりしませんが、マルチスレッドの意味は成立すると思います。
magutyan0814

2022/01/09 06:13 編集

@jimbe さん わざわざアドバイスありがとうございます泣 助かります! 私の制作テーマとして、工場生産ラインをアニメーションで再現するというものに決めてこのコードを書いています。ですので、円の移動に手をかけるというより、例えば生産ラインの処理機械に見立てた四角形が円を受け取ったとき、その四角形を何らかの処理をしているような色に差し替え、処理が終わったら元の色に戻り次の四角形へ色が変わった円をアニメーションで送り出す、というような形にしたいです。 そこで各四角形が差し変えられる色が異なっていたり、各四角形で円を受け取るタイミングが違う場合にも対応できるなどスレッドを使えば色々なことができるかなぁと思っております。(まだ作っていない者の想像ですが)また、同期処理はオプションで、必須というわけではありません。 この質問はマルチスレッド機構を使ってみようということで簡単に書いたコードです。せっかくお答えいただいたのですが、ばっさり変わってしまう可能性もあります。しかし解決しておかないと困ると思いまして質問させていただきました。
jimbe

2022/01/09 09:04

コードの背景が大分見えてきました。ご説明ありがとうございます。 ご質問自体とは離れてしまいますが、「工場生産ラインをアニメーションで再現」であれば、円の移動アニメーションの"開始"をスレッドにするのは「マルチスレッド機構を使ってみよう」という程度の意味とは言え、ちょっと意味が無かったと思います。 java はオブジェクト指向であり、オブジェクトを基本単位として処理を記述します。そのメタファーとして例えば「車」を「エンジン」「タイヤ」等の組み合わせとするなど、実際のモノを用いたりすることも良くあります。 その延長として、工場生産ラインを材料・処理機械・コンベア等のオブジェクトとして表現(表示処理も含む)し、処理機械をコンベアの端のとして接続、独自に動作するモノである処理機械とコンベアをスレッドとして動作させ、材料を最初のコンベアの端に載せるとコンベアによって運ばれて処理されていく・・・といった形が出来ます。 もちろん課題は magutyan0814 さんのお考えで達成されるものですのでこれは雑談レベルの私の案ですが、スレッドを投げっぱなしのアニメーションの開始だけでは、スレッドで難しい部分、動作中のデータの入出力・同期等に全く触れませんので、もう少し表現構造にあった形でのお試しをされたほうが良かったのではと感じました。 例えばコンベア(常時動いており、材料を乗せると一定速度で逆側に移動させていき、端に付いたら予め登録(接続)されている別のオブジェクト(=スレッド)に材料を渡す。材料が移動中でも次の材料を乗せられる)をスレッドで(動作・移動の表現・アニメーションも含めて)どう書くか、です。
magutyan0814

2022/01/09 09:51

お返事ありがとうございます。 確かに、もう少し制作テーマを考慮してマルチスレッドを試してみればよかったです。 コンベアに流れ着いた材料を別の機械に流す作業をスレッド化するということですね!並列作業になっていますし、学べる点が多くありそうです。チャレンジしてます。 今は、少し考えてMachineクラスをスレッドクラスのサブクラスにし、Cubbyholeなど使って材料が流れ着いた/ついていないの状態をなんとかMachineインスタンス間で共有(接続)できないかなと試行錯誤しているところです。流れ着いた→色を変えて次に流す の認識部分を作ろうとしています。 多くのアドバイス本当にありがとうございました。

まだ回答がついていません

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

JavaFX

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

Java

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

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

例外処理

例外処理(Exception handling)とは、プログラム実行中に異常が発生した場合、通常フローから外れ、例外として別の処理を行うようにデザインされたプログラミング言語構造です。