1

JavaFx textfield.setText() method not working when called from another thread,I am calling recieved() method from another thread.but I am not able to set the text,to the text field so I used platform.runlater but it is not working.

DepartmentsController is my controller class which has recieved method that is called from another thread (kryonet thread-Kryonet a high level networking library).

import com.MyCompany.Modal.DepartmentModal;
import com.MyCompany.Network.ClientMaster;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.animation.FadeTransition;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.util.Duration;

public class DepartmentsController implements Initializable {

   private DepartmentModal departmentModal;
    @FXML
    Button btn;
    @FXML
    VBox vBox;
    @FXML
    ComboBox departmentNameComboBox;
    @FXML
    TextField departmentNameTF;
    @FXML
    TextField departmentIdTF;
    @FXML
    TextField noOfBatchTF;

  Main main;

  public void customInitialize()//initialize from controllers
  {     departmentModal.setRequestData(true);
        ClientMaster.NETWORK_MANAGER.client.sendTCP(departmentModal);

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

       departmentModal=new DepartmentModal();



        //String string = new StringBuilder("abcd").append(23).append(false).append("xyz").toString();

    TranslateTransition tt = new TranslateTransition(Duration.millis(700),btn);
                        tt.setFromX(-100);
                        tt.setToX(0f);
                        tt.setCycleCount((int) 1f);
                        tt.setAutoReverse(false);
                        tt.play();

    FadeTransition ft = new FadeTransition(Duration.millis(1000), vBox);
                   ft.setFromValue(0);
                   ft.setToValue(1.0);
                   ft.play();

    }    
    public void initiate(Main main)
    {
        this.main=main;

    }
    public void backBtnOnClick()
    {
       main.controllers.dashBoardController.Initiate(main);

        System.out.println("clicked");
    }

    public void saveBtnOnClick()
    {

    }
    public void clearBtnOnClick()
    {

    }

    public void recieved(DepartmentModal departmentModal)
    {




        if(departmentModal.isRequestData()==true)
        {
             Platform.runLater(new Runnable() {
    @Override
    public void run() {
            System.out.println(departmentModal.getDepartmentId());
           departmentIdTF.setText(departmentModal.getDepartmentId());//cannot set this field

               }
});
        }


    }
}

I have main class that is starting of javafx applicaiton that initialize controllers class that contain all controllers of my javafx application

import com.MyCompany.Network.ClientMaster;
import javafx.animation.ScaleTransition;

import javafx.application.Application;
import javafx.geometry.Rectangle2D;

import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;


/**
 *
 * @author shersha
 */
public class Main extends Application {
    public Controllers controllers;

    @Override
    public void start(Stage stage) throws Exception {


controllers=new Controllers();     
new StaticClass(stage);
new ClientMaster(this);



        Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();


StaticClass.stage.setX(bounds.getMinX());
StaticClass.stage.setY(bounds.getMinY());
StaticClass.stage.setWidth(bounds.getWidth());
StaticClass.stage.setHeight(bounds.getHeight());




       controllers.loginController.initialize(this);
       Scene scene = new Scene(controllers.loginLoader.getRoot());
       scene.getStylesheets().add("com/MyCompany/UICoreComponents/JMetroDarkTheme.css");
    /*FadeTransition ft = new FadeTransition(Duration.millis(2000), controllers.loginLoader.getRoot());
    ft.setFromValue(0.5);
    ft.setToValue(1.0);
    ft.play();*/



    /* TranslateTransition tt = new TranslateTransition(Duration.millis(2000), controllers.loginLoader.getRoot());
     tt.setByX(200f);
     tt.setCycleCount((int) 4f);
     tt.setAutoReverse(true);

     tt.play();*/

     ScaleTransition st = new ScaleTransition(Duration.millis(1000), controllers.loginLoader.getRoot());
     st.setFromX(1.5f);
     st.setFromY(1.5f);
     st.setToX(1f);
     st.setToY(1f);
     st.setCycleCount((int) 1f);
     st.setAutoReverse(true);

     st.play();

       StaticClass.stage.setFullScreen(true);
       StaticClass.stage.setScene(scene);

    StaticClass.stage.setFullScreenExitHint("");
    //StaticClass.stage.setFullScreenExitKeyCombination(KeyCombination.NO_MATCH);

       StaticClass.stage.show();

        /*


       StaticClass.stage.setScene(StaticClass.LOGIN_SCENE);

       StaticClass.stage.setFullScreen(true);

    StaticClass.stage.setFullScreenExitHint("");

         StaticClass.stage.show();

*/



    }


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

}

Controllers class create reference departmentscontroller so that i can access it from any controller like

main.controllers.departmentcontroller

import javafx.fxml.FXMLLoader;

/**
 *
 * @author Shersha
 */
public class Controllers {
     public LoginController loginController;
     public DepartmentsController departmentsController;
     public DashBoardController dashBoardController;
     public SchemeDepartmentController schemeDepartmentController;
     public StaffsController staffsController;
     public SchemesController schemesController;
     public SubjectsController subjectsController;
     public StudentsController studentsController;
     public StaffManagementController staffManagementController;
     public StudentManagementController studentManagementController;
     FXMLLoader staffManagementLoader,studentManagementLoader,subjectsLoader,studentsLoader,loginLoader,dashBoardLoader,schemesLoader,departmentsLoader,schemeDepartmentLoader,staffsLoader;
    public Controllers() throws Exception
    {
       loginLoader= new FXMLLoader();
       loginLoader.setLocation(getClass().getResource("Login.fxml"));
       loginLoader.load();
       loginController= loginLoader.getController();



       dashBoardController= new DashBoardController();



       schemesLoader= new FXMLLoader();
       schemesLoader.setLocation(getClass().getResource("Schemes.fxml"));
       schemesLoader.load();
       schemesController= schemesLoader.getController();

        departmentsLoader= new FXMLLoader();
        departmentsLoader.setLocation(getClass().getResource("Departments.fxml"));
        departmentsLoader.load();
        departmentsController=departmentsLoader.getController();


        schemeDepartmentLoader= new FXMLLoader();
        schemeDepartmentLoader.setLocation(getClass().getResource("SchemeDepartment.fxml"));
        schemeDepartmentLoader.load();
        schemeDepartmentController=schemeDepartmentLoader.getController();



        staffsLoader= new FXMLLoader();
        staffsLoader.setLocation(getClass().getResource("Staffs.fxml"));
        staffsLoader.load();
        staffsController=staffsLoader.getController();


        subjectsLoader= new FXMLLoader();
        subjectsLoader.setLocation(getClass().getResource("Subjects.fxml"));
        subjectsLoader.load();
        subjectsController=subjectsLoader.getController();


        studentsLoader= new FXMLLoader();
        studentsLoader.setLocation(getClass().getResource("Students.fxml"));
        studentsLoader.load();
        studentsController=studentsLoader.getController();

        staffManagementLoader= new FXMLLoader();
        staffManagementLoader.setLocation(getClass().getResource("StaffManagement.fxml"));
        staffManagementLoader.load();
        staffManagementController=staffManagementLoader.getController();

        studentManagementLoader= new FXMLLoader();
        studentManagementLoader.setLocation(getClass().getResource("StudentManagement.fxml"));
        studentManagementLoader.load();
        studentManagementController=studentManagementLoader.getController();
    }
   public void initialize()
   {
       departmentsController.customInitialize();

   }

}

NetworkManager(kryonet thread) is the class that calls recive method in departmentscontroller

import com.MyCompany.Modal.DepartmentModal;
import com.MyCompany.Modal.LoginModal;
import com.MyCompany.Modal.SchemeModal;
import com.MyCompany.attendanceMaster.StaticClass;
import com.esotericsoftware.kryonet.Client;
import com.esotericsoftware.kryonet.Connection;
import com.esotericsoftware.kryonet.Listener;
import java.io.IOException;
import com.MyCompany.attendanceMaster.Main;
/**
 *
 * @author shersha
 */
public class NetworkManager extends Listener{


    String ip = "localhost";
   public  Client client;
    int port = 27960;
        Main main;
        RegisterClasses registerClasses;
        public NetworkManager(Main main)
        {
            this.main=main;
        }
             public void connect(){
        client = new Client();
         registerClasses=new RegisterClasses(client);

        client.addListener(this);

        client.start();
        try {
            client.connect(5000, ip, port, port);
        } catch (IOException e) {
            e.printStackTrace();

                        System.out.println("server offline");
        }
    }


             public void received(Connection c, Object o){
        if(o instanceof LoginModal){
            LoginModal loginModal=(LoginModal)o;


                      main.controllers.loginController.recieved(loginModal);


                    }
                   else if(o instanceof SchemeModal)
                {

                    SchemeModal schemeModal=(SchemeModal)o;
                   main.controllers.schemesController.recieved(schemeModal);
                }
                 else if(o instanceof DepartmentModal)

                {
                  System.out.println("point 1");
                    DepartmentModal departmentModal=(DepartmentModal)o;
                   main.controllers.departmentsController.recieved(departmentModal);
                }
    }


}

I have one more class called dashboard controller that puts all fxml element to the stage

public class DashBoardController implements Initializable {
  SchemesController schemesController;
  Main main;
 ToggleButton[] tb,tb2;
 Parent root ;
 ImageView iv0,iva0,iv1,iva1,iv2,iva2,iv3,iva3,iv4,iva4,iv5,iva5,iv6,iva6,iv7,iva7;
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
       System.out.println("one time");



    public void Initiate(Main main)
    {
      this.main=main;
        // tb=new ToggleButton[8];
             tb2=new ToggleButton[8];
           VBox up = new VBox(20);
       Text text4flow = new Text("Basic");
        text4flow.setFont(Font.font("Calibri", FontWeight.BOLD, 30));
     text4flow.setFill(Color.WHITE);
        text4flow.setUnderline(false);
        VBox.setMargin(text4flow, new Insets(10, 0, 0, 10));

        //creating Flow Pane

        up.setPadding(new Insets(50, 50, 50, 50));

        FlowPane flowpane = new FlowPane();
        flowpane.setHgap(10);
        flowpane.setVgap(10);



flowpane.getChildren().add(tb[1]);



tb[1].addEventHandler(MouseEvent.MOUSE_ENTERED, 
    new EventHandler<MouseEvent>() {

        @Override public void handle(MouseEvent e) {

 tb[1].setSelected(true);

tb[1].setGraphic(iva1);

        }
         });


  tb[1].addEventHandler(MouseEvent.MOUSE_EXITED, 
    new EventHandler<MouseEvent>() {
             private Effect shadow;
        @Override public void handle(MouseEvent e) {
          tb[1].setGraphic(iv1);




        }
         });

tb[1].setOnAction(new EventHandler<ActionEvent>() {
    @Override public void handle(ActionEvent e) {
        tb[1].setGraphic(iva1);
        try {
            System.out.println("kk");
            FXMLLoader loader= new FXMLLoader();
            loader.setLocation(getClass().getResource("Departments.fxml"));

            Pane screen = (Pane) loader.load();
            main.controllers.departmentsController=loader.getController();
            main.controllers.departmentsController.initiate(main);
            StaticClass.stage.setFullScreen(true);
          /*  FadeTransition ft = new FadeTransition(Duration.millis(1000), screen);
            ft.setFromValue(0.7);
            ft.setToValue(1.0);
            ft.play();*/
            StaticClass.stage.getScene().setRoot(screen);
            StaticClass.stage.getScene().getStylesheets().add("com/MyCompany/UICoreComponents/JMetroDarkTheme.css");
            StaticClass.stage.show();

//Execute some code here for the event..
        } catch (IOException ex) {
            Logger.getLogger(DashBoardController.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
});

          StaticClass.stage.getScene().setRoot(up);                   
          StaticClass.stage.getScene().getStylesheets().add("com/MyCompany/UICoreComponents/JMetroDarkTheme.css");
          StaticClass.stage.show();


    }
}
Shersha Fn
  • 1,511
  • 3
  • 26
  • 34
  • Please show more context for your code. Where is `received` defined? In a controller? Where is it called from? If it's defined in a controller, how are you getting the reference to the controller? – James_D Jan 19 '16 at 16:47
  • i have added all necessary informations... – Shersha Fn Jan 19 '16 at 17:02
  • received is not called from a controller it is called form NetworkManager class which itself is another thread.To reference controller I am using controllers class that has all controllers defined and referenced – Shersha Fn Jan 19 '16 at 17:07
  • The relationships between the various pieces are still not very clear. You probably need to create a [MCVE] to get help here. (Emphasis on *complete* and *minimal*: you don't need 10 different views to show the issue, but you do need to show how you are displaying the text field that isn't responding to your method call.) I recommend writing a new project from scratch that has *just enough* to show the problem. – James_D Jan 19 '16 at 17:12
  • I am really frustrated....to fix this issue....I am trying to set departmentsId.setText() method from another thread Networkmanager class ,I researched and found out that I have to use platform.runlater inorder to acess gui thread from another thread but the problem is it is not working i cannot set the text – Shersha Fn Jan 19 '16 at 17:19
  • Ok I will start from scratch,Is there any way I could Live chat with you to fix this issue?? – Shersha Fn Jan 19 '16 at 17:23
  • I have meetings for the rest of the day... I would probably want to completely redesign this which may not be what you want to hear anyway :). IMO you need a data model that is independent of the controllers, and all data changes go through the model. Once you start trying to communicate directly from one controller to another you start to get in a big mess. See if http://stackoverflow.com/questions/32342864/applying-mvc-with-javafx helps clarify what I mean (though of course you can use whatever design you like; it's just a suggestion). – James_D Jan 19 '16 at 17:27
  • My best guess, though, is that the instance of `DepartmentsController` on which you are calling `received` is not the one that is connected to the UI that is displayed. Try putting `System.out.println(this);` in the `DepartmentsController` constructor and in the `received` method: you can then see how many are created and which one(s) you call `received` on (you can distinguish the instances by the hashcode displayed in the default `toString()` method). – James_D Jan 19 '16 at 17:41
  • (Instance of departmentscontroller).recieved(departmentModal) when called from another thread ie networkmanager passes departmentmodal.getdepartmentid() when i print it like this System.out.println(departmentModal.getDepartmentId()); inside recieved method i am getting the id as D101,I am sure that it is connected to to UI that is displayed. and when i set it to textfied like departmentIdTF.setText(departmentModal.getDepartmentId()); it wont set. – Shersha Fn Jan 19 '16 at 17:55
  • I think the problem is with design of my application as you said earlier... thank you very much for your help appreciate it... :) – Shersha Fn Jan 19 '16 at 17:57

1 Answers1

-1

First of all, be sure that you are getting the data BEFORE initializing the view, I suggest to place the code of your "custom initializer" inside the actual initializer...

Then try replacing your Runnable with a Task, wich is a Background JavaFX Thread that handle the UI and place the Text in your TextField:

final Task task = new Task<Void>() {
        @Override
        protected Void call() throws Exception {
            //code here
            return null;
        }
    };

new Thread(task).start();

You can read more about Tasks in the official documentation: https://docs.oracle.com/javafx/2/api/javafx/concurrent/Task.html

PekosoG
  • 246
  • 3
  • 9
  • That makes no sense. Since you can't change the UI on a background thread, and the `NetworkManager`, as stated, is running on a background thread, the OP is using `Platform.runLater(...)` to schedule that change on the FX Application Thread. Using a `Task` to move it to a *different* background thread is hardly going to help. – James_D Jan 19 '16 at 19:19
  • Sorry James, but what do you mean? I've changed the UI by using a Task exactly as I answered, did I use a different/wrong concept? – PekosoG Jan 19 '16 at 19:30
  • You cannot make changes to the UI on a background thread. See, e.g., the "Threading" section in the [`Application` documentation](http://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html). The whole point of `Platform.runLater(...)` is to schedule those changes on the FX Application Thread when you are using background threads. Read the documentation you linked. *Nowhere* in any of those examples is the UI changed from the `call()` method, unless the change is wrapped in `Platform.runLater()`. – James_D Jan 19 '16 at 19:34
  • I had a look at some of your other answers, and many of them are as dangerously wrong as this one. You should take those answers (and this one) down until you properly understand threading in JavaFX. – James_D Jan 19 '16 at 20:09
  • I'm sorry, they worked fine with me and I thought they were correct. – PekosoG Jan 19 '16 at 20:32
  • @pekoso Garcia I tried this as you said but it is not working...it made no difference – Shersha Fn Jan 20 '16 at 03:12