I have created a detailed program in Java and I am now trying to create a UI for it with Java FX. In the demo below, I used Scene Builder for creating two circle shapes and two buttons. Scene Builder outputs an FXML file which is loaded into Java. The FXML file contains the JavaFX layout.
The problem I am having is that I want to save the names of all the circle shapes in an array, so that I can easily reference them later from the other Java program that I have written.
JavaFX won't let me store the names of the circle shapes in an array. So, I have to identify every shape one by one whenever I want to make changes to them. Here is the FXML file created with Scene Builder. The circle shapes are identified in the FXML with fx:id's nCircle_0_0 and nCircle_0_1:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.shape.Circle?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Button layoutX="402.0" layoutY="77.0" mnemonicParsing="false" onAction="#chColourClick" text="A0" />
<Button layoutX="402.0" layoutY="117.0" mnemonicParsing="false" onAction="#btnClick2" text="A1" />
<Circle fx:id="nCircle_0_0" fill="#ff741f" layoutX="249.0" layoutY="104.0" radius="18.0" stroke="BLACK" strokeType="INSIDE" />
<Circle fx:id="nCircle_0_1" fill="#ff741f" layoutX="306.0" layoutY="104.0" radius="18.0" stroke="BLACK" strokeType="INSIDE" />
</children>
</AnchorPane>
The Main.java file loads in the FXML:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 600, 400));
primaryStage.show();
// Controller startUp = new Controller();
}
public static void main(String[] args) {
launch(args);
}
}
and the Controller.java file contains the actions:
package sample;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
public class Controller {
@FXML
private Circle nCircle_0_0;
@FXML
private Circle nCircle_0_1;
public Circle [] theCircles = {nCircle_0_0, nCircle_0_1};
@FXML
public void chColourClick(ActionEvent event) {
String btText = ((Button)event.getSource()).getText();
System.out.println(btText);
blueCircle(nCircle_0_0);
}
public void blueCircle(Circle toChange){
toChange.setFill(Color.web("#266f9f"));
}
@FXML
public void btnClick2(MouseEvent event) {
changeColour(theCircles[1]);
}
public void changeColour(Circle chosenCircle){
chosenCircle.setFill(Color.web("#266f9f"));
}
}
If the above code is run, a window will open with two buttons A0 and A1. Clicking on the A0 button will turn the first circle blue. Clicking on the A1 button will cause an error message (I had hoped clicking the A1 button would turn the second circle blue).
The A0 button is linked to an action in Controller.java which calls a method blueCircle(nCircle_0_0); The variable name nCircle_0_0 declared at the top of the Controller.java file which corresponds to the fx:id is passed into the blueCircle method as a parameter, and it works fine.
On the A1 button, an action is triggered which calls the method changeColour(theCircles[1]); In this case the second item in an Array called theCircles is passed in as a parameter. This second item is nCircle_0_1, but JavaFX won't recognise this item as the object name for changing the colour. So instead I get a java.lang.IllegalArgumentException error.
From everything I've been reading so far, I can see that Java is seeing the values in the Array as null. But I don't see how to stop them being null as they seem to be created in the FXML file and not in the Controller.java file.
Is there some way I can store all of these reference names in an array? I need to reference them from elsewhere in my program using other arrays, and at the moment I can't see any way of doing it.
Update: I have made an additional edit to my code to illustrate the problem
In the following MouseEvent, If I print theCircles[0] to the console I get null. If I get the source of the button click and insert that into my theCircles array, then the full object reference is displayed after I print theCircles[0]:
@FXML
public void btnClick2(MouseEvent event) {
System.out.println(theCircles[0]);
Circle value = (Circle)event.getSource();
theCircles[0] = value;
System.out.println(theCircles[0]);
}
This outputs the following to the console:
null
Circle[id=nCircle_0_1, centerX=0.0, centerY=0.0, radius=20.0, fill=0x1e90ffff, stroke=0x000000ff, strokeWidth=4.0]
The first time it outputs theCircles[0] it comes out as null. Then if I use getSource to place the object into circleGrid at position [0] it outputs the full object to the console if I again print theCircles[0]. So at that point, the object and not the null value exists in theCircles[0]. I can then pass theCircles[0] as a parameter into other methods to change the properties of the circle shape in other ways. So, it is possible to put the full object reference into the array. But the only way I can do it is by clicking on the shape and using getSource.
Is there a way I can put all of the object references into my array when Controller.java loads, without having to click on them? At the moment if I set up a for loop to put the object names into the array when Controller.java loads, they just go in as null. I just cannot work this out, but there must be some way of doing it.
User contributions licensed under CC BY-SA 3.0