0

The following JavaFx program is supposed to get the current IP address on the machine once a button is pressed and show it on the screen. I have gotten everything to work, but I am having issues updating the text from the class that extends Task

MainApp.java

public class MainApp extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("/fxml/Scene.fxml"));

        Scene scene = new Scene(root);
        scene.getStylesheets().add("/styles/Styles.css");

        stage.setAlwaysOnTop(true);
        stage.setTitle("IP Viewer");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

my FXMLController

public class FXMLController implements Initializable {

    @FXML
    private void handleButtonAction(ActionEvent event) {

        Task<Void> task = new IpTask();;

        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();

    }

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }
}

IpTask: It gets the current IP address and tried to update the UI, but I get a java.lang.NullPointerException exception on textIp.setText

public class IpTask extends Task<Void> {

    @FXML
    private Text textIp;

    @Override
    protected Void call() throws Exception {
        Common common = new Common();
        Ip ip = common.getIp();
        System.out.println("You clicked me!");
        return null;
    }

    @Override
    protected void failed() {
        System.out.println("Failed!");
    }

    @Override
    protected void succeeded() {
        System.out.println("Updated");  
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                textIp.setText("JUST TO SEE IF THE TEXT GETS SET");
            }
        });
    }
}

and below is my Scene.fxml

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

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

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="com.limitedenterprisesinc.ipviewer.FXMLController">
    <children>
        <Button layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <!-- <Label layoutX="126" layoutY="120" minHeight="16" minWidth="69" fx:id="label" /> -->
        <javafx.scene.text.Text layoutX="126" layoutY="140" fx:id="textIp"/>
    </children>
</AnchorPane>

How can I update the textIp textfield from the IpTask class?

Arya
  • 8,473
  • 27
  • 105
  • 175

1 Answers1

2

Fields are injected to the controller instance that is used with the FXMLLoader. IpTask is not used as a controller and therefore nothing is injected to the field.

Inject the field to the controller and pass it to IpTask. Furthermore you don't have to use Platform.runLater in the succeeded method, since it's invoked on the JavaFX application thread.

public class FXMLController implements Initializable {

    @FXML
    private Text textIp;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        Task<Void> task = new IpTask(textIp);

        Thread thread = new Thread(task);
        thread.setDaemon(true);
        thread.start();
    }

    ...
}
public class IpTask extends Task<Void> {

    private final Text textIp;

    public IpTask(Text textIp) {
        if (textIp == null) {
            throw new IllegalArgumentException();
        }
        this.textIp = textIp;
    }

    ...

    @Override
    protected void succeeded() {
        System.out.println("Updated");
        textIp.setText("JUST TO SEE IF THE TEXT GETS SET");
    }
}
fabian
  • 80,457
  • 12
  • 86
  • 114