-2

I've created a 9x9 GridPane in SceneBuilder, and I want to add individual TextFields to each cell. I'm certain there are other methods for creating a large table like this, but I'm not looking for a different way to do this (this is part of my learning experience). I don't want to add TextFields in FXML/SceneBuilder; I want to keep track of them in an array so I can access their individual values, so I want to create them one at a time in the Controller and then add them to the array as well as to each cell of the GridPane.

Here is the part of my controller that attempts to add TextFields (I tried creating them before adding them to the array):

@FXML
private GridPane gridPane;
private TextField myTextField[][] = new TextField[9][9];
.
.
.
@Override
public void initialize(URL url, ResourceBundle rb) {
  for (int i = 0; i < 9; ++i){
        for (int j = 0; j < 9; ++j){

            TextField tempTextField = new TextField();
            Font myFont = new Font("System",38);
            tempTextField.setFont(myFont);
            tempTextField.setText(i + ", " + j);
            tempTextField.setPrefSize(70, 70);
            myTextField[i][j] = tempTextField;
            gridPane.add(tempTextField,i,j);
            System.out.println("TextField " +i+j+" Created!");
        }
    } 
}

I don't get an error before runtime and the scene is not updated.

EDIT: I have looked at the StackTrace and noticed that I'm getting a Null Pointer at

gridPane.add(tempTextField,i,j);

FXML File:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="654.0" prefWidth="747.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="sudokusolver.FXMLDocumentController">
    <children>
      <BorderPane prefHeight="654.0" prefWidth="747.0">
         <center>
            <GridPane fx:id="gridPane" gridLinesVisible="true" prefHeight="198.0" prefWidth="200.0" BorderPane.alignment="CENTER">
               <columnConstraints>
              <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
                  <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
               </columnConstraints>
               <rowConstraints>
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
                  <RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
               </rowConstraints>
            </GridPane>
         </center>
         <bottom>
            <HBox alignment="CENTER" prefHeight="40.0" prefWidth="747.0" BorderPane.alignment="CENTER">
               <children>
                  <FlowPane prefHeight="200.0" prefWidth="200.0">
                     <children>
                        <Button fx:id="loadButton" alignment="CENTER" contentDisplay="CENTER" minHeight="-Infinity" minWidth="-Infinity" onAction="#setGrid" prefHeight="35.0" prefWidth="100.0" text="Load Board" />
                          <Button fx:id="solveButton" alignment="CENTER" contentDisplay="CENTER" minHeight="-Infinity" minWidth="-Infinity" onAction="#sudokuSolve" prefHeight="35.0" prefWidth="100.0" text="Solve" />
                     </children>
                  </FlowPane>
               </children>
            </HBox>
         </bottom>
      </BorderPane>
    </children>
</AnchorPane>
Anil
  • 655
  • 1
  • 11
  • 25
Raitab
  • 1
  • 1
  • So obviously `gridPane` is null. Maybe post the FXML file? – James_D Oct 03 '17 at 22:09
  • @James_D I have updated. Also, could you let me know if updating the question notifies people who have commented. That way I can avoid pointless tags/comments like this. – Raitab Oct 03 '17 at 22:31
  • No, there are no automatic notifications for an edit to a question (other than notifications if someone else edits your question or answer). – James_D Oct 03 '17 at 22:33
  • That looks correct. This is the controller for the FXML you posted, presumably? And I assume you are not using it as a controller for any other FXML files, or creating any other instances of it somehow? – James_D Oct 03 '17 at 22:34
  • @James_D I've remedied the problem. I'm rather new to all of this and NetBeans has a default FXML document. I deleted a Label from SceneBuilder and it didn't delete the object in the Controller. It wasn't giving me an error for the Label at all, but was instead directing me toward that other line. I appreciate your help in getting me to understand this. – Raitab Oct 03 '17 at 23:03

1 Answers1

3

Try implementing the javafx.fxml.Initializable interface in your controller and move the setGrid() logic to the method that comes with it.

Anil
  • 655
  • 1
  • 11
  • 25
Miron Balcerzak
  • 886
  • 10
  • 21
  • 5
    You don't need to implement `Initializable` (since JavaFX 2.1). Just define a method `public void initialize()`, it will be invoked automatically by reflection. – James_D Oct 03 '17 at 13:59
  • Moving to initialize is something I had tried before. I tried it again for certainty and it doesn't work. I could post the error given at compilation, but it's very long. There appears to be a Reflection, Loader, and Null Pointer Exceptions, but none point directly to my code. – Raitab Oct 03 '17 at 14:46
  • @Raitab Edit your question to include your attempt to use `initialize()` and the complete stack trace. I assume if you got null pointer exceptions you read https://stackoverflow.com/questions/218384/what-is-a-nullpointerexception-and-how-do-i-fix-it and tried to fix them. – James_D Oct 03 '17 at 14:53
  • @James_D - you are right, and I am well aware of that feature. However, personally, I do not like "magic" within my code. This is some convention that JavaFX developers agreed on...but this is just me and my way of keeping the "clean code" :) – Miron Balcerzak Oct 03 '17 at 15:27
  • @MironBalcerzak Isn't "if the controller implements `Initializable`, invoke its `initialize()` method" just as much a convention as "If the controller has an `initialize()` method, invoke it"? There are pros and cons. E.g. it's much easier to catch a typo in the name of the method if you implement the interface; however using the reflection approach has much more flexibility (you can drop the parameters if you don't need them, or make the method private if you annotate it, etc.) – James_D Oct 03 '17 at 15:33
  • @James_D Thanks James, upon more careful observation, I saw that I had missed the key line. I've updated the question with the initialize method and the line I found from the Stack Trace. – Raitab Oct 03 '17 at 22:06