Java FX - Thread Issues

0

Good morning,

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

Whenever I run the code I get an error, but if I run that same code without leaving 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 for 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) {

    }    

}

Here is the example of my FXML:

<?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 always accusing:

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)
    
asked by anonymous 25.05.2018 / 07:22

1 answer

1

Your purpose was only made 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 they are compatible). In my case I used the updateMessage () method, so that Thread can send progress messages, and linked it to the text property of the label I want to change.

The result is this:

Onceagainwatchoutformultiplethreadsupdatingthesamenode(thelabelinthecase)

Toseetheprocessusingaprogressindicator,seethisquestion:

26.05.2018 / 16:37