-1

I am developing a gluon/Javafx application that make call to a server in order to get resources. So i thought that it would be good using Multithreading. So what we need are 2 files:

appThread.java

package com.knn.client;

import com.knnapplication.views.ExampleView;

import java.io.IOException;

import javafx.application.Platform;
import javafx.scene.control.Label;

public class appThread implements Runnable {
    Label label_view;
    Thread th;

    private Object lock = new Object();

    public Object getLock() {
        return lock;
    }

    public appThread(Label label) {
        label_view = label;
        th = new Thread(this);
        th.start();
        System.out.println("Thread start()");
    }

    public void run() {
        String risposta = "";
        try {
            ExampleView.getClient().getOut().writeObject(1);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        try {
            ExampleView.getClient().getOut().writeObject("servo.dat");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        boolean flag = true; // reading example
        do {
            try {
                risposta=ExampleView.getClient().getIn().readObject().toString();
            } catch (IOException | ClassNotFoundException  e) {
                throw new RuntimeException(e);
            }

            System.out.println(risposta);

            if (!risposta.contains("@ENDEXAMPLE")) {
                // if (attribute.class --> discrete) ??
                if (risposta.equals("@READSTRING")) { //leggo una stringa
                    label_view.setText("Inserisci valore discreto: ");
                    synchronized (lock) {
                        try {
                            lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                } else if (risposta.equals("@READOUBLE")) {
                    double x = 0.0;
                    do {
                        label_view.setText("Inserisci valore continuo");
                        synchronized (lock) {
                            try {
                                lock.wait();
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    } while (new Double(x).equals(Double.NaN));
                    // flag = false;
                }
            } else
                flag = false;
        } while (flag);
    }
}

And ExamplePresenter.java that also defines event handlers. So My idea is as it follow: I start thread during di fxml initialization (ExamplePresenter.java), after that i start writing and receiving to and from server into the run() method of appThread.java. When i find a specific situation i want to wait my thread and i want to insert a string into the TextField defined into di ExamplePresenter file. So the handler called sendExample() should notify() thread and resume the execution from the appThread.java

package com.knnapplication.views;

import com.gluonhq.charm.glisten.application.AppManager;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.TextField;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import com.knn.client.appThread;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import com.knn.client.appThread;
import java.io.IOException;


public class ExamplePresenter {
    @FXML private View exampleView;
    @FXML private Button send_sample;
    @FXML private Button start_example;
    @FXML private TextField sample_prompt;

    boolean check = false;
    Thread th;
    appThread currentThread;

    @SuppressWarnings("removal")
    public void initialize() {
        exampleView.showingProperty().addListener((obs, oldValue, newValue) -> {
            if (newValue) {
                AppBar appBar = AppManager.getInstance().getAppBar();
                appBar.setNavIcon(MaterialDesignIcon.MENU.button(e ->
                        AppManager.getInstance().getDrawer().open()));
                appBar.setTitleText("Inserisci esempio:");
                label.setText(ExampleView.getFile().toString());
            }

            currentThread = new appThread(label);

            });
    }

    @FXML private VBox _input_section;
    @FXML private Label label;

    /*
    HANDLER: questa funzione gestisce l'evento di click del pulsante
    con id "send_sample"
     */
    @FXML
    void sendExample(ActionEvent event) throws IOException {
        // check = true;
        ExampleView.getClient().getOut().writeObject(sample_prompt.getText().toString());
        synchronized (currentThread.getLock()) {
            currentThread.getLock().notify();
        }

        label.setText("Valore inserito correttamente!");
    }

    @FXML
    void startExample(ActionEvent event) throws IOException, ClassNotFoundException, InterruptedException {

    }
}

It gives me: "NOT ON FX APPLICATION THREAD", so i does not work. I've also tried in many other methods, but nothing to do. Probably i don't understand how does it work. Hope you can help me.

0009laH
  • 1,960
  • 13
  • 27
  • Your title could be more specific. – Basil Bourque Oct 15 '22 at 21:15
  • Why not a `Task` or `Service`, seen [here](https://stackoverflow.com/q/73528613/230513)? – trashgod Oct 15 '22 at 23:06
  • Ok, i would try – Luigi Daddario Oct 15 '22 at 23:19
  • But i also have to do this using threads – Luigi Daddario Oct 15 '22 at 23:20
  • 1
    A `javafx.concurrent.Task` is a `Runnable`, so you could do `new Thread(theTask)`. Note that just like how a `Thread` can only be started once, a `Task` can only be executed once. If you want a "reusable" `Task` then use a `javafx.concurrent.Service`. A `Service` has an `java.util.concurrent.Executor` that it uses to execute its `Task`s. This allows you to not only "reuse" tasks, but also reuse _threads_, so that you don't have to create a new thread each time. – Slaw Oct 16 '22 at 02:42

1 Answers1

0

When you do an update on a JavaFX component (Labels,Buttons,etc.) you should always do it on the JavaFX thread. You should use Platform.runLater() method otherwise you’ll get the error message you get.

Example: Platform.runLater(()-> { label.setText("Bla bla bla”);});

javasuns
  • 1,061
  • 2
  • 11
  • 22