Issue
I understand that for each time I load a nested fxml and controller that I can use that controller to manipulate the nested fxml. For example I can make every other row purple, but what I don't understand is how, after everything is loaded, can I target something specific to manipulate.
This is the most bare bones minimal replicate-able example I can make, anything reduced from this doesn't fit the criteria of a nested fxml and a child. What I want to do here is take the first score, with the text "Score0" and change it to "10" when the 10 button is pushed. I have a feeling I'm close, the score box should be score[0]. It should also be nested in row[0], but I can't seem to get the scoreEntry method to find the box to change it.
Main.java:
public class Main extends Application {
@Override
public void start(Stage stage) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(Main.class.getResource("view1.fxml"));
Scene scene = new Scene(fxmlLoader.load(), 400, 300);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
view1.fxml:
<AnchorPane prefHeight="300.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.nested.Ctrl1">
<children>
<VBox fx:id="rowHolder" prefHeight="260.0" prefWidth="400.0" />
<Button mnemonicParsing="false" onAction="#scoreEntry" prefHeight="40.0" prefWidth="40.0" text="10" AnchorPane.leftAnchor="70.0" AnchorPane.topAnchor="260.0" />
<Button mnemonicParsing="false" onAction="#scoreEntry" prefHeight="40.0" prefWidth="40.0" text="0" AnchorPane.topAnchor="260.0" />
</children>
</AnchorPane>
Ctrl1.java:
public class Ctrl1 {
@FXML
private VBox rowHolder;
@FXML
void initialize() {
addRows();
}
public void addRows() {
int rounds = 2;
HBox row[];
row = new HBox[rounds];
String ctrlArray[];
ctrlArray = new String[rounds];
for (int i = 0; i < row.length; i++) {
row[i] = new HBox();
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/nested/view2.fxml"));
row[i] = loader.load();
rowHolder.getChildren().add(row[i]);
Ctrl2 ctrl2 = loader.getController();
ctrlArray[i] = String.valueOf(ctrl2);
ctrl2.setRoundNum(String.valueOf(i));
System.out.println(row[i]);
} catch (IOException e) {
e.printStackTrace();
}
}
for (int i = 0; i < ctrlArray.length; i++) {
System.out.println("Controller: " + ctrlArray[i]);
}
}
private BigDecimal scoreInput;
private boolean numberInput;
@FXML
public void scoreEntry(ActionEvent event) {
Button button = (Button) event.getSource();
String buttonText = button.getText();
if (buttonText.matches("[0-10\\.]")) {
if (!numberInput) {
numberInput = true;
//TODO: find Label for input text
//I think it should be something like "row[0].getChildren().score[0].clear();"
}
//And then I would append it with something like "score[0].appendText(buttonText);"
return;
}
}
}
view2.fxml
<HBox prefHeight="30.0" prefWidth="400.0" style="-fx-background-color: #77e77e;" xmlns="http://javafx.com/javafx/17" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.nested.Ctrl2">
<children>
<Label fx:id="rowNum" text="Row Number" />
<HBox fx:id="scoresHolder" prefHeight="100.0" prefWidth="200.0" />
<Label fx:id="subTotal" text="Sub Total" />
<Label fx:id="total" text="Total" />
</children>
</HBox>
Ctrl2.java
public class Ctrl2 {
@FXML
private Label rowNum;
@FXML
private Label subTotal;
@FXML
private HBox scoresHolder;
@FXML
private Label total;
public void setRoundNum(String strRnd) {
rowNum.setText(strRnd);
}
public void setSubTotal(String strRnd) {
subTotal.setText(strRnd);
}
public void setTotal(String strRnd) {
total.setText(strRnd);
}
@FXML
void initialize() {
int plays = 1;
Label score[];
score = new Label[plays];
for (int i = 0; i < score.length; i++) {
score[i] = new Label("Score" + i);
scoresHolder.getChildren().add(score[i]);
System.out.println(score[i]);
}
}
}
Solution
I took @James_D's advice and wrapped my controllers and cells in arrays.
//This is the array for the controllers. It's outside the method to be accessed by other methods.
public static Ctrl2[] ctrlArray = new Ctrl2[2];
public void addRows() {
int rounds = 2;
HBox row = null;
for (int i = 0; i < rounds; i++) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/nested/view2.fxml"));
row = loader.load();
rowHolder.getChildren().add(row);
ctrlArray[i] = loader.getController();
ctrlArray[i].setRoundNum(String.valueOf(i));
} catch (IOException e) {
e.printStackTrace();
}
}
for (int i = 0; i < ctrlArray.length; i++) {
System.out.println("Controller: " + ctrlArray[i]);
}
}
The problem I was having was with scope. If I make the array holder outside the method I can access it from other methods.
private Label[] score;
public void addScores() {
int plays = 2;
//Moved array holder from here to outside
score = new Label[plays];
for (int i = 0; i < score.length; i++) {
score[i] = new Label("Score" + i);
scoresHolder.getChildren().add(score[i]);
System.out.println(score[i]);
}
}
Answered By - horribly_n00bie
Answer Checked By - Marilyn (JavaFixing Volunteer)