4 Replies Latest reply: Apr 26, 2013 11:25 AM by biochemistry43 RSS

    IllegalStateException: Not on FX application thread;

    biochemistry43
      What is the problem here?

      The exception is thrown in Panel_PatronesController.java in the estableceCoordenadasEnCampos(...) method.

      This method is called in EvaluateInput.java class which has a reference to this controller class (Panel_PatronesController).

      This reference has been passed in class ClientExecution. this in turn, received reference fromSocketCatcherClients class.

      References to this controller class, were obtained in the Main class and passed a thread executed SocketCatcherClients

      Panel_PatronesController.java
      ...
      public void tomarCoordenadas(int tipoPatron, String lat, String lon)
          {
              Pattern p = Pattern.compile("[,]+");
              
              
              double latitud = Double.parseDouble(lat);
              double longitud = Double.parseDouble(lon);
              
              //Recupera un ArrayList con las coordenadas convertidas a formato grados, minutos, orientación
              ArrayList<String> coordenadas = FuncionesSigna.CoordenadasDecimalAString(latitud, longitud);
              String conversionLat = coordenadas.get(0).toString();
              String conversionLon = coordenadas.get(1).toString();
              
              //Separo las coordenadas en sus partes
              String[] separaLat = p.split(conversionLat);
              String gradosLat = separaLat[0];
              System.out.println("gradosLat = "+ gradosLat);
              String minutosLat = separaLat[1];
              System.out.println("minutosLat = "+ minutosLat);
              String orientaLat = separaLat[2];
              System.out.println("orientaLat = "+ orientaLat);
              
              String[] separaLon = p.split(conversionLon);
              String gradosLon = separaLon[0];
              System.out.println("gradosLon = "+ gradosLon);
              String minutosLon = separaLon[1];
              System.out.println("minutosLon = "+ minutosLon);
              String orientaLon = separaLon[2];
              System.out.println("orientaLon = "+ orientaLon);
              
              estableceCoordenadasEnCampos(tipoPatron, gradosLat, minutosLat, orientaLat, gradosLon, minutosLon, orientaLon);
          }
      
      private void estableceCoordenadasEnCampos(int tipoPatron, String gradosLat, String minutosLat, String orientaLat, String gradosLon, String minutosLon, String orientaLon)
          {switch(tipoPatron)
              {
                  case 1:
                      campLatGradosPatronRectNumPiernas.setText(gradosLat);
                      campLatMinutosPatronRectNumPiernas.setText(minutosLat);
                      orientacionLatPatronRectNumPiernas.getSelectionModel().select(orientaLat);  //here exception
                      campLongGradosPatronRectNumPiernas.setText(gradosLon);
                      campLongMinutosPatronRectNumPiernas.setText(minutosLon);
                      orientacionLongPatronRectNumPiernas.getSelectionModel().select(orientaLon); //here exception
                  return;
                  ....
      }
      Main.java
      ...
       public void start(Stage primaryStage) {
              try {
                  
                  FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Estructura_General.fxml"));
                  AnchorPane page = (AnchorPane) fxmlLoader.load();
                  Estructura_GeneralController estructuraController = (Estructura_GeneralController) fxmlLoader.getController(); 
                 ...
                 Panel_PatronesController patronesController = estructuraController.getPatronesPanelController();
                  (new Thread(new SocketCatcherClients(patronesController))).start();
               ...
      ...
      Panel_PatronesController.java is a controller class of Panel_Patrones.fxml which is included in Estructura_General.fxml by fx:include ....

      This is the error message:
      Exception in thread "Thread-5" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-5
           at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
           at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
           at javafx.scene.Parent$1.onProposedChange(Parent.java:245)
           at com.sun.javafx.collections.VetoableObservableList.setAll(VetoableObservableList.java:90)
           at com.sun.javafx.collections.ObservableListWrapper.setAll(ObservableListWrapper.java:314)
           at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:602)
           at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:209)
           at com.sun.javafx.scene.control.skin.SkinBase$3.changed(SkinBase.java:282)
           at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:107)
           at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
           at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
           at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
           at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
           at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
           at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
           at javafx.beans.property.StringProperty.setValue(StringProperty.java:84)
           at javafx.scene.control.Labeled.setText(Labeled.java:135)
           at com.sun.javafx.scene.control.skin.ChoiceBoxSkin.updateSelection(ChoiceBoxSkin.java:321)
           at com.sun.javafx.scene.control.skin.ChoiceBoxSkin.access$200(ChoiceBoxSkin.java:60)
           at com.sun.javafx.scene.control.skin.ChoiceBoxSkin$5.invalidated(ChoiceBoxSkin.java:300)
           at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:155)
           at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
           at javafx.beans.property.ReadOnlyIntegerWrapper$ReadOnlyPropertyImpl.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:195)
           at javafx.beans.property.ReadOnlyIntegerWrapper.fireValueChangedEvent(ReadOnlyIntegerWrapper.java:161)
           at javafx.beans.property.IntegerPropertyBase.markInvalid(IntegerPropertyBase.java:130)
           at javafx.beans.property.IntegerPropertyBase.set(IntegerPropertyBase.java:163)
           at javafx.scene.control.SelectionModel.setSelectedIndex(SelectionModel.java:67)
           at javafx.scene.control.SingleSelectionModel.updateSelectedIndex(SingleSelectionModel.java:208)
           at javafx.scene.control.SingleSelectionModel.select(SingleSelectionModel.java:142)
           at javafx.scene.control.ChoiceBox$ChoiceBoxSelectionModel.select(ChoiceBox.java:417)
           at javafx.scene.control.SingleSelectionModel.select(SingleSelectionModel.java:117)
           at signa.Panel_PatronesController.estableceCoordenadasEnCampos(Panel_PatronesController.java:343)
           at signa.Panel_PatronesController.tomarCoordenadas(Panel_PatronesController.java:312)
           at mx.edu.inidetam.EvaluateInput.changeMap(EvaluateInput.java:72)
           at mx.edu.inidetam.ClientExecution.run(ClientExecution.java:66)
           at java.lang.Thread.run(Thread.java:722)
      Perhaps it was not necessary but I put so much information in case

      Sorry for bad English


      Thanks in advance

      Edited by: biochemistry43 on 25/04/2013 10:56 AM
        • 1. Re: IllegalStateException: Not on FX application thread;
          James_D
          Your method estableceCoordenadasEnCampos changes the state of the user interface. Changes to the user interface should only be executed on the FX Application thread: you're calling the method from a user Thread (the one you create in your start(...) method).

          Some UI methods will throw exceptions if they're not executed on the FX Application Thread: others don't but should be executed on that thread anyway. So your setText(...) method calls in estableceCoordenadasEnCampos(...) don't throw an exception but those calls should also be made on the FX Application Thread.

          To fix, replace
          estableceCoordenadasEnCampos(tipoPatron, gradosLat, minutosLat, orientaLat, gradosLon, minutosLon, orientaLon);
          with
          Platform.runLater(new Runnable() {
            @Override
            public void run() {
              estableceCoordenadasEnCampos(tipoPatron, gradosLat, minutosLat, orientaLat, gradosLon, minutosLon, orientaLon);
            }
          });
          You'll need to declare the variables gradosLat, minutosLat, orientaLat, gradosLon, minutosLon, orientaLon as final.

          If you're using Java 8 you can simplify to
          Platform.runLater( () -> estableceCoordenadasEnCampos(tipoPatron, gradosLat, minutosLat, orientaLat, gradosLon, minutosLon, orientaLon) );
          • 2. Re: IllegalStateException: Not on FX application thread;
            biochemistry43
            great James

            It worked very well but I would ask you a few more questions.

            Why should I declare "Final" variables?
            Where I can find all this information that you provide me?

            I understand that you are an expert but what is the right place to find information about JavaFX 2.0?

            It happens sometimes, I believe that the official documentation is poor or does not cover all those little details.

            The Web has a wealth of information of all kinds and not all guide you properly, so a novice like me, it is extremely difficult to find useful information and if we add the handling not too good English, the complication is worse .
            • 3. Re: IllegalStateException: Not on FX application thread;
              James_D
              biochemistry43 wrote:
              great James

              It worked very well but I would ask you a few more questions.

              Why should I declare "Final" variables?
              Because the Runnable you pass to Platform.runLater(...) is implemented as an anonymous inner class. Anonymous inner classes can only access instance variables and final local variables, not non-final local variables. That's a general Java topic rather than a JavaFX topic.

              Interestingly (perhaps), in Java 8 you can replace the anonymous inner class with a lambda expression: Platform.runLater( () -> estableceCoordenadasEnCampos(...) ); In this case, the local variables don't need to be final: the rule for lambda expressions is that they can access local variables that are "effectively final". "Effectively final" basically means that you could declare them as final without introducing a compile error. I think this is a bit strange: it's actually pretty good practice to declare variables as final whenever you can, so if a variable is "effectively final", it probably should be declared final anyway.
              Where I can find all this information that you provide me?

              I understand that you are an expert but what is the right place to find information about JavaFX 2.0?

              It happens sometimes, I believe that the official documentation is poor or does not cover all those little details.
              I disagree with that last statement.

              I consider myself to have a lot of Java experience: I landed my first Java consulting job in 1996 and these days as well as using Java quite a bit in my day job, I do some occasional Java consulting and also do some professional training in Java. I do not really consider myself a JavaFX expert: I have one large project in JavaFX, plus a couple of other small projects which I don't expect to be distributed beyond my own desktop. The main point is that everything I've learned about JavaFX I've learned from the official documentation. Probably one of the advantages of experience is knowing where to look in the documentation. (Cynics might say that the JavaFX documentation only looks good to those of us who had to deal with the documentation in the early days of Java; but again I don't really agree with that.)

              If you are new to Java, as well as to JavaFX, it's probably a good idea to work through [url http://docs.oracle.com/javase/tutorial/index.html]Oracles Java tutorial (at least the trails covering the basics). You'll find it does cover things such as [url http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html]anonymous classes, including knowing what variables can be accessed.

              You should also work through the [url http://docs.oracle.com/javafx/index.html]official JavaFX documentation. For example, the page on [url http://docs.oracle.com/javafx/2/architecture/jfxpub-architecture.htm]JavaFX architecture has a paragraph on Threads, which fairly clearly states that "live" scene graphs should only be accessed from the FX Application Thread.

              >
              The Web has a wealth of information of all kinds and not all guide you properly, so a novice like me, it is extremely difficult to find useful information and if we add the handling not too good English, the complication is worse .
              Yes indeed. Not everything you read on the internet is true :). I would recommend starting with the "official" documentation. If you can't find what you need there, look for things written (or at least linked) by sites maintained by those working for, or close to, the source. So for example fxexperience.com is maintained by Jonathan Giles, who is a tech lead for JavaFX. Articles linked from there are going to be pretty trustworthy. If you do find yourself needing to search, say, stackoverflow.com, see if you can verify the information you find there by looking back at the official documentation before trusting it.

              With time and experience, you'll learn where to find the right information; but you can accelerate that process by familiarizing yourself with the documentation as much as possible. And then you'll learn which articles online are trustworthy or not.
              • 4. Re: IllegalStateException: Not on FX application thread;
                biochemistry43
                Thanks James.

                Really appreciate all your recommendations and all the time you took to respond. I suspect you're a busy person and I wonder how that will give you time to answer these questions?

                Anyway ... thank you very much again

                God bless you