I am trying to make a game with a multiplayer option in javafx using TCP/IP connection. I created a thread that handles the connections in the background so that it will listen to connections while the user plays offline. If someone tries to connect i want the thread fire a button on the main javafx application. The problem is i can't modify a UI on another thread. I tried using Task<>, platform.runlater, and Timeline to no effect.
Thread thread = new Thread(){
public void run(){
try {
int ServerPort=6779;
ServerSocket serverSocket = new ServerSocket(ServerPort);
System.out.println("waiting for player to join");
Socket connectionSocket = serverSocket.accept();
ObjectOutputStream outToServer1 = new ObjectOutputStream(connectionSocket.getOutputStream());
System.out.println("connected");
Board boardJ = new BoardM();
outToServer1.writeObject(boardJ);
boardS=boardJ;
ServerBoard.fire();
} catch (IOException ex) {
Logger.getLogger(JavaFXApplication1.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
thread.start();
The Thread is ok here. What you have to do is to wrap the fireing of the button in a Platform.runLater call.
Related
I am trying to write a simple JavaFX app which acts as an auto clicker for a game I play. I choose two Points that the mouse should click alternately. Everything works fine until the Robot needs to do his work.
When I put it like this:
robot.mouseMove(join);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
robot.mouseMove(accept);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
my App crashes. I've read things up online and it seems like you should not sleep in the JavaFX application thread. My new approach was to create a new thread that takes care of the clicking from the application thread like this:
clicker = new Clicker(join, accept);
Thread clickerThread = new Thread(clicker);
clickerThread.start();
And here how it looks in Clicker:
public void run() {
while (running){
try {
robot.mouseMove(join);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
robot.mouseMove(accept);
Thread.sleep(2000);
robot.mouseClick(MouseButton.PRIMARY);
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Clicker sleep interrupted!");
}
}
}
However with the new approach I suddenly get this error:
Exception in thread "Thread-3" java.lang.IllegalStateException: This operation is permitted on the event thread only; currentThread = Thread-3
Does anyone know how I could fix this problem?
When you want to execute a periodic foreground task on the JavaFX Application Thread you should first consider using an animation. Here's an example of using a Timeline:
Point2D join = ...;
Point2D accept = ...;
Robot robot = ...;
Timeline timeline = new Timeline(
new KeyFrame(Duration.ZERO, e -> robot.mouseMove(join)),
new KeyFrame(Duration.seconds(2), e -> robot.mouseClick(MouseButton.PRIMARY)),
new KeyFrame(Duration.seconds(4), e -> robot.mouseMove(accept)),
new KeyFrame(Duration.seconds(6), e -> robot.mouseClick(MouseButton.PRIMARY)),
new KeyFrame(Duration.seconds(8))
);
timeline.play();
The above will execute each KeyFrame's on-finished handler two seconds after the previous one (the first one immediately after the animation is started). The last KeyFrame matches your final call to sleep though it may not be necessary. All this will occur on the JavaFX Application Thread.
You can configure an animation to replay a certain number of times, or even forever, by setting its cycleCount property. For example:
timeline.setCycleCount(5); // play 5 times then stop
// or
timeline.setCycleCount(Animation.INDEFINITE); // play forever
You need to execute the mouseMove on the UI thread try wrapping the calls with Platform.runlater(() -> robot.mouseMove(MouseButton.PRIMARY));
public void run() {
while (running){
try {
Platform.runlater(() -> robot.mouseMove(join));
Thread.sleep(2000);
Platform.runlater(() -> robot. mouseClick(MouseButton.PRIMARY));
Thread.sleep(2000);
Platform.runlater(() -> robot.mouseMove(accept));
Thread.sleep(2000);
} catch (InterruptedException e) {
System.out.println("Clicker sleep interrupted!");
}
}
}
Platform.runLater() will schedule an action on the main thread and return immediately. It may take some time before the action is actually executed, in small applications this delay is usually not perceptible. If the delay were long it may happen that you schedule your action, sleep and schedule again before the first action was executed. If you want your clickerThread to wait for the action to execute before continuing then you will need some form of synchronisation, see below for an example of a method that wraps Platform.runlater() with a lock.
public void waitUntilExecutedOnMainThread(Runnable runnable){
Semaphore semaphore = new Semaphore(0);
Platform.runLater(() -> {
try {
runnable.run();
} finally {
semaphore.release();
}
});
try {
semaphore.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
waitUntilExecutedOnMainThread(() -> robot. mouseClick(MouseButton.PRIMARY))
The project is a chat program with a multi-threaded server to handle multiple clients. The code below is server-side for the thread that begins once a client connects. The ConnectionHandler takes a connected clients socket and 'ID'.
The static "broadcast" method called in run() is not relevant to the question as well as both functions in the finally clause.
I have been working on the project on both a Windows 10 desktop, and an XPS laptop running Ubuntu 18.04.
Client disconnection is handled once the IOException is caught in the run() method. This works as designed on Windows, however for Ubuntu that is not the case. When exiting the GUI client it seems like only the exception is caught on Windows and doesn't happen on Ubuntu. Thus rendering the server non-working for Linux and working perfectly on Windows.
Is this not a well practiced method to handle a client disconnection in general? Or is it something else that I need to change in order for this to work on Linux? I have no idea what to do because I'm not sure if it's an error in my code or it's just the way Linux handles Java versus Windows?
Any help or tips is appreciated. Thanks in advance.
class ConnectionHandler implements Runnable
{
//Begin declarations for new client thread
int clientId;
Socket connection;
BufferedReader reader;
BufferedWriter writer;
String message;
//end declarations for new client thread
public ConnectionHandler(int clientId, Socket connection)
{
this.clientId = clientId;
this.connection = connection;
}
#Override
public void run()
{
try
{
reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));
}
catch (IOException e)
{
e.printStackTrace();
}
try
{
while (true)
{
message = reader.readLine();
if (message != null)
{
System.out.println("Message from " + message);
CrosstalkServer.broadcast(message);
}
}
}
catch (IOException e)
{
System.out.println("Client has disconnected. Recycling client ID: " + clientId);
}
finally
{
//Close the reader, writer, and socket.
terminateClient();
//Client has disconnected, handle client count and recycle client ID
CrosstalkServer.recycleClientId(this);
}
}
Edit: I tested the program on Windows 10, Windows 7, and Ubuntu 18.04. After some testing, it is the client side causing the problem. I ran the server on my Ubuntu laptop, and tested a Windows 7 client along with a Windows 10 clients. The Windows 7 client did not cause an IOException to be thrown, while Windows 10 did. Ubuntu client-side does not cause the IOException either.. What is a better way to determine a client disconnection? Start a thread to monitor by attempting to constantly write to each client in my client arraylist?
I've coded a client program that communicates with my arduino server. It had a swing button and a methog that ran a loop checking for any input from the server. I tried it with multiple instances running from different or/and the same IP and everything was fine. Now I tried implementing that same method for the socket in a app with JavaFX GUI. After I read here and there that it needs to be on a separate thread I did it as instructed and it seems to be working just fine. If I try to launch a second instance of it though,it imidiately throws NullPointerException on the line where i check socket.isConnected() && !Socket.isClosed(). The first instance continues to work just fine, but the other one just stays with the GUI open.
As I've done it with the same class but not on a new thread and with swing button, I can say that the problem is not on the server side.
I need to be able to launch as many instances of the program as I want while they all keep an open socket at all times. Any ideas on how to fix that ?
Update: I tryed recalling the initiation in the loop when socket is lost. It seems that the socket closes right after it is opened.
Here is the Class for the client:
package panelSouth;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class Networking implements Runnable{
static Socket socket;
static OutputStreamWriter out;
public void run() {
//Initializing socket - IP/PORT
String host = "192.168.1.178";
int port = 2015;
boolean connected=true;
do{
try{
socket = new Socket(host,port);
}
catch(Exception unknownHostException){
connected=false;
System.out.println("Connecting to host...");
}
}while(connected==true);
System.out.println("Connection is a success!");
System.out.println("Requesting pin states...");
//Requesting pin states on startup.
try{
out = new OutputStreamWriter(socket.getOutputStream());
out.write("r;");
out.flush();
}catch(Exception ex){
System.out.println(ex);
}
listen();
}
//Listening for incoming commands from host
public static void listen(){
try{
BufferedReader in = new BufferedReader(
new InputStreamReader(
socket.getInputStream() ) );
while(socket.isConnected() && !socket.isClosed()){
States.commandProcess(in.readLine());
}
}catch(Exception ex){
System.out.println(ex);
}
}
//send commands.
static public void send(String command){
try{
out.write(command);
out.flush();
}catch(Exception ex){
System.out.println(ex);
}
}
//closing the socket and resetting the pins on host on close up.
static public void close(){
try{
OutputStreamWriter out = new OutputStreamWriter(socket.getOutputStream());
out.write("x;");
out.flush();
socket.close();
}catch(Exception exception){
}
}
}
And here is the Main:
public static void main(String[] args) throws Exception{
Thread network = new Thread(new Networking());
network.setDaemon(true);
network.start();
launch(args);
}
I removed the loops in the defining of the socket and I put recall of the function only in the catch{} part. It seems that the loop was defining more than one socket or something and when I was actually sending data to the socket, it was another socket. Also I changed the thread handling and made it with Task which seems to work a lot better with JavaFX scene.
OK, so I'm a bit new to SwingWorker in Java.
I've built a Java GUI that, when the "Start" button is pressed, launches several SwingWorker threads. The first thread simply keeps track of run time and updates the GUI appropriately. The second one plays a series of sounds files. The third (and problematic) thread should monitor the serial port for incoming data to be manipulated later on down the road. All of these threads will be running for a while, hence them being SwingWorkers.
I am using the jSSC library (https://code.google.com/p/java-simple-serial-connector/wiki/jSSC_examples) to read data from the serial port, and it does so by firing an eventListener.
My question: Is it redundant/inelegant to code an EventListener inside of a SwingWorker thread? And if so, is there a better way to go about this?
Here is a bit of my code:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
SerialPort serialPort = findPort(); // returns a serialport I can use to read data from.
SwingWorker worker1 = new SwingWorker<Void, Void>(){
#Override
protected Void doInBackground() throws Exception {
long elapsedTime, startTime = System.currentTimeMillis();
while (true){
Thread.sleep(1000);
elapsedTime = (System.currentTimeMillis() - startTime)/1000;
jTimeField.setText(String.format("%02d:%02d:%02d", elapsedTime/3600, (elapsedTime%3600)/60, elapsedTime%60));
if (isCancelled()){} /* Check if thread has been canceled */
}
}
};
SwingWorker worker2 = new SwingWorker<Void, Void>(){
#Override
protected Void doInBackground() throws Exception {
// This Thread: Plays music files; Self terminates; On termination also terminates worker 1 and 3 via cancel().
}
};
SwingWorker worker3 = new SwingWorker<Void, Void>(){
#Override
protected Void doInBackground() throws Exception {
serialPort.addEventListener(new SerialPortReader());
return null;
}
class SerialPortReader implements SerialPortEventListener {
#Override
public void serialEvent(SerialPortEvent event) {
byte buffer[];
if (event.isRXCHAR() && event.getEventValue() > 0){
buffer = serialPort.readBytes();
for (byte b: buffer){
// Do stuff with incoming data
}
}
}
}
};
}
Any and all constructive criticism is appreciated.
It does not do any good to add the event listener in your swingworker thread and then return once that's done. Why not just add the listener from your EDT and, if it takes long to process events, fire off processing threads from there? Listening to events can't be blocking, that would defeat the entire Observer pattern.
I have a problem while working with JavaFX and Threads. Basically I have two options: working with Tasks or Platform.runLater. As I understand Platform.runLater should be used for simple/short tasks, and Task for the longer ones. However, I cannot use any of them.
When I call Thread, it has to pop up a captcha dialog in a middle of task. While using Task, it ignores my request to show new dialog... It does not let me to create a new stage.
On the other hand, when I use Platform.runLater, it lets me show a dialog, however, the program's main window freezes until the pop up dialog is showed.
I need any kind of solution for this. If anyone knows how to deal with this or had some similar experience and found a solution I am looking forward to hearing from you!
As puce says, you have to use Task or Service for the things that you need to do in background. And Platform.runLater to do things in the JavaFX Application thread from the background thread.
You have to synchronize them, and one of the ways to do that is using the class CountDownLatch.
Here is an example:
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
return null;
}
};
}
};
service.start();
Use a Worker (Task, Service) from the JavaFX Application thread if you want to do something in the background.
http://docs.oracle.com/javafx/2/api/javafx/concurrent/package-summary.html
Use Platform.runLater from a background thread if you want to do something on the JavaFX Application thread.
http://docs.oracle.com/javafx/2/api/javafx/application/Platform.html#runLater%28java.lang.Runnable%29
It's too late to answer but for those who have the error, here is the solution XD
You can use one Thread.
Use the lambda expression for the runnable in the thread and the runlater.
Thread t = new Thread(() -> {
//Here write all actions that you want execute on background
Platform.runLater(() -> {
//Here the actions that use the gui where is finished the actions on background.
});
});
t.start();
You can user directly this code
Don't forget you can't send non-final variable in thread .
you can send final variable in thread
//final String me="ddddd";
new Thread(new Runnable() {
#Override
public void run() {
// me = me + "eee";
//...Your code....
}
}).start();
Use in
your code
try/catch