-2

For anyone experienced with JavaFX, I have made a canvas inside my scene builder, but when I actually try to access said canvas it is null, I am not sure why as I know its made inside my scene builder and shows up in my FXML File Ive gone ahead and pushed the code to github, it can be found here if anyone wants to look and see if I did something wrong: https://github.com/ProSavage/JavaFXCalculator/tree/master/src/application/grapher Feel free to give any other advice as well!

Here is the relevant code

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.layout.AnchorPane?>
 <?import javafx.scene.layout.HBox?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" 
minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0"  
xmlns="http://javafx.com/javafx/9.0.1" xmlns:fx="http://javafx.com/fxml/1" 
fx:controller="application.grapher.GrapherController">
<children>
  <HBox alignment="CENTER" layoutX="4.0" layoutY="280.0" prefHeight="20.0" 
prefWidth="593.0">
     <children>
        <TextArea prefHeight="37.0" prefWidth="569.0" />
     </children>
  </HBox>
  <Button layoutX="238.0" layoutY="336.0" mnemonicParsing="false" 
  prefHeight="50.0" prefWidth="125.0" text="Graph" />
     <HBox fx:id="canvasBox" layoutX="14.0" layoutY="20.0" 
prefHeight="250.0" prefWidth="570.0" />
 </children>
   </AnchorPane>

The class

public class GrapherController {

@FXML
private HBox canvasBox;


public void test() {
    Canvas canvas = new Canvas(570,250);
    canvasBox.getChildren().add(canvas);
    double startX = canvas.getWidth()/2 * -1;
    double endX = startX * -1;
    double startY = canvas.getHeight()/2 * -1;
    double endY = startY * -1;

    GraphicsContext grapher = canvas.getGraphicsContext2D();
    grapher.beginPath();

    String equation = "x+1";
    grapher.moveTo(startX,Evaluator.eval(equation.replace("x",startX + "")));
    for (double i = startX; i < endX; i++) {
        grapher.lineTo(startX,Evaluator.eval(equation.replace("x",String.valueOf(i))));
    }






}



}

Basically when running the test method, If I create a canvas and add it to the box, the canvas is null and if I try making it into the xml file itself its still null. I feel like theres some essential step I am missing to the canvas it self.

  • `Canvas canvas = new Canvas(570,250);` unless this statement throws an exception, `canvas` CANNOT be `null` afterwards. If you complain about the `Canvas` being empty however... You need to call `stroke` on the `GraphicsContext` to actually draw something. Furthermore always using `startX` as `x` coordinate is probably not the correct thing to do... – fabian May 21 '18 at 08:10

1 Answers1

0

It is actually your canvasBox field that is null. But the issue lies in your GrapherScene class. You are manually creating a GrapherController and calling test() on that instance. There is no possible way for canvasBox to not be null in that instance:

  • You never set it yourself
  • The instance wasn't created by a FXMLLoader which means no dependency injection of the FXML fields occur

Change:

public GrapherScene() {
    try {
        Stage grapherStage = new Stage();
        Parent root = FXMLLoader.load(getClass().getResource("grapher.fxml"));
        Scene scene = new Scene(root, 600, 400);
    //scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
        grapherStage.setScene(scene);
        grapherStage.setTitle("Grapher");
        grapherStage.show();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    GrapherController grapher = new GrapherController();
    grapher.test();
}

To:

public GrapherScene() {
    try {

        Stage grapherStage = new Stage();
        FXMLLoader loader = new FXMLoader(getClass().getResource("grapher.fxml"));
        grapherStage.setScene(new Scene(loader.load());
        grapherStage.setTitle("Grapher");
        grapherStage.show();

        // Must be called AFTER loader.load()
        // Method has generic return type so explicit casting is not necessary in this case
        GrapherController grapher = loader.getController();
        grapher.test();

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Note: I'm using the instance FXMLLoader.load() method here and not the static FXMLLoader.load(URL) method.


For more information:

Slaw
  • 37,820
  • 8
  • 53
  • 80