JavaFX textArea.setText not working in loop - javafx

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);
}
}

Related

BufferedReader freezes the UI in Javafx

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);

How does the graphic inside a Javafx ListCell catch MouseEvents?

I have a custom ListCell with a ImageView as the graphic. I want this ImageView to catch MouseEvents (like mouse_over, or mouse_click). But it does not catch any events.
The custom ListCell however catches events.
Is this unusual behaviour or do I need to pass the Events from the ListCell to its graphic (somehow)?
If I add a Button, it gets Mouseevents, strangely.
If you have just a link of a working example, I would happily crawl my way through it ;)
Thanks for your effort.
Class CustomCell:
package test;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
public class CustomCell extends ListCell<String>{
ImageView removeTrack;
public CustomCell(){
removeTrack = new ImageView("https://lh3.googleusercontent.com/-lbN1Ca63JPs/AAAAAAAAAAI/AAAAAAAAAAQ/smvshnyosS4/s46-c-k/photo.jpg");
removeTrack.setOnMouseClicked(e -> {
System.out.println("test");
});
}
#Override
protected void updateItem(String t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t);
setGraphic(removeTrack);
setContentDisplay(ContentDisplay.RIGHT);
addEventFilter(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
removeTrack.setVisible(true);
}
});
addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
removeTrack.setVisible(false);
}
});
}
}
}
Main-Class:
package test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Scanner;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.stage.Stage;
import javafx.util.Callback;
public class JAVAtest extends Application{
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
ObservableList<String> names = FXCollections.observableArrayList(
"Julia", "Ian", "Sue", "Matthew", "Hannah", "Stephan", "Denise");
ListView lv = new ListView(names);
lv.setCellFactory(new Callback<ListView<String>, ListCell<String>>(){
#Override
public ListCell<String> call(ListView<String> p) {
return new CustomCell();
}
});
Scene scene = new Scene(lv);
stage.setScene(scene);
stage.show();
}
}
Well.. I can't see why your code isn't working. Seems like a bug.
It works fine if you wrap the image view in a container of some kind. For example:
import javafx.event.EventHandler;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.ListCell;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
public class CustomCell extends ListCell<String> {
ImageView removeTrack;
StackPane imageContainer ;
public CustomCell() {
removeTrack = new ImageView(
"https://lh3.googleusercontent.com/-lbN1Ca63JPs/AAAAAAAAAAI/AAAAAAAAAAQ/smvshnyosS4/s46-c-k/photo.jpg");
removeTrack.setOnMouseClicked(e -> {
System.out.println("test");
});
imageContainer = new StackPane(removeTrack);
}
#Override
protected void updateItem(String t, boolean bln) {
super.updateItem(t, bln);
if (t != null) {
setText(t);
setGraphic(imageContainer);
setContentDisplay(ContentDisplay.RIGHT);
addEventFilter(MouseEvent.MOUSE_MOVED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
imageContainer.setVisible(true);
}
});
addEventFilter(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
imageContainer.setVisible(false);
}
});
} else {
setText(null);
setGraphic(null);
}
}
}
(As an aside: always handle all possible cases in the updateItem(...) method. Your code will have bugs if you start removing items or possibly while scrolling, because you don't handle the empty cell / null item case.)

JavaFX - Control and Concurrency

I have a sample Hello World JavaFx. I am using Eclipse and eFxclipse plugin. My Eclipse is kepler which is Eclipse 4.3.2 version and Java servion is Jdk1.7-045.
What I try to add is very little concurrency codes, I just want to update button text in the example. Could this backend task interact with upfront UI control, for example button, scene? If not, how could I make tailored backend task, then interact with UI control?
Thanks in advance
package com.juhani.fx.exer;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application{
private static final short COREPOOLSIZE=2;
private static final short MAXIMUMPOOLSIZE=2;
private static final int WORKQUEUECAPACITY=100;
private static Logger log = LogManager.getLogger(
HelloWorld.class.getName());
private ExecutorService executors = new ThreadPoolExecutor(COREPOOLSIZE,MAXIMUMPOOLSIZE,20,TimeUnit.MINUTES,new ArrayBlockingQueue<Runnable>(WORKQUEUECAPACITY));
public static void main(String[] args) {
LogMessage logMessage = new LogMessage("BEGIN",1.0,1,"HELLOWORLD");
log.trace(logMessage.toString());
launch(args);
}
#Override
public void start(final Stage primaryStage) throws InterruptedException {
primaryStage.setTitle("Hello World!");
final Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
final StackPane root = new StackPane();
root.getChildren().add(btn);
final Scene scene= new Scene(root,300,250);
primaryStage.setScene(scene);
primaryStage.show();
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
for(int i=0;i<20;i++){
btn.setText("First row\nSecond row "+i);
primaryStage.show();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
log.error(new LogMessage("entering interruption",1.0,2,"exception").toString());
}
}
return new Boolean(true);
}
};
executors.submit(task);
}
}
This answer specially talks about the use of Platform.runLater. If you are using Task, you are better off updating the UI using the method it provides as stated in
kleopatra's answer.
For updating the UI, you have to be on the Javafx thread.
Once you are on any other thread, use Platform.runLater() to update those data back to Javafx UI. A working example can be found below
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HelloWorld extends Application {
private static final short COREPOOLSIZE = 2;
private static final short MAXIMUMPOOLSIZE = 2;
private static final int WORKQUEUECAPACITY = 100;
private ExecutorService executors = new
ThreadPoolExecutor(COREPOOLSIZE, MAXIMUMPOOLSIZE, 20, TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(WORKQUEUECAPACITY));
public static void main(String[] args) {
launch(args);
}
#Override
public void start(final Stage primaryStage) throws InterruptedException {
primaryStage.setTitle("Hello World!");
final Button btn = new Button();
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println("Hello World!");
}
});
final StackPane root = new StackPane();
root.getChildren().add(btn);
final Scene scene = new Scene(root, 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
Task<Boolean> task = new Task<Boolean>() {
#Override
public Boolean call() {
final AtomicInteger i = new AtomicInteger(0);
for( ; i.get() < 20; i.incrementAndGet()) {
Platform.runLater(new Runnable() {
#Override
public void run() {
btn.setText("First row\nSecond row " + i);
}
});
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {}
}
return Boolean.valueOf(true);
}
};
executors.submit(task);
}
}
For more information you can go through the links provided here
A Task is designed to interact with the ui on the fx-application thread, to take advantage of that support you should use it as designed :-)
As a general rule, you must not access ui in the call method [*] of the Task. Instead, update one of its properties (message, progress ...) and bind that property to your ui. Sample code:
Task<Boolean> taskWithBinding = new Task<Boolean>() {
#Override
public Boolean call() {
final AtomicInteger i = new AtomicInteger(0);
for( ; i.get() < 20; i.incrementAndGet()) {
updateMessage("First row\nSecond row " + i);
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
return Boolean.FALSE;
}
}
return Boolean.TRUE;
}
};
btn.textProperty().bind(taskWithBinding.messageProperty());
[*] The one exception is outlined (wrap the access into an runLater) in the other answer. Doing so is technically correct - but then you are by-passing a Task's abilities and could use an arbitrary Runnable ...

Real-time LineChart JavaFx

I have a problem with my GUI. I am trying to create a Gui which displays some analog values stored by the Arduino microcontroller. I am able to store all data I want in an array. Now I am using SceneBuilder and JavaFx to plot the arrays of this analog signal and I see the real signal but the graph is autoscaling and scattering . I would like to have more something like the following:
Advanced Stock Line Chart example in JAVAFX
JavaFX Example
Here is my code. The function updateGraph1(...) is called everytime that I receive a value which can update the graph.
package de.zft.degreen.view;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.Set;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.ValueAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
public class Gui extends Application implements Runnable, Initializable {
#FXML
private static LineChart<Number,Number> graph1;
public static XYChart.Series<Number, Number> series;
private ChangeListener changeListener;
private static Scene scene;
public Gui() {
series = new XYChart.Series<>();
series.setName("bye");
}
public ChangeListener getChangeListener() {
return changeListener;
}
public void setChangeListener(ChangeListener changeListener) {
this.changeListener = changeListener;
}
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println("Start start");
primaryStage.setTitle("DEGREEN GUI");
System.out.println("Before");
Pane myPane = FXMLLoader.load(getClass().getResource("Gui2.fxml"));
System.out.println("After");
System.out.println("Step1");
scene = new Scene(myPane);
System.out.println("Step2");
primaryStage.setScene(scene);
System.out.println("Step3");
primaryStage.show();
System.out.println("End start");
}
private void init(Stage primaryStage){
System.out.println("Start Init");
}
#FXML
public void updateGraph1(Long long1, int v){
System.out.println("Start updateGraph1"+series.getName());
final int q = v;
final long long2 = long1;
Platform.runLater(new Runnable() {
#Override
public void run() {
add2Series(long2,q,100);
}
});
System.out.println("End updateGraph1");
}
#Override
public void run() {
System.out.println("Gui Initialized");
launch();
System.out.println("Gui Ended");
}
#FXML
public void initialize(URL arg0, ResourceBundle arg1) {
System.out.println("Start Initialize"+series.getName());
series = new XYChart.Series<Number,Number>();
series.setName("Voltage DE1");
graph1.getData().add(series);
graph1.setAnimated(false);
System.out.println("End Initialize"+series.getName());
}
#FXML
protected static void add2Series(Number x, Number y, int displayedSize) {
int seriesSize = series.getData().size();
if (seriesSize >= displayedSize) {
series.getData().remove(0);
}
series.getData().add(new XYChart.Data<Number,Number>(x,y));
}
}
Someone Can help me please?
Take a look at this sample . The visible categories are managed in runtime so that only last ten added are visible.

Get list of all JavaFX Tasks

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());
}});

Resources