I want to change text I create a task and increment i, but I want to set a new text on this same place when i is changed, but old text doesn't disappear. It's my code. On swing I will be use repaint()
Task task = new Task<Void>() {
#Override
public Void call() throws Exception {
int i = 0;
while (true) {
final int finalI = i;
Platform.runLater(new Runnable() {
#Override
public void run() {
String a = "aaa";
if(finalI>4){
a = "sadsa";
}
if(finalI>10){
a = "sadsadsadsadsad";
}
gc.fillText(a, 150, 250+10);
}
});
i++;
Thread.sleep(1000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
As I mentioned in my comment, the problem is that Canvas really acts like a drawing board. You have drawn some text on it then you have drawn another text without erasing the previous text.
In your case, when you want to store a reference to the text to be able to update it, it is more reasonable to use a Pane and put a Text instance on it.
I have created an example for you:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.TextArea;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.text.Text;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
BorderPane root = new BorderPane();
Scene scene = new Scene(root, 400, 400);
Pane pane = new Pane();
Text text = new Text("");
pane.getChildren().add(text);
Task<Void> task = new Task<Void>() {
String a = "Initial text";
#Override
public Void call() throws Exception {
int i = 0;
while (true) {
if (i > 4)
a = "I is bigger than 4";
if (i > 10)
a = "I is bigger than 10";
Platform.runLater(() -> {
text.setText(a);
// If you want to you can also move the text here
text.relocate(10, 10);
});
i++;
Thread.sleep(1000);
}
}
};
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
root.setCenter(pane);
primaryStage.setScene(scene);
primaryStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Note: You can also eliminate the Platform.runlater(...) block by updating the messageProperty of the task inside call() then binding the textProperty of the Text to this property.
Example:
Pane pane = new Pane();
Text text = new Text("");
text.relocate(10, 10);
pane.getChildren().add(text);
Task<Void> task = new Task<Void>() {
{
updateMessage("Initial text");
}
#Override
public Void call() throws Exception {
int i = 0;
while (true) {
if (i > 4)
updateMessage("I is bigger than 4");
if (i > 10)
updateMessage("I is bigger than 10");
i++;
Thread.sleep(1000);
}
}
};
text.textProperty().bind(task.messageProperty());
Thread th = new Thread(task);
th.setDaemon(true);
th.start();
Related
I want to display a ProgressBar using a Popup in JavaFX so that I will be able to make the ProgressBar disappear by calling the PopUp's hide() method. However, rather than disappearing when the background task is complete, the ProgessBar doesn't show at all.
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) {
StackPane root = new StackPane();
Popup popup = new Popup();
ProgressBar bar = new ProgressBar();
popup.getContent().add(bar);
Task<Void> task = new Task<>() {
#Override
protected Void call() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
updateProgress(i, 100);
} catch (Exception ignored) {
}
}
return null;
}
};
bar.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(workerStateEvent -> popup.hide());
popup.show(stage);
new Thread(task).start();
stage.setScene(new Scene(root, 100, 100));
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
When I run the above code, all I see is a blank stage, shown here:
If I add the ProgressBar to the Stage manually using root.getChildren().add(bar), the bar displays correctly, with its progressProperty properly bonded, so I know that the issue is with the Popup. However, using that method, the bar doesn't disappear when the background task is complete.
I can't find this documented anywhere, but I think the owner of a Popup must be showing for the Popup.show(owner) method to succeed. So the following reordering of your code (calling stage.show() before popup.show(stage)) works:
#Override
public void start(Stage stage) {
StackPane root = new StackPane();
Popup popup = new Popup();
ProgressBar bar = new ProgressBar();
popup.getContent().add(bar);
Task<Void> task = new Task<>() {
#Override
protected Void call() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
updateProgress(i, 100);
} catch (Exception ignored) {
}
}
return null;
}
};
bar.progressProperty().bind(task.progressProperty());
task.setOnSucceeded(workerStateEvent -> popup.hide());
stage.setScene(new Scene(root, 100, 100));
stage.show();
popup.show(stage);
new Thread(task).start();
}
Note your other approach works: you just have to remove the progress bar from the scene graph when the task is complete:
#Override
public void start(Stage stage) {
StackPane root = new StackPane();
// Popup popup = new Popup();
ProgressBar bar = new ProgressBar();
// popup.getContent().add(bar);
root.getChildren().add(bar);
Task<Void> task = new Task<>() {
#Override
protected Void call() {
for (int i = 0; i < 100; i++) {
try {
Thread.sleep(100);
updateProgress(i, 100);
} catch (Exception ignored) {
}
}
return null;
}
};
bar.progressProperty().bind(task.progressProperty());
// task.setOnSucceeded(workerStateEvent -> popup.hide());
task.setOnSucceeded(event -> root.getChildren().remove(bar));
stage.setScene(new Scene(root, 100, 100));
stage.show();
// popup.show(stage);
new Thread(task).start();
}
I'm trying to demonstrate to a few beginner programmers how to set a label on a JavaFX app to auto update. Basically they would like the value to decrease every minute or so on the label without any user interaction.
Java isn't my strong point and looking through some previous questions I get that I need to deal with threads and Runnable().
I have put the code together below that works, but I was just wondering if there is a better way of doing this or an easier way to demonstrate the same outcome with simpler code.
public class MainTimer2 extends Application {
private int count = 100;
private Label response = new Label(Integer.toString(count));
public static void main(String[] args) {
launch(args);
}
//Update function
private void decrementCount() {
count--;
response.setText(Integer.toString(count));
}
#Override
public void start(Stage myStage) {
myStage.setTitle("Update Demo");
//Vertical and horizontal gaps set to 10px
FlowPane rootNode = new FlowPane(10, 10);
rootNode.setAlignment(Pos.CENTER);
Scene myScene = new Scene(rootNode, 200, 100);
myStage.setScene(myScene);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Runnable updater = new Runnable() {
#Override
public void run() {
decrementCount();
}
};
while (true) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("Timer error");
}
// UI update is run on the Application thread
Platform.runLater(updater);
}
}
});
// don't let thread prevent JVM shutdown
thread.setDaemon(true);
thread.start();
rootNode.getChildren().addAll(response);
myStage.show();
}
}
Count down by using PauseTransition:
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class MainTimer2 extends Application {
private int count = 100;
private Label response = new Label(Integer.toString(count));
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage myStage) {
myStage.setTitle("Update Demo");
//Vertical and horizontal gaps set to 10px
FlowPane rootNode = new FlowPane(10, 10);
rootNode.setAlignment(Pos.CENTER);
Scene myScene = new Scene(rootNode, 200, 100);
myStage.setScene(myScene);
rootNode.getChildren().addAll(response);
myStage.show();
update();
}
private void update() {
PauseTransition pause = new PauseTransition(Duration.seconds(1));
pause.setOnFinished(event ->{
decrementCount();
pause.play();
});
pause.play();
}
//Update function
private void decrementCount() {
count = (count > 0) ? count -1 : 100;
response.setText(Integer.toString(count));
}
}
Alternatively you could use Timeline:
private void update() {
KeyFrame keyFrame = new KeyFrame(
Duration.seconds(1),
event -> {
decrementCount();
}
);
Timeline timeline = new Timeline();
timeline.setCycleCount(Animation.INDEFINITE);
//if you want to limit the number of cycles use
//timeline.setCycleCount(100);
timeline.getKeyFrames().add(keyFrame);
timeline.play();
}
I'm new to Javafx and developing an IDE using this. The problem i'm facing with JavaFX is that i have to use Platform.runLater() to reflect changes in GUI from other threads. As my IDE i'm developing use multiple threads to keep up to date information and using Platform.runLater() makes application unresponsive. And sometime background processes has to print output of millions of line which i think cause problem when multiple threads try to do same. I tried to put a counter so that if output is larger than 250000 lines it will print output after 250000 lines else in other case it will print immediately after completion of the thread, even in this case if two or more thread try to execute Platform.runLater() (also there are other threads which creates tree with checkbox items and reflect realtime values) application hangs but everything in background is keep running normally and even application doesn't throw any exception. In normal java swing app i didn't face any similar problem. So i'm seeking guidance to tackle these problems. Can somebody gave me PRO tips to solve similar problems? :)
Edit On The request of #jewelsea
I tried to keep the sample code as simple as possible
FxUI.java
public class FxUI extends Application {
public static TextArea outputArea;
#Override
public void start(Stage primaryStage) {
outputArea= new TextArea();
Button btn = new Button();
btn.setText("Start Appending Text To Text Area");
btn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Thread r=new Thread( new Runnable() {
#Override
public void run() {
for (int i = 0; i < 10; i++) {
Thread t= new Thread(new simpleThread(i));
t.start();
try {
Thread.sleep(1000);
System.out.println("Thread Awake");
} catch (InterruptedException ex) {
Logger.getLogger(FxUI.class.getName()).log(Level.SEVERE, null, ex);
}
} }
});
r.start();
}
});
VBox root = new VBox(30);
outputArea.setWrapText(true);
outputArea.setPrefHeight(400);
root.getChildren().add(outputArea);
root.getChildren().add(btn);
Scene scene = new Scene(root, 500, 500);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
simpleThread.java
public class simpleThread implements Runnable {
int threadnumber;
public simpleThread(int j) {
threadnumber = j;
}
#Override
public void run() {
String output = "";
String content;
int length;
final String finalcontent2;
final int finallength2;
for (long i = 0L; i <= 10000; i++) {
final String finalcontent;
final int finallength;
if (i % 1000 == 0) {
output += "\nThread number = " + threadnumber + " \t Loop Counter=" + i;
content = FxUI.outputArea.getText() + "\n" + output;
length = content.length();
finallength = length;
finalcontent = "" + content;
Platform.runLater(new Runnable() {
#Override
public void run() {
System.out.println("appending output");
FxUI.outputArea.setText(finalcontent);
FxUI.outputArea.positionCaret(finallength);
}
});
} else {
output += "\nThread number = " + threadnumber + " \t Loop Counter=" + i;
}
System.out.println("Thread number = " + threadnumber + " \t Loop Counter=" + i);
}
}
}
I think the first real issue here is that your code is simply massively inefficient. Building up a string in a loop is a really bad thing to do: you create a new object and copy all the characters every time. Additionally, each time you update the text area, you are copying the entire existing text, creating another String by concatenating the additional content, and then replacing all the existing content with the new content. The string concatenation is going to run in quadratic time (as you are increasing the length of the strings each time) and you're going to cause mayhem for Java's string interning process.
Also, note that you shouldn't read the state of a node in the scene graph anywhere except on the FX application thread, so your line
content = FxUI.outputArea.getText() + "\n" + output;
is not thread-safe.
In general, to build up a string in a loop, you should use a StringBuilder to build up the string contents. If you're using a TextArea, it has an appendText(...) method which is all you need to update it.
Update following discussion in comments:
Having made those general comments, making those improvements doesn't really get you to a state where the performance is acceptable. My observation there is that the TextArea is slow to respond to user input even after the threads have completed. The issue is (I guess) that you have a large amount of data which is actually associated with a "live" part of the scene graph.
A better option here is probably to use a virtualized control such as a ListView to display the data. These only have cells for the visible portion and reuse them as the user scrolls. Here is an example. I added selection and copy-to-clipboard functionality as that is the main thing you would miss going from a TextArea to a ListView. (Note that if you have a huge number of things selected, the String.join() method is very slow to run. You might have to create a background task for that and a blocking dialog to show its progress if that's important.)
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
public class BigListBackgroundThreadDemo extends Application {
private static final int NUM_ITERATIONS = 10_000 ;
private static final int NUM_THREADS_PER_CALL = 5 ;
#Override
public void start(Stage primaryStage) {
ListView<String> data = new ListView<>();
data.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
Button startButton = new Button("Start");
Button selectAllButton = new Button("Select All");
Button selectNoneButton = new Button("Clear Selection");
Button copyToClipboardButton = new Button("Copy to clipboard");
copyToClipboardButton.disableProperty().bind(Bindings.isEmpty(data.getSelectionModel().getSelectedItems()));
AtomicInteger threadCount = new AtomicInteger();
ExecutorService exec = Executors.newFixedThreadPool(5, r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t ;
});
startButton.setOnAction(event -> {
exec.submit(() -> {
for (int i=0; i < NUM_THREADS_PER_CALL; i++) {
exec.submit(createTask(threadCount, data));
try {
Thread.sleep(500);
} catch (InterruptedException exc) {
throw new Error("Unexpected interruption", exc);
}
}
});
});
selectAllButton.setOnAction(event -> {
data.getSelectionModel().selectAll();
data.requestFocus();
});
selectNoneButton.setOnAction(event -> {
data.getSelectionModel().clearSelection();
data.requestFocus();
});
copyToClipboardButton.setOnAction(event -> {
ClipboardContent clipboardContent = new ClipboardContent();
clipboardContent.putString(String.join("\n", data.getSelectionModel().getSelectedItems()));
Clipboard.getSystemClipboard().setContent(clipboardContent);
});
HBox controls = new HBox(5, startButton, selectAllButton, selectNoneButton, copyToClipboardButton);
controls.setAlignment(Pos.CENTER);
controls.setPadding(new Insets(5));
BorderPane root = new BorderPane(data, null, null, controls, null);
Scene scene = new Scene(root, 800, 600);
primaryStage.setScene(scene);
primaryStage.show();
}
private Task<Void> createTask(AtomicInteger threadCount, ListView<String> target) {
return new Task<Void>() {
#Override
public Void call() throws Exception {
int count = threadCount.incrementAndGet();
AtomicBoolean pending = new AtomicBoolean(false);
BlockingQueue<String> messages = new LinkedBlockingQueue<>();
for (int i=0; i < NUM_ITERATIONS; i++) {
messages.add("Thread number: "+count + "\tLoop counter: "+i);
if (pending.compareAndSet(false, true)) {
Platform.runLater(() -> {
pending.set(false);
messages.drainTo(target.getItems());
target.scrollTo(target.getItems().size()-1);
});
}
}
return null ;
}
};
}
public static void main(String[] args) {
launch(args);
}
}
In JavaFX you have to do your background process in a Service which run a Task . By doing this you'll won't freez your GUI thread
Quick example, if you want a String as a return value of your process.
The service :
public class MyService extends Service<String> {
#Override
protected Task<String> createTask() {
return new Task<String>() {
#Override
protected String call() throws Exception {
//Do your heavy stuff
return "";
}
};
}
}
Place you want to use your service :
final MyService service = new MyService();
service.setOnSucceeded(e -> {
//your service finish with no problems
service.getValue(); //get the return value of your service
});
service.setOnFailed(e -> {
//your service failed
});
service.restart();
You have other method like setOnFailed, for the different status. So implement what you need.
You can also monitor this service, But I let you read the doc for this. It's quit simple.
You should also read JavaFX concurency
I'm looking for a way to hide a Pane for a short time (around 100ms) and then immediately show it again.
Right now I'm using a StackPane with two AnchorPanes on top, and on key press I remove the top pane. However, that doesn't seem to happen immediately and it takes way too long.
I also tried using CSS to make the top pane invisible, but that doesn't seem to do anything at all.
Here's some code of that:
pn_middle.setStyle("-fx-background-color: rgba(128, 128, 128, 0);");
try {
Thread.sleep(1000); //1 sec for testing
} catch (InterruptedException e) {
e.printStackTrace();
}
pn_middle.setStyle("-fx-background-color: rgba(128, 128, 128, 1);");
If you use JavaFX 8, here is a solution using a timer from ReactFX. Unlike #ItachiUchiha's solution, it does not create any new threads.
import java.time.Duration;
import org.reactfx.util.FxTimer;
button.setOnAction(event -> {
pane.setVisible(false);
FXTimer.runLater(Duration.ofMillis(1000), () -> pane.setVisible(false));
});
Use a Timer to clock the time for which you want to hide your Pane. Try the example out, it contains a StackPane which has a Pane, colored as PINK and a Button. On the click of the Button, the Pane is hidden for 1000ms
import java.util.Timer;
import java.util.TimerTask;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class HideAndShowPane extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
StackPane stackPane = new StackPane();
Button button = new Button("Click Me to hide Pane !");
Pane pane = new Pane();
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//Hide the Pane
pane.setVisible(false);
//Schedule the Visibility for 1000ms
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
//Run on UI thread
Platform.runLater(new Runnable() {
#Override
public void run() {
pane.setVisible(true);
}
});
}
}, 1000);
}
});
pane.setPrefSize(200, 200);
pane.setStyle("-fx-background-color : PINK");
stackPane.getChildren().addAll(pane, button);
Scene scene = new Scene(stackPane, 500, 500);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Using Task
You can also achieve this by using Task and Thread.sleep ad later binding the valueProperty of the Task with the visibleProperty of the Pane
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//Create a Task
Task<Boolean> task = new Task<Boolean>() {
#Override
protected Boolean call() throws Exception {
try {
//Invisible for 1000ms
Thread.sleep(1000);
}
catch (InterruptedException e) {
return Boolean.FALSE;
}
return Boolean.TRUE;
}
};
//Start the Task
new Thread(task).start();
//Bind the visibility with Task Value
pane.visibleProperty().bind(task.valueProperty());
}
});
Without creating any new Threads
Thanks to Tomas Mikula's answer, this can also be achieved without creating any new Thread. Using a combination of Timeline, KeyFrames and KeyValue
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
pane.setVisible(false);
Timeline timeline = new Timeline();
timeline.getKeyFrames().add(
new KeyFrame(Duration.millis(1000),
new KeyValue(pane.visibleProperty(), true)));
timeline.play();
}
});
I want to use thread I can use in simple program, but I can't use threads in fxml controller
Simple program:
/*
* 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 javafxapplication3;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
*
* #web http://java-buddy.blogspot.com/
*/
public class JavaFX_TimerTask extends Application {
final int MAX = 100;
Thread myTaskThread;
Thread myRunnableThread;
Timer myTimer;
MyTask myTask;
MyRunnable myRunnable;
MyTimerTask myTimerTask;
#Override
public void start(Stage primaryStage) {
myTask = new MyTask();
ProgressBar progressBarTask = new ProgressBar();
progressBarTask.setProgress(0);
progressBarTask.progressProperty().bind(myTask.progressProperty());
ProgressBar progressBarRunnable = new ProgressBar();
progressBarRunnable.setProgress(0);
myRunnable = new MyRunnable(progressBarRunnable);
ProgressBar progressBarTimerTask = new ProgressBar();
progressBarTimerTask.setProgress(0);
myTimerTask = new MyTimerTask(progressBarTimerTask);
Button btnStart = new Button("Start Task");
btnStart.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
myTaskThread = new Thread(myTask);
myTaskThread.start();
myRunnableThread = new Thread(myRunnable);
myRunnableThread.start();
myTimer = new Timer();
myTimer.scheduleAtFixedRate(myTimerTask, 80, 100);
}
});
VBox vBox = new VBox();
vBox.setPadding(new Insets(5, 5, 5, 5));
vBox.setSpacing(5);
vBox.getChildren().addAll(
new Label("Run in Thread(Task)"),
progressBarTask,
new Label("Run in Thread(Runnable)"),
progressBarRunnable,
new Label("Run in Timer and TimerTask"),
progressBarTimerTask,
btnStart);
StackPane root = new StackPane();
root.getChildren().add(vBox);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("java-buddy.blogspot.com");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
class MyTask extends Task<Void>{
#Override
protected Void call() throws Exception {
for (int i = 1; i <= MAX; i++) {
updateProgress(i, MAX);
Thread.sleep(100);
}
return null;
}
}
class MyRunnable implements Runnable{
ProgressBar bar;
public MyRunnable(ProgressBar b) {
bar = b;
}
#Override
public void run() {
for (int i = 1; i <= MAX; i++) {
final double update_i = i;
//Not work if update JavaFX UI here!
//bar.setProgress(i/MAX);
//Update JavaFX UI with runLater() in UI thread
Platform.runLater(new Runnable(){
#Override
public void run() {
bar.setProgress(update_i/MAX);
}
});
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
Logger.getLogger(JavaFX_TimerTask.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
class MyTimerTask extends TimerTask{
ProgressBar bar;
double count;
public MyTimerTask(ProgressBar b) {
bar = b;
count = 0;
}
#Override
public void run() {
bar.setProgress(count++/MAX);
if(count >= MAX){
myTimer.cancel();
}
}
}
}
Now, I want to use thread in a fxml controller:
public class DashboardController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
}
}
When I use thread, in initialize it doesn't show me any output.
How can I use thread?
Thank you.
JavaFx already runs threads -
JavaFx thread for GUI
Launch thread for background services.
If you need to make something like progress bar in which you want to run something over javafx thread then i would suggest use Services instead of thread as it can be used again and again while threads can't be.
Service<Void> ser = new Service<Void>() {
#Override protected Task createTask() {
return new Task<Void>() {
#Override protected Void call() throws InterruptedException {
// You code you want to execute in service backgroundgoes here
return null;
}
};
}
};
ser.setOnSucceeded((WorkerStateEvent event) -> {
// Anything which you want to update on javafx thread (GUI) after completion of background process.
});
ser.start();
You can use the service again and again with any variation like loop/recursion/switch -
ser.restart(); // Restart the service
ser.reset(); // Stops the service
Is your Controller initialized?
Do you set it (in the fxml/FXMLoader)?
If it your Controller is loaded this should work.
public class DashboardController implements Initializable {
#Override
public void initialize(URL url, ResourceBundle rb) {
myTask = new MyTask();
myTaskThread = new Thread(myTask);
myTaskThread.start();
}
}