0

I need to update my GUI based on client input. Calling my controller class method, from the background task works. But it can't update the GUI, because it is not the JavaFX application thread..please help.

I tried many of the related Q & A, but I am still confused.

Should I use Platform. runLater or Task ?

Here's my class where I create an instance of controller class

public class FactoryClass {

    public static Controller_Gui1 createGUI() {
        FXMLLoader fxLoader = new FXMLLoader();
        fxLoader.setLocation(MainApp_Gui1.class.getResource("/com/Gui_1.fxml"));
        AnchorPane anchorPane = null;
        try {
            anchorPane = (AnchorPane) fxLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
        Controller_Gui1 controller_Gui1 = (Controller_Gui1) fxLoader
                .getController();
        Scene scene = new Scene(anchorPane);
        //System.out.println(scene);
        controller_Gui1.setScene(scene);
        return controller_Gui1;
    }
}

Controller class

@FXML
Button B1 = new Button();
@FXML
public void handleButton1() {
    B1.setDisable(true);
}

Application class

public class MainApp_Gui1 extends Application {
    Controller_Gui1 cGui;

    @Override
    public void start(Stage primaryStage) throws Exception {
        initScene(primaryStage);
        primaryStage.show();
        System.out.println("asdasd");
        SceneSetting sceneSetting = new SceneSetting();
        //handleEvent();
        System.out.println("after");
        sceneSetting.setSceneAfter();
        System.out.println("after2");

    }

    // creating scene
    private void initScene(Stage primaryStage) throws IOException {
        primaryStage.setScene(getScene(primaryStage));

    }

    public Scene getScene(Stage primaryStage) {
        Controller_Gui1 cGui;
        cGui = FactoryClass.createGUI();
        return cGui.getScene();
    }

    public void ExcessFromOutside() {
        Platform.runLater(new Runnable() {
            public void run() {
               System.out.println(Platform.isFxApplicationThread());
               cGui.handleButton1();
            }
        });

    }

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

I want to call ExcessFromOutside() method from another thread.

I got a null pointer exception while trying to update the GUI Here's my application class

public class MainAppGui1 extends Application {
Controller_Gui1 controller_Gui1;
@Override
public void start(Stage primaryStage) throws Exception {
    initScene(primaryStage);
    primaryStage.show();

}
// creating scene
public void initScene(Stage primaryStage) throws IOException {
    FXMLLoader fxLoader = new FXMLLoader();
    fxLoader.setLocation(MainApp_Gui1.class.getResource("/com/Gui_1.fxml"));
    AnchorPane anchorPane=new AnchorPane();
    anchorPane = (AnchorPane) fxLoader.load();
    Controller_Gui1 controller_Gui1 = (Controller_Gui1) fxLoader.getController();
    Scene scene = new Scene(anchorPane);
    primaryStage.setScene(scene);
}
@FXML
public  void ExcessFromOutside()
{
    Platform.runLater(new Runnable() {      
        @Override 
        public void run() {

            System.out.println("called atleast");
            controller_Gui1.handleButton1();

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


}

and this is the class from where i tried to update the GUI

public class Hudai {
public static void main(String args[]) throws InterruptedException
{
    new Thread()
    {
        public void run()
        {
            MainAppGui1.main(null);
        }
    }.start();
    Thread.sleep(5000);
    MainAppGui1 m = new MainAppGui1();
    m.ExcessFromOutside();      
}

}
Community
  • 1
  • 1
xoxis
  • 11
  • 1
  • 6

2 Answers2

1

To disable your button in a different thread you can use Task's updateValue.

Task<Boolean> task = new Task<Boolean>() {
    @Override
    public Boolean call() {
         ... // The task that this thread needs to do
         updateValue(true);
         ...
         return null;
    }
};
button.disableProperty().bind(task.valueProperty());

If you want to use a new thread to call a method, which alters the scene graph, the best chance you have is to use Platform.runLater() in it.

//code inside Thread
...
// code to run on the JavaFX Application thread
Platform.runLater(new Runnable() {
    @Override 
    public void run() {
         handleButton1();
    }
});
...
ItachiUchiha
  • 36,135
  • 10
  • 122
  • 176
  • You need a `Task` if you want to call `updateValue(true)`. – James_D Mar 26 '15 at 16:39
  • Ohh yeah, correct. A typo while writing the snippet, thanks for pointing that out :) – ItachiUchiha Mar 26 '15 at 16:46
  • Thanks a lot.Platform.runlater is better for my project..but it's still not working. i don't know why..my GUI changes from mouse clicking..but i can't update it through a method from application thread using platform.runlater.My project is a two player game.I need to disable a button from a grid based on client message.so i want to change my GUI from the thread where i receive input streams.thank you – xoxis Mar 29 '15 at 21:01
  • You don't need `Platform.runLater` if you are already on the `Application Thread`. I don't really understand your question. Can you create a [MCVE](http://stackoverflow.com/help/mcve) and add it to your question, to help me understand the scenario? – ItachiUchiha Mar 29 '15 at 21:15
  • Your implementation doesn't make any sense. – ItachiUchiha Mar 30 '15 at 08:42
  • It has multiple issues. For example *1. usage of `@FXML` in `MainAppGui1` which is not a controller.* *2. Creating a new instance of class which extends Application `MainAppGui1 m = new MainAppGui1();`.* I suggest you to go through the [documentation](http://docs.oracle.com/javase/8/javafx/api/toc.htm) and [tutorials on JavaFX](http://docs.oracle.com/javase/8/javafx/fxml-tutorial/preface.htm) / [tutorials on FXML](http://docs.oracle.com/javase/8/javafx/get-started-tutorial/index.html) first. – ItachiUchiha Mar 30 '15 at 08:59
0

You should get a NullPointerException when you run this program.

The problem is, the member of MainApp_Gui1

Controller_Gui1 cGui;

never gets a value.

Remove line "Controller_Gui1 cGui;" from this code:

public Scene getScene(Stage primaryStage) {
    // Hudai hudai = new Hudai(primaryStage);
    // return hudai.getScene();
    Controller_Gui1 cGui;
    cGui = FactoryClass.createGUI();
    return cGui.getScene();

}
gaRos
  • 2,463
  • 6
  • 22
  • 27
  • Another thing, if you use @FXML for initializing a Button, you don't have to call new. So @ FXML Button B1; // without new Button – gaRos Mar 25 '15 at 11:52
  • thank you,,i just started javafx..thats why...and all i want to update my gui using this method – xoxis Mar 25 '15 at 11:56
  • problem is my ExcessFromOutside method is called after closing the window – xoxis Mar 25 '15 at 11:58
  • it is working but i want to make change with the method...but i cant – xoxis Mar 25 '15 at 12:03
  • ooh, but why do you want to modify that button if you close the window, I don't understand what do you want to achive with your application. – gaRos Mar 25 '15 at 12:03
  • If the application is started, and the GUI is visible, then you can call cGui.handleButton1(); without the Platform.runLater... that is only necessary if you try to do something before the window is loaded. But I still don't understand how your window is closing. – gaRos Mar 25 '15 at 12:08
  • i want to modify this button before closing...but cant..because the application thread doesent get this method before closing the window.... i want to update my gui from another thread how can i do that..any tutorial ? – xoxis Mar 25 '15 at 12:09
  • okay ill try it .. for clearence i wana make a game that will disable a button based on client input..thank u – xoxis Mar 25 '15 at 12:15