Java FX - Threading Issues

Asked

Viewed 361 times

0

Good morning,

I would like to sanction a question that is disturbing me, as I do to edit a Label from a Thread using a button?

Whenever I run the code I get an error, but if I run this same code without setting the Label it works perfectly, generating a System.out.println("some text"); for example.

I would like an explanation on the subject and a solution to it, grateful.

Follow my class Example:

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package Ajuda;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;

/**
 * FXML Controller class
 *
 * @author neto_
 */
public class AjudaController implements Initializable {

    @FXML
    Label label;

    @FXML
    private Button botao;

    @FXML
    void apBotao(ActionEvent event) {
        thread.start();
    }

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            // do work
            label.setText("text");
        }
    });

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {

    }    

}

Follow the FXML of my example:

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

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Ajuda.AjudaController">
   <children>
      <Label fx:id="label" layoutX="286.0" layoutY="192.0" text="Label" />
      <Button fx:id="botao" layoutX="274.0" layoutY="144.0" mnemonicParsing="false" onAction="#apBotao" text="Button" />
   </children>
</AnchorPane>

Error that always accuses:

Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
    at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:279)
    at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
    at javafx.scene.Parent$2.onProposedChange(Parent.java:367)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:113)
    at com.sun.javafx.collections.VetoableListDecorator.setAll(VetoableListDecorator.java:108)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.updateChildren(LabeledSkinBase.java:575)
    at com.sun.javafx.scene.control.skin.LabeledSkinBase.handleControlPropertyChanged(LabeledSkinBase.java:204)
    at com.sun.javafx.scene.control.skin.LabelSkin.handleControlPropertyChanged(LabelSkin.java:49)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
    at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
    at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
    at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:182)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:103)
    at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:110)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:144)
    at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:49)
    at javafx.beans.property.StringProperty.setValue(StringProperty.java:65)
    at javafx.scene.control.Labeled.setText(Labeled.java:145)
    at Ajuda.AjudaController$1.run(AjudaController.java:38)
    at java.lang.Thread.run(Thread.java:748)
  • You’ve changed little from the previous code, except for the services. As I said in the previous question changes on the screen can only be made by the main thread. If you just change a label to use Thread?

  • Because the system requires changes to the label, since I will work with a load screen and change values after it, if I do not use threads the entire program becomes static during the operation of the method used. @Gustavofragoso

1 answer

1


Your purpose just became clear in your comment above. If you want a loading screen with updates there is an easy way to do this:

Label label = new Label("Texto inicial");

Service<Void> atualizacao = new Service<Void>() {

    @Override
    protected Task<Void> createTask() {

        return new Task<Void>() {

            @Override
            protected Void call() throws Exception {

                updateMessage("Iniciando atualização");
                Thread.sleep(2000); // Suas tarefas demoradas

                updateMessage("Operação 1 concluída");
                Thread.sleep(2000); // Suas tarefas demoradas

                updateMessage("Finalizando");
                return null;
            }

        };
    }
};

label.textProperty().bind(atualizacao.messageProperty());

atualizacao.start();

When you create a link between properties in Javafx they interact with each other (if compatible). In my case I used the updateMessage() method, so that Thread launches progress messages, and I linked it to the text property of the label I want to change.

The result is this:

Thread

Again beware of multiple threads updating the same node (the label in the case)

To see the process using a progress indicator see this question: Javafx progress indicator in interface construction

progress bar is not updating correctly

  • Very well explained, thank you. But I still have one more question, what if I want to set the percentages of the progression through another class for example? Is it possible? Using for example a method that receives double values.

  • 1

    Take a look at the other questions I Linkei, have other methods you can use as updateValue(), updateProgress() etc

  • Relax, I figured out how to do it, helped me a lot, thanks!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.