Im working on Javafx. I have created an echo ServerClient system i.e Sending data to server and back to all clients(broadcast). It works fine when Client sends data to Server. But the frame freezes when Server sends the data back to Client. Here is the code:
Client:
/*
* 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 com.rajeshpatkar;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author Dimpi
*/
public class Client extends Application{
int flag = 999;
public void start(Stage primaryStage) throws Exception {
Connect cnn = new Connect(primaryStage);
cnn.sconnect();
}
public static TextArea Frame(Stage primaryStage, PrintWriter nos, BufferedReader nis) throws IOException {
TextField tf = new TextField();
TextArea ta = new TextArea();
Button btn = new Button();
btn.setText("Click");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
String get = tf.getText();
nos.println(get);
try {
Connect.chat(nis,ta);
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
BorderPane root = new BorderPane();
root.setCenter(ta);
BorderPane panel = new BorderPane();
root.setBottom(panel);
panel.setCenter(tf);
panel.setRight(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
return ta;
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
class Connect {
Stage primaryStage;
Connect(Stage primaryStage) {
this.primaryStage = primaryStage;
}
public void sconnect() throws IOException {
System.out.println("Client Signing IN");
Socket soc = new Socket("localhost", 9081);
PrintWriter nos = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(soc.getOutputStream()
)
), true);
BufferedReader nis = new BufferedReader(
new InputStreamReader(soc.getInputStream()
)
);
TextArea ta=Client.Frame(primaryStage, nos, nis);
}
public static void chat(BufferedReader nis,TextArea ta) throws IOException{
String set = nis.readLine();
while (!set.equals("End")) {
ta.appendText(set+"\n");
set = nis.readLine();
}
}
}
Server: /*
* 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 com.rajeshpatkar;
import static com.rajeshpatkar.Server.a1;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
/**
*
* #author Dimpi
*/
public class Server extends Application {
public static ArrayList<PrintWriter> a1=new ArrayList<PrintWriter>();
#Override
public void start(Stage primaryStage) throws IOException {
System.out.println("Server signing IN");
ServerSocket ss = new ServerSocket(9081);
for (int i = 0; i < 5; i++) {
Socket soc = ss.accept();
Conversation c = new Conversation(soc);
c.start();
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
class Conversation extends Thread {
Socket soc;
Conversation(Socket soc) {
this.soc = soc;
}
public void run() {
try {
PrintWriter nos = new PrintWriter(
new BufferedWriter(
new OutputStreamWriter(soc.getOutputStream()
)
), true);
BufferedReader nis = new BufferedReader(
new InputStreamReader(soc.getInputStream()
)
);
Server.a1.add(nos);
String get=nis.readLine();
while(true){
for(PrintWriter p:a1){
System.out.println(get);
p.println(get);
}
get=nis.readLine();
}
} catch (Exception e) {
}
}
}
the issue of freezing the client-ui is caused your method: chat(). which is called by your button. it contains the method readLine() of BufferedReader which will wait for an input to happen. this wait will cause your freeze since it happens on the Application Thread.
so what you can do is: on your button-eventhandler: only write output:
String get = tf.getText();
nos.println(get);
but add a Thread which will update your TextArea if your InputStream receives an input, e.g. like this:
static void handleInput(BufferedReader nis, TextArea ta) throws IOException {
final Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
String output;
while ((output = nis.readLine()) != null) {
final String value = output;
Platform.runLater(new Runnable() {
#Override
public void run() {
ta.appendText(value + System.getProperty("line.separator"));
}
});
}
return null;
}
};
new Thread(task).start();
}
and call that method once:
handleInput(nis, ta);
Related
I have a function named doWrite, which is basically representing the action of a button.
In this function, inside the for loop, txtShow.setText(st.toString()) is not showing any data on GUI, but the same thing is visible on console using System.out.println,
I have also used txtShow.setText at the end of the function to print "block written successfully" but this is displayed on GUI successfully.
I want to know why it is not working in for loop.
Part of Controller code:
#FXML
void doWrite(ActionEvent event) throws IOException, InterruptedException {
//txtShow.setText("Scan your card");
OutputStream os=s1.getOutputStream();
String messageString ="%"+txtBlock.getText()+txtData.getText();
os.write(messageString.getBytes());
//System.out.println(messageString);
os.flush();
os.close();
Thread.sleep(2000);
InputStream is=s1.getInputStream();
StringBuilder st = new StringBuilder();
for(int i=0,x=0;true;i++){
char a=(char)is.read();
if(a == '#'){
txtShow.setText(st.toString());
System.out.print(st.toString());
st.setLength(0);
Thread.sleep(5000);
continue;
}
if(a == '*')
{
break;
}
st=st.append(a);
}
System.out.print( st.toString());
txtShow.setText("Block written successfully");
//doAlert("Block written successfully !");
}
Main code:
package Cards;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import com.fazecast.jSerialComm.SerialPort;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
public class cardMain extends Application {
//static boolean x=true;
#Override
public void start(Stage primaryStage) {
try {
Parent root=FXMLLoader.load(getClass().getResource("card.fxml"));
Scene scene = new Scene(root);
scene.setFill(Color.NAVY);
primaryStage.setTitle("Student Registration");
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException, InterruptedException{
launch(args);
}
}
I have made a progress bar in javafx. There is a cancel Button by default. I just want to disable this cancel button when my task got completed.
jobProgressView.setGraphicFactory(task -> {
return new Button("save");
});
Without more code, I'm only able to make a guess. Even your added code isn't enough to know all things from your implementation.
So this solution assumes, that you have a Task that is running and showing it's progress on a Progressbar. The Task here is wrapped in a service, which can be restarted (maybe you also need this?).
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class CancelButtonDemo extends Application {
Service<Integer> service = new MyService();
#Override
public void start(Stage primaryStage) {
Button start = new Button();
Button cancel = new Button();
ProgressBar progress = new ProgressBar(0);
start.setText("Run Task");
start.setOnAction((ActionEvent event) -> {
if (!(service.getState().equals(Worker.State.READY))) {
service.reset();
}
progress.progressProperty().bind(service.progressProperty());
service.start();
});
start.disableProperty().bind(service.runningProperty());
cancel.setText("Cancel Task");
cancel.setOnAction((ActionEvent event) -> {
service.cancel();
progress.progressProperty().unbind();
progress.setProgress(0);
});
cancel.disableProperty().bind(Bindings.not(service.runningProperty()));
VBox root = new VBox(20);
root.setAlignment(Pos.CENTER);
root.getChildren().addAll(start, progress, cancel);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Cancel Button Demo");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
class MyService extends Service<Integer> {
#Override
protected Task<Integer> createTask() {
return new Task<Integer>() {
#Override
protected Integer call() throws Exception {
int iterations;
for (iterations = 0; iterations < 10000000; iterations++) {
if (isCancelled()) {
updateMessage("Cancelled");
break;
}
updateMessage("Iteration " + iterations);
updateProgress(iterations, 10000000);
}
return iterations;
}
};
}
}
}
The above application looks like this:
I want to move to next stage after Timer but when I run the page is frozen.
I want some help please to resolve this problem, I'm new in JavaFX .
I want to go to next screen after a specific time that I choose because this screen is a load screen
this is my code:
/*
* 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 chapitreapp;
import ressources.FadeInLeftTransition;
import ressources.FadeInRightTransition;
import ressources.FadeInTransition;
import ressources.config;
import ressources.config2;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.concurrent.TimeUnit;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.concurrent.WorkerStateEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import org.springframework.beans.*;
import org.springframework.context.*;
/**
* FXML Controller class
*
* #author anas
*/
public class LoadController implements Initializable {
#FXML
private Text lblWelcome;
#FXML
private Text lblRudy;
#FXML
private VBox vboxBottom;
#FXML
private Label lblClose;
Stage stage;
#FXML
private ImageView imgLoading;
/**
* Initializes the controller class.
* #param url
* #param rb
*/
#Override
public void initialize(URL url, ResourceBundle rb) {
longStart();
lblClose.setOnMouseClicked((MouseEvent event) -> {
Platform.exit();
System.exit(0);
});
// TODO
}
private void longStart() {
Service<ApplicationContext> service = new Service<ApplicationContext>() {
#Override
protected Task<ApplicationContext> createTask() {
return new Task<ApplicationContext>() {
#Override
protected ApplicationContext call() throws Exception {
ApplicationContext appContex = config.getInstance().getApplicationContext();
int max = appContex.getBeanDefinitionCount();
updateProgress(0, max);
for (int k = 0; k < max; k++) {
try
{
Thread.sleep(50);
updateProgress(k+1, max);
}
catch(InterruptedException e)
{
System.exit(0);
}
}
return appContex;
}
};
}
};
service.start();
service.setOnRunning((WorkerStateEvent event) -> {
new FadeInLeftTransition(lblWelcome).play();
new FadeInRightTransition(lblRudy).play();
new FadeInTransition(vboxBottom).play();
});
service.setOnSucceeded((WorkerStateEvent event) -> {
config2 config = new config2();
config.newStage(stage, lblClose, "/chapitreapp/FXMLDocument.fxml", "Sample Apps", true, StageStyle.UNDECORATED, false);
});
}
}
where did I go wrong?
Something along these lines, in your onSucceeded event handler, or a method that it calls...
try {
URL url = this.getClass().getResource("nextScene.fxml");
if (url != null) {
FXMLLoader loader = new FXMLLoader(url);
Parent root = loader.load(url);
Scene newScene = new Scene(root);
this.getStage().setScene(newScene);
} else {
System.out.println("URL was null");
}
} catch (Exception e) {
System.out.println(e);
}
In your controller, you will need to have some means of setting the stage, either via a constructor that accepts the Stage object or via a setStage() method. I've used a getStage() method above to access the Stage and set the new Scene object on it.
You could also use the static FXMLLoader load method: Parent root = FXMLLoader.load(url);
This may also be of benefit: https://blogs.oracle.com/acaicedo/entry/managing_multiple_screens_in_javafx1
This is my sample code, In my project I have used scroll pane, but i am click outside of node and use arrow keys that nodes are move to Center,left,right,bottom.how to lock the node in same position,
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ComboBoxEditable extends Application {
Node sub;
#Override
public void start(Stage primaryStage) {
ComboBox mainCombo = new ComboBox(listofCombo());
Button save = new Button("Save");
sub = new ComboBox(listofCombo());
HBox root = new HBox(20);
root.getChildren().addAll(mainCombo, sub,save);
ScrollPane pane = new ScrollPane(root);
mainCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == "Others") {
sub = new TextField();
} else {
sub = new ComboBox(listofCombo());
}
root.getChildren().remove(1);
root.getChildren().add(1, sub);
}
});
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(mainCombo.getValue());
if(sub.getClass() == ComboBox.class) {
ComboBox sub1 = (ComboBox)sub;
System.out.println(sub1.getValue());
} else {
TextField field = (TextField)sub;
System.out.println(field.getText());
}
}
});
Scene scene = new Scene(pane, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ObservableList listofCombo() {
ObservableList<String> list = FXCollections.observableArrayList();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf("Hello" + i));
}
list.add("Others");
return list;
}
}
I am ref this example code :JavaFX: scrolling vs. focus traversal with arrow keys
#James_D told "The default behavior for a scroll pane is that, if it has keyboard focus, the cursor (arrow) keys will cause it to scroll".So consume that event Ref for this solution JavaFX: scrolling vs. focus traversal with arrow keys
/*
* 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 comboboxeditable;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ComboBoxEditable extends Application {
Node sub;
#Override
public void start(Stage primaryStage) {
ComboBox mainCombo = new ComboBox(listofCombo());
Button save = new Button("Save");
sub = new ComboBox(listofCombo());
HBox root = new HBox(20);
root.getChildren().addAll(mainCombo, sub, save);
ScrollInterceptor pane = new ScrollInterceptor(root);
mainCombo.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observable, Object oldValue, Object newValue) {
if (newValue == "Others") {
sub = new TextField();
} else {
sub = new ComboBox(listofCombo());
}
root.getChildren().remove(1);
root.getChildren().add(1, sub);
}
});
save.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(mainCombo.getValue());
if (sub.getClass() == ComboBox.class) {
ComboBox sub1 = (ComboBox) sub;
System.out.println(sub1.getValue());
} else {
TextField field = (TextField) sub;
System.out.println(field.getText());
}
}
});
Scene scene = new Scene(pane, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
public ObservableList listofCombo() {
ObservableList<String> list = FXCollections.observableArrayList();
for (int i = 0; i < 10; i++) {
list.add(String.valueOf("Hello" + i));
}
list.add("Others");
return list;
}
private static class ScrollInterceptor extends ScrollPane {
public ScrollInterceptor() {
remapArrowKeys(this);
}
public ScrollInterceptor(Node content) {
ScrollInterceptor.this.setContent(content);
remapArrowKeys(this);
}
private void remapArrowKeys(ScrollPane scrollPane) {
scrollPane.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case UP:
case DOWN:
case LEFT:
case RIGHT:
event.consume();
}
}
});
}
}
}
Is there a way to get all running Tasks and Services in JavaFX application?
I would like to display the running Tasks in a List.
brian's answer is the way to go. If you have multiple places you are creating Tasks, this might get a bit tricky to manage. The following shows a way to encapsulate everything into an implementation of Executor. Note that I'm still doing exactly as brian suggests: adding Tasks to a List and removing them when they're complete; I just manage it all in an Executor so that the code to modify the list is all in one place.
MonitoringExecutor.java:
import java.util.concurrent.Executor;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
/**
* Wraps an Executor and exposes an ObservableList of Workers which have been
* executed but have not completed. (Workers are considered completed if they
* exit a RUNNING state; i.e. they are in a SUCCEEDED, FAILED, or CANCELLED state.)
*
*/
public class MonitoringExecutor implements Executor {
private final Executor exec ;
private final ObservableList<Worker<?>> taskList ;
public MonitoringExecutor(Executor exec) {
this.exec = exec;
this.taskList = FXCollections.observableArrayList();
}
#Override
public void execute(Runnable command) {
if (command instanceof Worker) {
final Worker<?> task = (Worker<?>) command ;
task.stateProperty().addListener(new ChangeListener<State>() {
#Override
public void changed(ObservableValue<? extends State> obs,
State oldState, State newState) {
if (oldState == State.RUNNING) {
taskList.remove(task);
}
}
});
taskList.add(task);
}
exec.execute(command);
}
public ObservableList<Worker<?>> getWorkerList() {
return taskList;
}
}
And here's an example of using it:
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.concurrent.Task;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TaskMonitor extends Application {
#Override
public void start(Stage primaryStage) {
final IntegerProperty tasksCreated = new SimpleIntegerProperty(0);
final ThreadFactory threadFactory = new ThreadFactory() {
#Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
}
};
final MonitoringExecutor exec = new MonitoringExecutor(Executors.newFixedThreadPool(5, threadFactory));
final TableView<Worker<?>> taskTable = createTable();
taskTable.setItems(exec.getWorkerList());
final Button newTaskButton = new Button();
newTaskButton.textProperty().bind(Bindings.format("Create task %d", tasksCreated.add(1)));
newTaskButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
tasksCreated.set(tasksCreated.get()+1);
exec.execute(new CountingTask("Task "+tasksCreated.get()));
}
});
final BorderPane root = new BorderPane();
root.setCenter(taskTable);
final HBox controls = new HBox();
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
controls.getChildren().add(newTaskButton);
root.setBottom(controls);
final Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView<Worker<?>> createTable() {
final TableView<Worker<?>> taskTable = new TableView<>();
final TableColumn<Worker<?>, String> titleCol = new TableColumn<>("Title");
titleCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, String>("title"));
final TableColumn<Worker<?>, Double> progressCol = new TableColumn<>("Progress");
progressCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, Double>("progress"));
progressCol.setCellFactory(new Callback<TableColumn<Worker<?>, Double>, TableCell<Worker<?>, Double>>() {
#Override
public TableCell<Worker<?>, Double> call(TableColumn<Worker<?>, Double> col) {
return new ProgressTabelCell();
}
});
final TableColumn<Worker<?>, State> stateCol = new TableColumn<>("State");
stateCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, State>("state"));
final TableColumn<Worker<?>, String> messageCol = new TableColumn<>("Message");
messageCol.setCellValueFactory(new PropertyValueFactory<Worker<?>, String>("message"));
messageCol.setPrefWidth(200);
taskTable.getColumns().addAll(Arrays.asList(titleCol, progressCol, stateCol, messageCol));
return taskTable;
}
private static class CountingTask extends Task<Void> {
private CountingTask(String title) {
updateTitle(title);
}
#Override
protected Void call() throws Exception {
final int n = new Random().nextInt(100)+100;
for (int i=0; i<n; i++) {
updateProgress(i, n);
updateMessage(String.format("Count is %d (of %d)", i, n));
Thread.sleep(100);
}
return null;
}
}
private static class ProgressTabelCell extends TableCell<Worker<?>, Double> {
final ProgressBar progressBar = new ProgressBar();
#Override
public void updateItem(Double value, boolean empty) {
if (empty || value == null) {
setGraphic(null);
} else {
setGraphic(progressBar);
progressBar.setProgress(value);
}
}
}
public static void main(String[] args) {
launch(args);
}
}
Just add and remove them from a list as needed. Then you can show them in a list. Here's some pieces of code.
ObservableList<String> runningTasks;
runningTasks.add(task.getTitle());
new Thread(task).start();
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
runningTasks.remove(task.getTitle());
}});