質問するログイン新規登録
JavaFX

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

Java

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

FXML

FXMLは、JavaFXに用意されているXMLベースのGUI記述言語です

Q&A

解決済

2回答

323閲覧

【javafxに関する疑問】FXML内において、オブジェクトのコントロール分割は可能か?

Fitz

総合スコア4

JavaFX

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

Java

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

FXML

FXMLは、JavaFXに用意されているXMLベースのGUI記述言語です

1グッド

0クリップ

投稿2025/10/08 13:23

1

0

実現したいこと

javafxにて、画面内の短形(以降操作キャラと呼びます)を動かし、中央にある枠に触れた時と、枠の内部に入った時にテキストが変化するコードを作成しました。
作成後、「オブジェクトコントロールを個別に設定出来たら、操作キャラは操作キャラのクラスに処理を格納でき、現在のコントロールクラスの可読性が上がるのでは?」と思いました。
そこで質問です。FXMLにおいて、コントロール設定されたFXMLの、特定のオブジェクトのコントロールを他クラスに譲渡するというのは可能なのでしょうか?

発生している問題・分からないこと

実現可能か分からない
・FXMLのオブジェクト(今回の場合は短形を)のコントロールを他のクラスに譲渡できるのか?
→Screen2に記述している、「private Rectangle shape1;//操作キャラ」に関連する移動制御の処理は個別に用意したり、中央枠等の操作キャラ以外を種類ごとに分けて機能を拡張していきたい。

該当のソースコード

java

1package application; 2 3import java.net.URL; 4import java.util.ResourceBundle; 5 6import javafx.animation.AnimationTimer; 7import javafx.beans.binding.BooleanBinding; 8import javafx.beans.property.BooleanProperty; 9import javafx.beans.property.SimpleBooleanProperty; 10import javafx.fxml.FXML; 11import javafx.fxml.Initializable; 12import javafx.geometry.Bounds; 13import javafx.scene.input.KeyCode; 14import javafx.scene.layout.AnchorPane; 15import javafx.scene.paint.Color; 16import javafx.scene.shape.Rectangle; 17import javafx.scene.text.Text; 18 19public class Screen2 implements Initializable{ 20 21 @FXML 22 private AnchorPane screen2;//画面 23 24 @FXML 25 private Rectangle boundary1;//境界(図形) 26 private Bounds boundboundary1;//境界の境界線 27 28 @FXML 29 private Rectangle shape1;//操作キャラ 30 private Bounds boundshape1;//操作キャラ境界線 31 32 boolean tutch = false; 33 boolean included= false; 34 35 36 @FXML 37 private Text text; 38 39 //キー押下変数 40 private BooleanProperty wPressed = new SimpleBooleanProperty(); 41 private BooleanProperty aPressed = new SimpleBooleanProperty(); 42 private BooleanProperty sPressed = new SimpleBooleanProperty(); 43 private BooleanProperty dPressed = new SimpleBooleanProperty(); 44 private BooleanProperty shiftPressed = new SimpleBooleanProperty(); 45 46 private BooleanBinding keyPressed = wPressed.or(aPressed).or(sPressed).or(dPressed).or(shiftPressed); 47 48 49 50 //移動速度 51 private int movementVariable = 2; 52 53 //スピードアップ 54 private int speedUp = 3; 55 56 //短形の高さ: 57 private double shape1Height; 58 59 AnimationTimer timer = new AnimationTimer() { 60 @Override 61 public void handle(long timestamp) { 62 63 boundshape1 = shape1.getBoundsInParent(); 64 boundboundary1 = boundary1.getBoundsInParent(); 65 contains(boundshape1,boundboundary1); 66 67 if(wPressed.get()) { 68 if(shiftPressed.get()) { 69 shape1.setLayoutY(shape1.getLayoutY() - (movementVariable + speedUp)); 70 71 } 72 shape1.setLayoutY(shape1.getLayoutY() - movementVariable); 73 74 } 75 76 if(sPressed.get()){ 77 if(shiftPressed.get()) { 78 shape1.setLayoutY(shape1.getLayoutY() + (movementVariable + speedUp)); 79 } 80 shape1.setLayoutY(shape1.getLayoutY() + movementVariable); 81 } 82 83 if(aPressed.get()){ 84 if(shiftPressed.get()) { 85 shape1.setLayoutX(shape1.getLayoutX() - (movementVariable + speedUp)); 86 } 87 shape1.setLayoutX(shape1.getLayoutX() - movementVariable); 88 } 89 90 if(dPressed.get()){ 91 if(shiftPressed.get()) { 92 shape1.setLayoutX(shape1.getLayoutX() + (movementVariable + speedUp)); 93 } 94 shape1.setLayoutX(shape1.getLayoutX() + movementVariable); 95 } 96 97 if(tutch == true) { 98 text.setText("当たっています。"); 99 text.setFill(Color.RED); 100 } 101 if(included == true){ 102 text.setText("内部に入っています。"); 103 text.setFill(Color.RED); 104 } 105 if(tutch != true && included != true) { 106 text.setText("何にも接触していません。"); 107 } 108 109 110 checkBorder(); 111 112 } 113 }; 114 115 116 @Override 117 public void initialize(URL url, ResourceBundle resourceBundle) { 118 //shape1X座標 119 shape1Height = shape1.getHeight(); 120 //shape1四隅 121 boundshape1 = shape1.getBoundsInParent(); 122 boundboundary1 = boundary1.getBoundsInParent(); 123 movementSetup(); 124 125 keyPressed.addListener(((observableValue, aBoolean, t1) -> { 126 if(!aBoolean){ 127 timer.start(); 128 } else { 129 timer.stop(); 130 } 131 })); 132 } 133 134 public void movementSetup(){ 135 screen2.setOnKeyPressed(e -> { 136 if(e.getCode() == KeyCode.W) { 137 wPressed.set(true); 138 } 139 140 if(e.getCode() == KeyCode.A) { 141 aPressed.set(true); 142 } 143 144 if(e.getCode() == KeyCode.S) { 145 sPressed.set(true); 146 } 147 148 if(e.getCode() == KeyCode.D) { 149 dPressed.set(true); 150 } 151 152 if(e.getCode() == KeyCode.SHIFT) { 153 shiftPressed.set(true); 154 } 155 156 }); 157 158 screen2.setOnKeyReleased(e ->{ 159 if(e.getCode() == KeyCode.W) { 160 wPressed.set(false); 161 } 162 163 if(e.getCode() == KeyCode.A) { 164 aPressed.set(false); 165 } 166 167 if(e.getCode() == KeyCode.S) { 168 sPressed.set(false); 169 } 170 171 if(e.getCode() == KeyCode.D) { 172 dPressed.set(false); 173 } 174 if(e.getCode() == KeyCode.SHIFT) { 175 shiftPressed.set(false); 176 } 177 }); 178 } 179 180 //当たり判定左がチェック対象、右があたる可能性のあるオブジェクト 181 public void contains(Bounds smallShape, Bounds largeShape) { 182 183 //接触判定 184 if ( smallShape.intersects(largeShape)) { 185 tutch = true; 186 }else { 187 tutch = false; 188 } 189 190 //内部判定 191 if(largeShape.getMinX() < smallShape.getMinX() && largeShape.getMinY() < smallShape.getMinY() && 192 largeShape.getMaxX() > smallShape.getMaxX() && largeShape.getMaxY() > smallShape.getMaxY()){ 193 included = true; 194 } 195 else { 196 included = false; 197 } 198 199 200 } 201 202 public void checkBorder() { 203 //上からwsad変数 204 double topbound = 0; 205 double bottombound = screen2.getHeight() - shape1Height; 206 double leftbound = 0; 207 double lightbound = screen2.getWidth() - shape1Height; 208 209 //w移動制御 210 if(shape1.getLayoutY() <= topbound) { 211 shape1.setLayoutY(topbound); 212 } 213 //s移動制御 214 if(shape1.getLayoutY() >= bottombound) { 215 shape1.setLayoutY(bottombound); 216 } 217 //a移動制御 218 if(shape1.getLayoutX() <= leftbound) { 219 shape1.setLayoutX(leftbound); 220 } 221 //d移動制御 222 if(shape1.getLayoutX() >= lightbound) { 223 shape1.setLayoutY(lightbound); 224 } 225 226 } 227 228 229}

FXML

1<?xml version="1.0" encoding="UTF-8"?> 2 3<?import javafx.scene.layout.AnchorPane?> 4<?import javafx.scene.shape.Rectangle?> 5<?import javafx.scene.text.Text?> 6 7<AnchorPane fx:id="screen2" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="1000.0" xmlns="http://javafx.com/javafx/24.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.Screen2"> 8 <children> 9 <Rectangle fx:id="shape1" arcHeight="5.0" arcWidth="5.0" fill="#ff8c1f" height="100.0" layoutX="450.0" layoutY="400.0" stroke="BLACK" strokeType="INSIDE" width="100.0" /> 10 <Rectangle fx:id="boundary1" arcHeight="5.0" arcWidth="5.0" fill="TRANSPARENT" height="200.0" layoutX="400.0" layoutY="150.0" stroke="BLACK" strokeType="INSIDE" width="200.0" AnchorPane.bottomAnchor="150.0" AnchorPane.leftAnchor="400.0" AnchorPane.rightAnchor="400.0" AnchorPane.topAnchor="150.0" /> 11 <Text fx:id="text" layoutX="417.0" layoutY="63.0" strokeType="OUTSIDE" strokeWidth="0.0" wrappingWidth="166.80340576171875" /> 12 </children> 13</AnchorPane> 14

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

試してみたこと。
・操作キャラを別のFXMLに作成。Screen2.FXMLで呼び出し(include)、Screen2クラスの操作キャラの初期値設定箇所に割り込ませてみた。
→対象の短形でNullpoint発生

補足

特になし

TN8001👍を押しています

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

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

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

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

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

guest

回答2

0

「ランダムに動く円」追加版(大して変わらないが1万時に収まらなかったので^^;

xml:screen2.fxml

1<?xml version="1.0" encoding="UTF-8"?> 2 3<?import application.Shape1?> 4<?import javafx.scene.layout.AnchorPane?> 5<?import javafx.scene.shape.Rectangle?> 6<?import javafx.scene.text.Text?> 7<AnchorPane fx:id="screen2" prefHeight="500.0" prefWidth="1000.0" xmlns:fx="http://javafx.com/fxml" 8 fx:controller="application.Screen2Controller"> 9 <children> 10 <Shape1 fx:id="shape1" arcHeight="5.0" arcWidth="5.0" fill="#ff8c1f" height="100.0" layoutX="450.0" 11 layoutY="400.0" 12 focusTraversable="true" stroke="BLACK" strokeType="INSIDE" width="100.0"/> 13 <!-- <Shape1 fill="RED" layoutX="150.0" layoutY="150.0" width="100.0" height="100.0" focusTraversable="true"/> --> 14 15 <Rectangle fx:id="boundary1" arcHeight="5.0" arcWidth="5.0" fill="TRANSPARENT" height="200.0" layoutX="400.0" 16 layoutY="150.0" stroke="BLACK" strokeType="INSIDE" width="200.0"/> 17 <Text fx:id="text" layoutX="417.0" layoutY="63.0" text="何にも接触していません。"/> 18 </children> 19</AnchorPane>

java:Screen2Controller.java

1package application; 2 3import javafx.fxml.FXML; 4import javafx.fxml.Initializable; 5import javafx.scene.layout.AnchorPane; 6import javafx.scene.shape.Rectangle; 7import javafx.scene.text.Text; 8 9import java.net.URL; 10import java.util.ArrayList; 11import java.util.ResourceBundle; 12 13public class Screen2Controller implements Initializable { 14 @FXML private AnchorPane screen2; 15 @FXML private Rectangle boundary1; 16 @FXML private Rectangle shape1; 17 @FXML private Text text; 18 19 @Override public void initialize(URL url, ResourceBundle resourceBundle) { 20 shape1.layoutXProperty().addListener((_, _, _) -> checkShape1()); 21 shape1.layoutYProperty().addListener((_, _, _) -> checkShape1()); 22 23 screen2.setOnKeyPressed(e -> { 24 switch (e.getCode()) { 25 case E -> screen2.getChildren().add(new RandomCircle()); 26 case SPACE -> { 27 shape1.setLayoutX(450); 28 shape1.setLayoutY(400); 29 30 var circles = new ArrayList<RandomCircle>(); 31 for (var child : screen2.getChildren()) { 32 if (child instanceof RandomCircle circle) { 33 circle.stop(); 34 circles.add(circle); 35 } 36 } 37 screen2.getChildren().removeAll(circles); 38 } 39 } 40 }); 41 } 42 43 private void checkShape1() { 44 var boundshape1 = shape1.getBoundsInParent(); 45 var boundboundary1 = boundary1.getBoundsInParent(); 46 var included = boundboundary1.contains(boundshape1); 47 var touch = boundboundary1.intersects(boundshape1); 48 49 if (included) text.setText("内部に入っています。"); 50 else if (touch) text.setText("当たっています。"); 51 else text.setText("何にも接触していません。"); 52 53 var top = 0d; 54 var bottom = screen2.getHeight() - shape1.getHeight(); 55 var left = 0d; 56 var right = screen2.getWidth() - shape1.getWidth(); 57 58 if (shape1.getLayoutY() <= top) shape1.setLayoutY(top); 59 if (shape1.getLayoutY() >= bottom) shape1.setLayoutY(bottom); 60 if (shape1.getLayoutX() <= left) shape1.setLayoutX(left); 61 if (shape1.getLayoutX() >= right) shape1.setLayoutX(right); 62 } 63}

 

java:Shape1.java

1package application; 2 3import javafx.animation.AnimationTimer; 4import javafx.beans.binding.BooleanBinding; 5import javafx.beans.property.BooleanProperty; 6import javafx.beans.property.SimpleBooleanProperty; 7import javafx.scene.shape.Rectangle; 8 9public class Shape1 extends Rectangle { 10 private final BooleanProperty wPressed = new SimpleBooleanProperty(); 11 private final BooleanProperty aPressed = new SimpleBooleanProperty(); 12 private final BooleanProperty sPressed = new SimpleBooleanProperty(); 13 private final BooleanProperty dPressed = new SimpleBooleanProperty(); 14 private final BooleanProperty shiftPressed = new SimpleBooleanProperty(); 15 private final BooleanBinding keyPressed = wPressed.or(aPressed).or(sPressed).or(dPressed).or(shiftPressed); 16 17 private final AnimationTimer timer = new AnimationTimer() { 18 @Override public void handle(long timestamp) { 19 var offset = shiftPressed.get() ? 5 : 2; 20 21 if (wPressed.get()) setLayoutY(getLayoutY() - offset); 22 if (sPressed.get()) setLayoutY(getLayoutY() + offset); 23 if (aPressed.get()) setLayoutX(getLayoutX() - offset); 24 if (dPressed.get()) setLayoutX(getLayoutX() + offset); 25 } 26 }; 27 28 public Shape1() { 29 setOnKeyPressed(e -> { 30 switch (e.getCode()) { 31 case W -> wPressed.set(true); 32 case A -> aPressed.set(true); 33 case S -> sPressed.set(true); 34 case D -> dPressed.set(true); 35 case SHIFT -> shiftPressed.set(true); 36 } 37 }); 38 39 setOnKeyReleased(e -> { 40 switch (e.getCode()) { 41 case W -> wPressed.set(false); 42 case A -> aPressed.set(false); 43 case S -> sPressed.set(false); 44 case D -> dPressed.set(false); 45 case SHIFT -> shiftPressed.set(false); 46 } 47 }); 48 49 keyPressed.addListener((_, aBoolean, _) -> { 50 if (!aBoolean) timer.start(); 51 else timer.stop(); 52 }); 53 } 54}

 

java:RandomCircle.java

1package application; 2 3import javafx.animation.AnimationTimer; 4import javafx.scene.paint.Color; 5import javafx.scene.shape.Ellipse; 6 7public class RandomCircle extends Ellipse { 8 private final AnimationTimer timer = new AnimationTimer() { 9 @Override public void handle(long timestamp) { 10 setCenterX(getCenterX() + Math.random() * 10 - 5); 11 setCenterY(getCenterY() + Math.random() * 10 - 5); 12 } 13 }; 14 15 public RandomCircle() { 16 setRadiusX(20); 17 setRadiusY(20); 18 setCenterX(Math.random() * 100 + 100); 19 setCenterY(Math.random() * 100 + 100); 20 setFill(Color.color(Math.random(), Math.random(), Math.random())); 21 timer.start(); 22 } 23 public void stop() { timer.stop(); } 24}

 

java:HelloApplication.java

1package application; 2 3import javafx.application.Application; 4import javafx.fxml.FXMLLoader; 5import javafx.scene.Scene; 6import javafx.stage.Stage; 7 8import java.io.IOException; 9 10public class HelloApplication extends Application { 11 public static void main(String[] args) { launch(); } 12 13 @Override public void start(Stage stage) throws IOException { 14 var fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("screen2.fxml")); 15 stage.setScene(new Scene(fxmlLoader.load())); 16 stage.show(); 17 } 18}

アプリ動画

投稿2025/10/09 22:02

TN8001

総合スコア10211

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

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

0

ベストアンサー

・FXMLのオブジェクト(今回の場合は短形を)のコントロールを他のクラスに譲渡できるのか?

fx:includeでできました^^
Scene Builder で他の FXML ファイルを埋め込む #Java - Qiita

ただ何をどう分けるのかは悩ましいですね...

  • 移動自体はShape1Controllerに任せた
  • 当たり判定等はScreen2Controller側で

xml:screen2.fxml

1<?xml version="1.0" encoding="UTF-8"?> 2 3<?import application.Shape1?> 4<?import javafx.scene.layout.AnchorPane?> 5<?import javafx.scene.shape.Rectangle?> 6<?import javafx.scene.text.Text?> 7<AnchorPane fx:id="screen2" 8 prefHeight="500.0" prefWidth="1000.0" 9 xmlns:fx="http://javafx.com/fxml" fx:controller="application.Screen2Controller"> 10 <children> 11 <!-- <fx:include fx:id="shape1" source="shape1.fxml"/> --> 12 <!-- ↑の代わりに継承クラスを使った場合 --> 13 <Shape1 fx:id="shape1" arcHeight="5.0" arcWidth="5.0" fill="#ff8c1f" height="100.0" layoutX="450.0" 14 layoutY="400.0" 15 focusTraversable="true" stroke="BLACK" strokeType="INSIDE" width="100.0"/> 16 17 <Rectangle fx:id="boundary1" arcHeight="5.0" arcWidth="5.0" fill="TRANSPARENT" height="200.0" layoutX="400.0" 18 layoutY="150.0" stroke="BLACK" strokeType="INSIDE" width="200.0"/> 19 <Text fx:id="text" layoutX="417.0" layoutY="63.0" text="何にも接触していません。"/> 20 </children> 21</AnchorPane>

java:Screen2Controller.java

1package application; 2 3import javafx.fxml.FXML; 4import javafx.fxml.Initializable; 5import javafx.scene.input.KeyCode; 6import javafx.scene.layout.AnchorPane; 7import javafx.scene.shape.Rectangle; 8import javafx.scene.text.Text; 9 10import java.net.URL; 11import java.util.ResourceBundle; 12 13public class Screen2Controller implements Initializable { 14 @FXML private AnchorPane screen2; 15 @FXML private Rectangle boundary1; 16 @FXML private Rectangle shape1; 17 @FXML private Text text; 18// @FXML private Shape1Controller shape1Controller; // コントローラも取れる 19 20 @Override public void initialize(URL url, ResourceBundle resourceBundle) { 21 shape1.layoutXProperty().addListener((_, _, _) -> checkShape1()); 22 shape1.layoutYProperty().addListener((_, _, _) -> checkShape1()); 23 24 screen2.setOnKeyPressed(e -> { 25 if (e.getCode() == KeyCode.SPACE) { 26 shape1.setLayoutX(450); 27 shape1.setLayoutY(400); 28 } 29 }); 30 } 31 32 private void checkShape1() { 33 var boundshape1 = shape1.getBoundsInParent(); 34 var boundboundary1 = boundary1.getBoundsInParent(); 35 var included = boundboundary1.contains(boundshape1); 36 var touch = boundboundary1.intersects(boundshape1); 37 38 if (included) text.setText("内部に入っています。"); 39 else if (touch) text.setText("当たっています。"); 40 else text.setText("何にも接触していません。"); 41 42 var top = 0d; 43 var bottom = screen2.getHeight() - shape1.getHeight(); 44 var left = 0d; 45 var right = screen2.getWidth() - shape1.getWidth(); 46 47 if (shape1.getLayoutY() <= top) shape1.setLayoutY(top); 48 if (shape1.getLayoutY() >= bottom) shape1.setLayoutY(bottom); 49 if (shape1.getLayoutX() <= left) shape1.setLayoutX(left); 50 if (shape1.getLayoutX() >= right) shape1.setLayoutX(right); 51 } 52}

 

xml:shape1.fxml

1<?xml version="1.0" encoding="UTF-8"?> 2 3<?import javafx.scene.shape.Rectangle?> 4<Rectangle fx:id="shape1" arcHeight="5.0" arcWidth="5.0" fill="#ff8c1f" height="100.0" layoutX="450.0" layoutY="400.0" 5 focusTraversable="true" stroke="BLACK" strokeType="INSIDE" width="100.0" xmlns:fx="http://javafx.com/fxml" 6 fx:controller="application.Shape1Controller"/>

java:Shape1Controller.java

1package application; 2 3import javafx.animation.AnimationTimer; 4import javafx.beans.binding.BooleanBinding; 5import javafx.beans.property.BooleanProperty; 6import javafx.beans.property.SimpleBooleanProperty; 7import javafx.fxml.FXML; 8import javafx.fxml.Initializable; 9import javafx.scene.shape.Rectangle; 10 11import java.net.URL; 12import java.util.ResourceBundle; 13 14public class Shape1Controller implements Initializable { 15 @FXML private Rectangle shape1; 16 17 private final BooleanProperty wPressed = new SimpleBooleanProperty(); 18 private final BooleanProperty aPressed = new SimpleBooleanProperty(); 19 private final BooleanProperty sPressed = new SimpleBooleanProperty(); 20 private final BooleanProperty dPressed = new SimpleBooleanProperty(); 21 private final BooleanProperty shiftPressed = new SimpleBooleanProperty(); 22 private final BooleanBinding keyPressed = wPressed.or(aPressed).or(sPressed).or(dPressed).or(shiftPressed); 23 24 private final AnimationTimer timer = new AnimationTimer() { 25 @Override public void handle(long timestamp) { 26 var offset = shiftPressed.get() ? 5 : 2; 27 28 if (wPressed.get()) shape1.setLayoutY(shape1.getLayoutY() - offset); 29 if (sPressed.get()) shape1.setLayoutY(shape1.getLayoutY() + offset); 30 if (aPressed.get()) shape1.setLayoutX(shape1.getLayoutX() - offset); 31 if (dPressed.get()) shape1.setLayoutX(shape1.getLayoutX() + offset); 32 } 33 }; 34 35 @Override public void initialize(URL url, ResourceBundle resourceBundle) { 36 shape1.setOnKeyPressed(e -> { 37 switch (e.getCode()) { 38 case W -> wPressed.set(true); 39 case A -> aPressed.set(true); 40 case S -> sPressed.set(true); 41 case D -> dPressed.set(true); 42 case SHIFT -> shiftPressed.set(true); 43 } 44 }); 45 46 shape1.setOnKeyReleased(e -> { 47 switch (e.getCode()) { 48 case W -> wPressed.set(false); 49 case A -> aPressed.set(false); 50 case S -> sPressed.set(false); 51 case D -> dPressed.set(false); 52 case SHIFT -> shiftPressed.set(false); 53 } 54 }); 55 56 keyPressed.addListener((_, aBoolean, _) -> { 57 if (!aBoolean) timer.start(); 58 else timer.stop(); 59 }); 60 } 61}

 

java:Shape1.java

1package application; 2 3import javafx.animation.AnimationTimer; 4import javafx.beans.binding.BooleanBinding; 5import javafx.beans.property.BooleanProperty; 6import javafx.beans.property.SimpleBooleanProperty; 7import javafx.scene.shape.Rectangle; 8 9public class Shape1 extends Rectangle { 10 private final BooleanProperty wPressed = new SimpleBooleanProperty(); 11 private final BooleanProperty aPressed = new SimpleBooleanProperty(); 12 private final BooleanProperty sPressed = new SimpleBooleanProperty(); 13 private final BooleanProperty dPressed = new SimpleBooleanProperty(); 14 private final BooleanProperty shiftPressed = new SimpleBooleanProperty(); 15 private final BooleanBinding keyPressed = wPressed.or(aPressed).or(sPressed).or(dPressed).or(shiftPressed); 16 17 private final AnimationTimer timer = new AnimationTimer() { 18 @Override public void handle(long timestamp) { 19 var offset = shiftPressed.get() ? 5 : 2; 20 21 if (wPressed.get()) setLayoutY(getLayoutY() - offset); 22 if (sPressed.get()) setLayoutY(getLayoutY() + offset); 23 if (aPressed.get()) setLayoutX(getLayoutX() - offset); 24 if (dPressed.get()) setLayoutX(getLayoutX() + offset); 25 } 26 }; 27 28 public Shape1() { 29 setOnKeyPressed(e -> { 30 switch (e.getCode()) { 31 case W -> wPressed.set(true); 32 case A -> aPressed.set(true); 33 case S -> sPressed.set(true); 34 case D -> dPressed.set(true); 35 case SHIFT -> shiftPressed.set(true); 36 } 37 }); 38 39 setOnKeyReleased(e -> { 40 switch (e.getCode()) { 41 case W -> wPressed.set(false); 42 case A -> aPressed.set(false); 43 case S -> sPressed.set(false); 44 case D -> dPressed.set(false); 45 case SHIFT -> shiftPressed.set(false); 46 } 47 }); 48 49 keyPressed.addListener((_, aBoolean, _) -> { 50 if (!aBoolean) timer.start(); 51 else timer.stop(); 52 }); 53 } 54}

 

java:HelloApplication.java

1package application; 2 3import javafx.application.Application; 4import javafx.fxml.FXMLLoader; 5import javafx.scene.Scene; 6import javafx.stage.Stage; 7 8import java.io.IOException; 9 10public class HelloApplication extends Application { 11 public static void main(String[] args) { launch(); } 12 13 @Override public void start(Stage stage) throws IOException { 14 var fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("screen2.fxml")); 15 stage.setScene(new Scene(fxmlLoader.load())); 16 stage.show(); 17 } 18}

アプリ動画

投稿2025/10/08 21:56

編集2025/10/09 21:58
TN8001

総合スコア10211

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

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

TN8001

2025/10/08 21:56

Rectangleを継承したクラスを作ったほうがシンプルな気もする^^;
Fitz

2025/10/09 02:39 編集

回答いただきありがとうございます。いくつか質問させてください。 自身のやり方でNULLが発生した原因 →短形の初期化ができていなかったのでNULLが発生していたと認識していますが、合っているでしょうか? コードについて ①Screen2Controller.java16行目 @FXML private Rectangle shape1;でScreen2Controller側でshape1を取得できているのは、FXMLでIDを記載したからでしょうか? ②Screen2Controller.java20行目 shape1.layoutXProperty().addListener((_, _, _) -> checkShape1()); →座標の変化を上記のコードで検知、addListener((_, _, _) でcheckShape1()を起動といった動きになるのでしょうか? ➂Shape1Controller.java:25行目 var offset = shiftPressed.get() ? 5 : 2;について、shiftキーでスピードが上がる記述をしているように見えますが、このような記述方法を始めてみました。どういった記述方法なのでしょうか? ➃Rectangleを継承したクラスを作ったほうがシンプル →「shape1自体FXMLで作成せず、継承クラスで作成、Screen2Controllerに値を渡す」といった意味でしょうか?
TN8001

2025/10/09 05:47 編集

> →短形の初期化ができていなかったのでNULLが発生していたと認識していますが、合っているでしょうか? どうやったかが分からないので何とも言えませんが、fx:idを書き忘れたとかタイポとかでしょうかね? > @FXML private Rectangle shape1;でScreen2Controller側でshape1を取得できているのは、FXMLでIDを記載したからでしょうか? はい。 「fx:id="shape1"」と型・名前ともにあっていれば取得できるはずです。 > →座標の変化を上記のコードで検知、addListener((_, _, _) でcheckShape1()を起動といった動きになるのでしょうか? そうです。 「Shape1Controllerで当たり判定までするのは違うかな?」と思ったんでこのようにしました。 場合によってはController同士で変更しあって、無限ループしたりするかもしれませんw > var offset = shiftPressed.get() ? 5 : 2;について、shiftキーでスピードが上がる記述をしているように見えますが、このような記述方法を始めてみました。どういった記述方法なのでしょうか? 「三項演算子」です。↓と同じ意味です^^ int offset; if (shiftPressed.get()) offset = 5; else offset = 2; [java 三項演算子 - Google 検索](https://www.google.com/search?q=java+%E4%B8%89%E9%A0%85%E6%BC%94%E7%AE%97%E5%AD%90) > →「shape1自体FXMLで作成せず、継承クラスで作成、Screen2Controllerに値を渡す」といった意味でしょうか? Shape1Controllerに書いたコードを「public class Shape1 extends Rectangle」に移せば、shape1.fxmlがいらなくなります。 ただ実際はもっと凝った内容なんですかね?だとしたら今の構成のほうがいいんかな??
Fitz

2025/10/09 14:02

ベスト選択後に申し訳ありません。 「Shape1Controllerに書いたコードを「public class Shape1 extends Rectangle」に移せば、shape1.fxmlがいらなくなります。」 とのことですが、コードのイメージがつかめておりません。 Rectangleを継承→@FXML shape1とshape1.fxmlを削除→コンストラクタでRectangle(x,y,w,h)を呼び出し→Screen2Controllerで図形を作成→画面に表示 という流れでしょうか? また、表示のために再度stageとsceneの取得が必要ということでしょうか?
TN8001

2025/10/09 14:28

> ベスト選択後に申し訳ありません。 回答に関する疑問はいつでもだれでもいいですよ^^ > とのことですが、コードのイメージがつかめておりません。 回答を修正しました(Shape1.javaを追加・screen2.fxmlを変更) 伝わりましたでしょうか。
Fitz

2025/10/09 16:40

追記いただきありがとうございます。 <?import application.Shape1?>でコンポーネントの紐づけを行い、動かすことができました。 この記述の重要箇所は、ラベルをRectangleから継承したShape1に変更することでしょうか? Rectangle要素+移動要素を持ったShape1にすることで、クラスから直接短形を動かすことができるという認識です。 また、Shape1クラスのAnimationTimer についてですが、こちらは疑問が2つあります。 ①「Shape1.this.setLayoutY(Shape1.this.getLayoutY() - offset)」といったような記述になるのは、自クラス(継承したRectangleクラス)のメソッドを呼び出したいからでしょうか? ②AnimationTimer ですが、今後、他のクラスで別途定義した場合でも、匿名クラスで作成していれば問題なく動作するのでしょうか?例えば、ランダムに動く別の短形を動かす場合等々。 リンク先の資料見た感じその場で定義・インスタンス化しているので、他クラスで再びAnimationTimerを匿名クラスで作成しても別インスタンス扱いで動作できるのかな?と思いました。
TN8001

2025/10/09 22:02

> <?import application.Shape1?>でコンポーネントの紐づけを行い、動かすことができました。 すいません。追記忘れました^^; > この記述の重要箇所は、ラベルをRectangleから継承したShape1に変更することでしょうか? 「ラベル」というのは<Rectangleとかのことですか?(HTMLで言うところのタグ、XMLだと要素) 「重要」というかShape1をどこにも使わなかったら意味がないので^^; > Rectangle要素+移動要素を持ったShape1にすることで、クラスから直接短形を動かすことができるという認識です。 まあそうですね。 でも例えば「円も動かしたくなったらどうすんの?ほとんど同じなclass Shape2 extends Ellipseクラスも作りますか?」みたいなことは思います(「よろしくないよね」という意味で) 回答コードは現状出ている条件で、(わたしが考える)一番シンプルというか素直な実装というだけで、ベストかどうかはわかりません。 十人十色とまでは言いませんが、色々なアプローチが考えられます。 > ①「Shape1.this.setLayoutY(Shape1.this.getLayoutY() - offset)」といったような記述になるのは、自クラス(継承したRectangleクラス)のメソッドを呼び出したいからでしょうか? すいません。ここは「setLayoutY(getLayoutY() - offset)」でよかったです。 「Shape1.this.」も冗長なだけで間違いではないです(「this.setLayoutY(」とは書けません) > ②AnimationTimer ですが、今後、他のクラスで別途定義した場合でも、匿名クラスで作成していれば問題なく動作するのでしょうか?例えば、ランダムに動く別の短形を動かす場合等々。 例えば↓のようなのを追加してみてください(<Shape1 fx:id="shape1"は残したまま) <Shape1 fill="RED" layoutX="150.0" layoutY="150.0" width="100.0" height="100.0" focusTraversable="true"/> [Tab]キーを押すとキーボードフォーカスが移動し、もう一方の四角が動くはずです(当たり判定はオレンジしかチェックしていないので赤は当然判定なし) 1000個とかあるとどうなるかわかりませんが、数十個程度なら大丈夫じゃないでしょうか(問題が出たらその時考えましょう) 「ランダムに動く円」を追加するように別回答しました(全然面白くないw
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.29%

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

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

質問する

関連した質問