I've got client-server application and the client has two threads, one for sending informations to server and the other, which should show changing window, but i get errors. I've read something about Platform.runlater, but I don't know how to use it. Here's the class with the window:
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class B implements Runnable{
private int counter = 0, lg;
private double x_1, x_2, y_1, y_2;
int [] bts = new int[2];
Button[] change_bts = new Button[2];
Button [] all_bts = new Button[221];
public void run() {
Group grupa = new Group();
int x = 0;
int ctr = 1;
for (int i = 0; i < 17; ++i) {
for (int j = 0; j < 13; ++j) {
if ( i%2 == 1) { x = 30; }
else { x = 0; }
Button bt = new Button();
bt.setLayoutX(x+30+j*60); bt.setLayoutY(30+i*60);
bt.setOnAction(
event -> {
if((bt.getText()!="0")) {
if ((counter == 1)) {
change_bts[counter] = bt;
bts[0] = Integer.parseInt(change_bts[0].getText());
bts[1] = Integer.parseInt(change_bts[1].getText());
}
else if (counter == 0) {
change_bts[counter] = bt;
counter++;
}
}
System.out.println(bt.getText());
}
);
all_bts[ctr-1] = bt;
ctr ++;
}
}
grupa.getChildren().addAll(all_bts);
Scene tsc = new Scene(grupa, 1100, 1200);
Stage tst = new Stage(); //New window (Stage)
tst.setScene(tsc);
tst.show();
}
}
And here is the class, which creates new threads:
import javafx.application.Application;
import javafx.stage.Stage;
import java.io.IOException;
public class Clients extends Application {
public static void main(String[] args) { launch(args);}
public void start(final Stage first_stage) throws IOException, InterruptedException {
Names n = new Names (); // this Class' constructor calls gogo() method below
}
public static void gogo(String a) {
Runnable[] runners = new Runnable[2];
Thread[] threads = new Thread[2];
runners[0] = new B();
runners[1] = new Another_Class();
threads[0] = new Thread(runners[0]);
threads[1] = new Thread(runners[1]);
threads[0].start();
threads[1].start();
}
}
please, help :<
As @Eggplant correctly pointed out that Thread class objects are not allowed to manipulate JavaFx UI Components and all UI components must be manipulated using JavaFx thread. What Platform.runLater does is it schedules your UI changes in the running JavaFx thread. Use it like this:
Platform.runLater(() -> {
//your UI manipulation code here...
});
You can actually use this bit of code from other "Thread" instances to delegate UI manipulation to actual JavaFx thread.
Consider encapsulating the information needed by the client in a separate class (typically referred to as model).
The client (the view) should respond to changes in the model. In the following example it does so by binding.
Now you can use a thread to update the model :
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class Clients extends Application {
public static void main(String[] args) { launch(args);}
@Override
public void start(final Stage first_stage) throws IOException, InterruptedException {
Model model = new Model();
Button run = new Button("Run");
run.setOnAction(e -> {
gogo(model);
run.setDisable(true);
});
Label counter = new Label();
counter.textProperty().bind(model.getCounterProperty().asString());
BorderPane root = new BorderPane(counter);
root.setBottom(run);
Scene scene = new Scene(root);
first_stage.setScene(scene);
first_stage.show();
}
private void gogo(Model model) {
//thread manipulates model
new Thread(new Updater(model)).start();
}
}
class Updater implements Runnable{
private final Model model;
private int counter = 0;
private boolean stop = false;
public Updater(Model model) {
this.model = model;
}
@Override
public void run() {
while (! stop){
model.setCounter(++counter);
try {
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException ex) { ex.printStackTrace();}
}
}
void setStop(boolean stop) {this.stop = stop; }
}
//use a model to encapsulate information needed for the view
class Model {
private final SimpleIntegerProperty counterProperty = new SimpleIntegerProperty(0);
SimpleIntegerProperty getCounterProperty() { return counterProperty; }
//use `Platform.runLater` to allow update from non javafx thread
//if updated by more than one thread it needs to be synchronized
void setCounter(int value) {
Platform.runLater(() -> counterProperty.set(value) );
}
}
Here is a quick example to show you how to use Platform.runLater(()-> ...);
I tried to keep it similar to your application but mine is dumbed down I added some comments in there as well
public class Main extends Application {
@Override
public void start(Stage stage) throws Exception{
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
for (int i = 0; i < 3; i++) {
//Create new class with Runnable Implemented
IncrementingButton button = new IncrementingButton();
vBox.getChildren().add(button.getButton());
//Start Thread
new Thread(button).start();
}
stage = new Stage();
stage.setScene(new Scene(vBox, 100, 100));
stage.setAlwaysOnTop(true);
stage.show();
}
public static void main(String[] args) { launch(args); }
class IncrementingButton implements Runnable{
int count = 0;
private Button button = new Button();
private Button getButton(){ return button; }
@Override
public void run(){
while (count != 10){
//Update Button Text
Platform.runLater(()-> button.setText("Count:"+count));
//Sleep for variation
try {
Thread.sleep((long)((Math.random() * 3)+1)*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
//Update Button Text
Platform.runLater(()-> button.setText("DONE"));
}
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.