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

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

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

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

Java

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

Q&A

解決済

5回答

777閲覧

javaFX でnodeの配列を作ったときに、それぞれのnodeからのActionを区別して処理したい

UserOfJava

総合スコア57

JavaFX

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

Java

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

0グッド

0クリップ

投稿2022/07/27 09:01

前提

JavaFXでButtonクラスの配列を作りました。それぞれのButtonをクリックしたときに、どのButtonからのEventか識別する方法がよくわからず、長々と識別するためのコードを書いています。

実現したいこと

Button配列のそれぞれの要素に対するEventHandlerが、もう少しスマートに書けないかと思っています。

自分で識別コードを書かないと、配列の範囲外の添え字になってしまいます。

該当のソースコード

JavaFx

1 2import javafx.application.Application; 3import javafx.event.ActionEvent; 4import javafx.event.EventHandler; 5import javafx.scene.Scene; 6import javafx.scene.control.Button; 7import javafx.scene.control.Label; 8import javafx.scene.layout.VBox; 9import javafx.stage.Stage; 10import javafx.geometry.Pos; 11 12public class HelloWorld extends Application { 13 static int i; 14 static int actionButton; 15 static final int numberOfButton = 2; 16 17 @Override 18 public void start(Stage primaryStage) { 19 Label lbl = new Label(); 20 Button[] btn = new Button[5]; 21 for(i=0; i<numberOfButton; i++){ 22 btn[i] = new Button(); 23 btn[i].setText(String.valueOf(i)); 24 btn[i].setOnAction(new EventHandler<ActionEvent>() { 25 @Override 26 public void handle(ActionEvent event) { 27 String souce = event.toString(); 28 actionButton = Integer.valueOf(souce.substring(souce.indexOf("button")+8,souce.length()-2)); 29 30 System.out.println(actionButton); 31 if(lbl.getText().equals("")){ 32 lbl.setText("Hello World"+"/"+actionButton); 33 }else{ 34 lbl.setText(""); 35 } 36 } 37 }); 38 } 39 40 41 VBox root = new VBox(20); 42 root.setAlignment(Pos.CENTER); 43 for (i=0; i< numberOfButton; i++){ 44 root.getChildren().add(btn[numberOfButton-i-1]); 45 } 46 root.getChildren().add(lbl); 47 48 Scene scene = new Scene(root, 300, 500); 49 50 primaryStage.setTitle("Hello World!"); 51 primaryStage.setScene(scene); 52 primaryStage.show(); 53 } 54 55 public static void main(String[] args) { 56 launch(args); 57 } 58} 59

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

OpenJX 18.0.1 JDK18.0.2

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

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

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

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

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

jimbe

2022/07/27 09:36 編集

souce ・・・ source でしょうか。 わざわざボタン毎にイベントハンドラを生成しているのですから、イベントハンドラ自体に値を渡して置けば良いだけでは。 そもそも toString の結果を解析するようなコードは、基本的にしてはいけないことです。 toString がどのような文字列を返す(べき)かは決まっていません。
UserOfJava

2022/07/27 10:44

回答ありがとうございます。 イベントハンドラ自体に値を渡して は、具体的にはどのようなコードになるのか、ご教示頂ければありがたいです。
guest

回答5

0

ハンドラをクラス化してコンストラクタで値を渡しておくというのも方法の一つと思います。つまり「 0 番のボタン」と「 "0" と表示するハンドラ」を結びつける感じ。

java

1 class ButtonHandler implements EventHandler<ActionEvent> { 2 private int actionButton; 3 private Label lbl; 4 ButtonHandler(int actionButton, Label lbl) { 5 this.actionButton = actionButton; 6 this.lbl = lbl; 7 } 8 @Override 9 public void handle(ActionEvent event) { 10 System.out.println(actionButton); 11 if(lbl.getText().equals("")) { 12 lbl.setText("Hello World" + "/" + actionButton); 13 } else { 14 lbl.setText(""); 15 } 16 } 17 }

(ハンドラの登録部分)

java

1 btn[i].setOnAction(new ButtonHandler(i, lbl));

また、ハンドラ内で振り分ることに拘るのであれば、 ActionEvent の getSource() というメソッドが押されたボタンを返します。

java

1 @Override 2 public void handle(ActionEvent event) { 3 Button source = (Button)event.getSource(); 4 int actionButton = Integer.parseInt(source.getText()); 5 6 System.out.println(actionButton); 7 if(lbl.getText().equals("")) { 8 lbl.setText("Hello World" + "/" + actionButton); 9 } else { 10 lbl.setText(""); 11 } 12 }

投稿2022/07/27 10:56

jimbe

総合スコア12512

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

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

UserOfJava

2022/07/27 12:12

早速、コードを例示して頂きありがとうございます。 やつてみます。
guest

0

イベントハンドラ自体に値を渡して

は、具体的にはどのようなコードになるのか、ご教示頂ければありがたいです。

は、こういう意味かと思ってました^^;

java

1import javafx.application.Application; 2import javafx.event.ActionEvent; 3import javafx.event.EventHandler; 4import javafx.geometry.Pos; 5import javafx.scene.Scene; 6import javafx.scene.control.Button; 7import javafx.scene.control.Label; 8import javafx.scene.layout.VBox; 9import javafx.stage.Stage; 10 11 12public class HelloWorld extends Application { 13 public static void main(String[] args) { launch(args); } 14 15 static final int numberOfButton = 2; 16 17 @Override public void start(Stage primaryStage) { 18 Label lbl = new Label(); 19 20 // 「区別する」というと単一ハンドラで動作を変えるようなイメージだが。。。 21// EventHandler<ActionEvent> handler = (e) -> { 22// if (lbl.getText().equals("")) { 23// Button b = (Button) e.getSource(); 24// lbl.setText("Hello World/" + b.getText()); 25// } else { 26// lbl.setText(""); 27// } 28// }; 29 30 Button[] btn = new Button[numberOfButton]; 31 for (int i = 0; i < btn.length; i++) { 32 btn[i] = new Button("" + i); 33// btn[i].setOnAction(handler); 34 35 final int ii = i; // ラムダには実質finalしか渡せないので一旦変数に受ける 36 btn[i].setOnAction(event -> { 37 if (lbl.getText().equals("")) { 38 lbl.setText("Hello World/" + ii); // iは参照できないがiiならok! 39 } else { 40 lbl.setText(""); 41 } 42 }); 43 } 44 45 VBox root = new VBox(20); 46 root.setAlignment(Pos.CENTER); 47 for (int i = btn.length - 1; 0 <= i; i--) { 48 root.getChildren().add(btn[i]); 49 } 50 51 root.getChildren().add(lbl); 52 53 primaryStage.setTitle("Hello World!"); 54 primaryStage.setScene(new Scene(root, 300, 500)); 55 primaryStage.show(); 56 } 57}

static int i;
たまにループの変数を外に出しているコードを見ますが、何の意味があるんでしょうか。

投稿2022/07/27 11:55

編集2023/07/30 12:18
TN8001

総合スコア9220

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

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

jimbe

2022/07/27 12:11

>>イベントハンドラ自体に値を渡して >こういう意味かと思ってました 最初それが一番簡単かと思ったのですが、コード内コメントのようなことを理解されているか分からなかったので普通に生成するようにしました。
UserOfJava

2022/07/27 12:27

TN8001さん、ありがとうごさいます。 int final ii = i; が肝ですね。ラムダ表記と。
TN8001

2022/07/27 13:11

> 最初それが一番簡単かと思ったのですが、コード内コメントのようなことを理解されているか分からなかったので普通に生成するようにしました。 なるほど。 「だけ」例が抜けているような気がしたので回答しましたが、確かにわかりにくいところですからね。 C#なんかはエラーが出ない分、かえって混乱する奴ですw
guest

0

この件に関し、回答を頂いた皆様に感謝しております。

その後、ネットを色々な形で検索して、私のコードとの関連で解説している記事があり、理解しました。
https://happynow.hateblo.jp/entry/20120512/1336826316

もっと早くに調べておけば良かったのですが、検索の語句がまずかったようです。

結局のところ、for文の i をそのまま参照せずに、いったん final int ii = i; で受けて、このiiでEventHandler のメソッドを書けばよいということのようです。 したがって、static i も使う必要がなくなりました。

皆様方のアドバイスのおかげで、Java の仕様の知らなかったことを勉強できました。
改めて、お礼申し上げます。

投稿2022/07/30 01:55

UserOfJava

総合スコア57

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

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

0

自己解決

jimbeさん、TN8001さん
時間を割いて、アドバイスしていただきありがとうございました。

なまけ者なので、自分のコードの最小限の修正で済むようにしました。
static int i;
はなんだとのお叱りで恐縮します。でも、for文の i を内部クラスから参照するには、この方法が楽です。したがって、これは外せません。

もとのコードとの違いは、
---java
btn[i].setOnAction(new EventHandler<ActionEvent>() {
final int ii = i;
@Override
public void handle(ActionEvent event) {

とfinal int ii =i; の一行をいれて、handle method では、 i の代わりに ii を用いることで、うまく行きそうです。

お示ししたのは検証用のプログラムで、開発中のものは長くなるので、エッセンスだけ検証しました。

ラムダ表記はらくなように見えますが、取り付けていません。すみません。古い人間なので。

JavaFXのコンパイラの問題ですかね。別にfinalを持ち出さなくても、コードとしてはそれぞれの配列要素に処理を for 文の i で定義しているのですけど、実際にeventが発生すると、なにやら、for 文の i を引きずって、最後のi +1 で実行しようとします。

OpenJX のjavadoc 読んでも、なんか薄いような気がして、この先、JavaFXはなくなるのではと言う予感もするぐらいです。

皆さん、面白くもない検証に協力して頂いて、本当に感謝しています。

投稿2022/07/28 02:10

UserOfJava

総合スコア57

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

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

jimbe

2022/07/28 03:43

> for文の i を内部クラスから参照するには、この方法が楽です。したがって、これは外せません。 これには賛同できません。 「for 文の i を引きずって、最後のi +1 で実行しようとします」がこの問題です。コンパイラ云々ではありません。
UserOfJava

2022/07/28 04:11

あまり分かってなくて言っていますので、申し訳ありません。
UserOfJava

2022/07/28 04:25

shiketaさん node にユーザー指定の色々を持たせる仕組みですね。有益なアドバイス、ありがとうございます。 handler1本で、すべてのeventを処理できそうに思えます。 貴重な時間を割いて、ありがとうございました。
guest

0

# 無用そうなループとか、問題を複雑にしそうなグローバル変数とか、突っ込みどころはいろいろありますが、それはさておき。

もう少しスマートに書けないかと思っています。

set/getUserData()を使ってみては?

java

1import javafx.application.Application; 2import javafx.event.ActionEvent; 3import javafx.event.EventHandler; 4import javafx.geometry.Pos; 5import javafx.scene.Scene; 6import javafx.scene.control.Button; 7import javafx.scene.control.Label; 8import javafx.scene.layout.VBox; 9import javafx.stage.Stage; 10 11public class HelloWorld 12 extends Application { 13 static final int numberOfButton = 2; 14 15 @Override 16 public void start(Stage primaryStage) { 17 final Label lbl = new Label(); 18 final Button[] btn = new Button[numberOfButton]; 19 20 final EventHandler<ActionEvent> handler = new EventHandler<ActionEvent>() { 21 @Override 22 public void handle(ActionEvent event) { 23 final int actionButton = (Integer) ((Button) event.getSource()).getUserData(); 24 25 System.out.println(actionButton); 26 if (lbl.getText().equals("")) { 27 lbl.setText("Hello World" + "/" + actionButton); 28 } else { 29 lbl.setText(""); 30 } 31 } 32 }; 33 34 final VBox root = new VBox(20); 35 root.setAlignment(Pos.CENTER); 36 37 for (int i = 0; i < numberOfButton; i++) { 38 final Button button = new Button(); 39 root.getChildren().add(button); 40 button.setText(String.valueOf(i)); 41 button.setUserData(i); 42 button.setOnAction(handler); 43 btn[i] = button; 44 } 45 46 root.getChildren().add(lbl); 47 48 final Scene scene = new Scene(root, 300, 500); 49 50 primaryStage.setTitle("Hello World!"); 51 primaryStage.setScene(scene); 52 primaryStage.show(); 53 } 54 55 public static void main(String[] args) { 56 launch(args); 57 } 58}

投稿2022/07/27 23:55

編集2022/07/27 23:57
shiketa

総合スコア3971

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問