Reputation: 355
we are developing a client-server application which has to work both with GUI and CLI. We have no problem with the CLI but we are struggling to implment it with JavaFX:
our server send some objects to the client (via socket) and these have to be processed.
This is our SocketServerListener (and writer):
public class SockeServerListener extends Thread implements ServerListener{
private CliController controller;
private ObjectInputStream in;
private ObjectOutputStream out;
public SocketServerListener(Socket server, CliController controller) throws UnknownHostException, IOException {
this.controller = controller;
this.out = new ObjectOutputStream(server.getOutputStream());
this.in = new ObjectInputStream(server.getInputStream());
}
public void publishMessage(String message) throws IOException, RemoteException {
out.writeObject(message);
out.flush();
}
public void run() {
try {
while (true) {
Dialogue dialogue = (Dialogue) in.readObject();
controller.parseDialogue(dialogue);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The SocketServerListener is instantiated by the controller which is the one who executes the who "executes" the received object, updating the interface (Cli/GUI)
public void parseDialogue(Dialogue dialog) {
dialog.execute(view); //view is an interface extended by both the Cli and GUI
this.canWrite = true;
}
As I said, this works very well with the CLI, but it throws an exception with JavaFX
Exception in thread "Thread-7" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-7
We tried to use the Class used to generate all the GUI as controller, but without any (positive) result. How can we instantiate a thread so that it can work with JavaFX and call the methods that show the screens we need?
Thank you
Upvotes: 0
Views: 1415
Reputation: 209653
Presumably the call to controller.parseDialogue(dialogue);
is updating the UI. You can only do this on the FX Application Thread. You can schedule a runnable to execute on the FX Application Thread using Platform.runLater()
:
Platform.runLater( () -> controller.parseDialogue(dialogue) );
Note that if you don't know you are executing this code in a context in which the FX toolkit has been started, the call to Platform.runLater(...)
should be made in the controller instead, e.g.
public class NonGuiController implements CliController {
@Override
public void parseDialog(Dialogue dialogue) {
// regular code here...
}
}
and
public class GuiController implements CliController {
@Override
public void parseDialogue(Dialogue dialogue) {
// some preliminary work (still on background thread here) if necessary...
Platform.runLater(() -> {
// code that updates UI here...
});
}
}
and revert to the original code in your socket listener class.
Upvotes: 1
Reputation: 38142
Not on FX application thread
gives you the cause of the issue.
According to the Javadoc of the Node class:
Node objects may be constructed and modified on any thread as long they are not yet attached to a Scene in a Window that is showing. An application must attach nodes to such a Scene or modify them on the JavaFX Application Thread.
Use Platform.runLater to execute code on the FX application thread and also have a look at the javafx.concurrent package for further utility classes.
Upvotes: 2