I made a progressbar and it works perfectly. The only issue is that i want to show the progress percentage. first some background information: Netwerk reads in a large file(=bestand) line by line and everytime it reads a line a counter goes up by 1. So the percentage i want to get is the (counter/1380)*100 with 1380 is the number of lines the scanner reads in. When I run it Netwerk reads in the file while the progressbar is running and the progressbar stops when the scanner is ready (so this works perfectly). But the percentage doesn't upgrade. When I debugged I discovered that updateprogress is called after Netwerk has finished reading and therefore the percentage stays at -100%. Does someone have a solution for this?
Task<Integer> task = new Task<Integer>() {
#Override
public Integer call() throws Exception {
n = new Netwerk(bestand);
updateProgress(((n.getTeller()/1380)*100), 100);
return null;
}
};
pb = new ProgressBar();
pb.progressProperty().bind(task.progressProperty());
Label lg = new Label();
lg.textProperty().bind(Bindings.format("Even geduld... %.0f%%",
task.progressProperty().multiply(100)));
task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
#Override
public void handle(WorkerStateEvent event) {
progressStage.close();
SaveStage = new Stage();
//initStage
}
});
new Thread(task).start();
So what happens is that I have a thread with a task in it, the task;
1. makes a Netwerk that reads in the document and increments the counter( i tested the counter and it works)
2. Updateprogress() to update the counter has well
then i bind the task to the progressbar and i bind the label with a textProperty. The problem is that the label doesn't update.
Define a variable as attribute of your class
class YourClass {
private volatile int percentage;
Initialize it when you start your ProgressBar, and assign it inside Task:
Task task = new Task<Integer>() {
#Override
public Integer call() throws Exception {
n = new Netwerk(bestand);
// assign here the percentage variable
percentage = n.getPercentage();
if (n.getTeller() == 1380) {
return null;
}
return null;
}
Related
Lately I encountered some issues with code that asynchonously updates GUI. I then came across this article, which shined some light on the problem - I was not using Platform.runLater() to update my GUI components, however, consider the original code:
public class Main extends Application {
private TextArea textArea = new TextArea();
private Label statusLabel = new Label("Not Started...");
private Button startButton = new Button("Start");
private Button exitButton = new Button("Exit");
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(final Stage stage) {
startButton.setOnAction(event -> startTask());
exitButton.setOnAction(event -> stage.close());
HBox buttonBox = new HBox(5, startButton, exitButton);
VBox root = new VBox(10, statusLabel, buttonBox, textArea);
root.setStyle("-fx-padding: 10;" +
"-fx-border-style: solid inside;" +
"-fx-border-width: 2;" +
"-fx-border-insets: 5;" +
"-fx-border-radius: 5;" +
"-fx-border-color: blue;");
Scene scene = new Scene(root, 400, 300);
stage.setScene(scene);
stage.setTitle("A simple Concurrency Example");
stage.show();
}
private void startTask() {
Runnable task = this::runTask;
Thread backgroundThread = new Thread(task);
backgroundThread.setDaemon(true);
backgroundThread.start();
}
private void runTask() {
for (int i = 1; i <= 10; i++) {
try {
String status = "Processing " + i + " of " + 10;
statusLabel.setText(status);
textArea.appendText(status + "\n");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
The problematic part is the runTask() method. The article explains that instead of simply using statusLabel.setText(status), I should use Platform.runLater(() -> statusLabel.setText(status));. That makes sense to me.
What doesn't make sense, however, is why I don't have to apply the same logic to textArea updates? Notice the fifth line of runTask() method - the textArea.appendText(status + "\n"); part. Why it doesn't give me an exception (java.lang.IllegalStateException: Not on FX application thread) about modifying an FX component from non-FX thread, since it's clearly a way of updating GUI FX component? What operations should I put inside the Platform.runLater() and what operations do now have to be there?
Run later will interfere more or less with the UI Thread. The execution will be queued in the UI thread. When you have a thread sleep or a long calculation the UI will freeze. You can use it for simple tasks. But in your case I do recommend it, because it is only a "set-operation".
Generally you should use Observable properties and bind them to the UI when possible. Then you don't need to do anything of the "Thread" and "Queuing" and "RunLater" operations.
When the WHOLE operation is needed to executed with the "run later", and the calculation would be time costly, you should look, for what you can run later or use a different Mechanism.
But when you just add something with out run laterform a difficult or longer calculation from another thread, an exception will pop up.
So what you want is to update the UI-Elements when it is needed and the new values are calculated or provided by whatever mechanism.
Here the way to go with Properties:
StringProperty text = new SimpleStringProperty("Hello");
Label label = new Label();
label.getTextProperty().bind(text);
Now whenever you Update text from another Thread, the update will automatically occur in the UI without Run Later.
If there is no way around:
What you could (in the case of more costly operations) do is have a queue that contains all the executions of updates for the view that come asynchronously. And execute the changes only in the JavaFX Thread.
You should use the Animationtimer for that.
//thread safe queue
Queue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
Now the approach with runLater:
Platform.runLater(()->{
while(!queue.isEmpty()) {
queue.remove().run();
}
});
And the approach with the AnimationTimer.
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
//Whatever condition or how many changes you would make at one tick
//In this case we just run all "updates" in that tick.
// I would recommend it, you could update 100 things each tick
while(!queue.isEmpty()) {
queue.remove().run();
}
}
};
timer.start();
Then have a thread that would calculate something and when it's done it adds the new change to the queue. Or sleeps or waits for a response etc.
private void startTask() {
Runnable task = this::runTask;
Thread backgroundThread = new Thread(task);
backgroundThread.setDaemon(true);
backgroundThread.start();
}
private void runTask() {
for (int i = 1; i <= 10; i++) {
try {
String status = "Processing " + i + " of " + 10;
//Add the new change as a Runnable here
//It will be run in the in the next update of the UI
tasks.add(()->{
statusLabel.setText(status);
textArea.appendText(status + "\n");
});
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
NOTE
It still depends for what purpose you are going to use it.
Those are just two approaches.
When you only update declared values, you could also use Property Bindings.
(StringProperty in your case)
And I would personally always go with the AnimationTimer.
RunLater decides when it is "fine" with queuing the Runnable. With the Animationtimer, you can be sure it is executed each tick, when a update is needed.
You could also Store all the updates and then do a "poll" of the new Values each tick.
TASK
When you know exactly where you want to put which value you should use Task and bind it the the UI element, that would also work.
Label statusLabel = new Label("Not Started...");
Task<String> t = new Task<String>() {
#Override
protected String call() throws Exception {
int i = 0;
while(//any condition ... ) {
i++;
Thread.sleep(1000);
updateValue("i is " + i);
}
return "last value!";
}
// now Bind the TextProperty of the Label to the ValueProperty of the
// Task
statusLabel.getTextproperty().bind(task.getValueProperty());
Thread backgroundThread = new Thread(task);
backgroundThread.start();
I have a swing application that is quite slow to start up because it has to load a thousand pictures into the GUI. It takes 10 seconds to start up.
It is a single thread application, how could I code multithread to speed up the task? The following code is in a for loop of 1000 iterations.
ImageIcon icon = new ImageIcon(Files.readAllBytes(coverFile.toPath()));
// ImageIcon icon = createImageIcon(coverFile);
JLabel label = null;
if (coverCount % 2 == 0) {
label = createLabel(coverFile, movieFile, icon, SwingConstants.LEFT);
} else {
label = createLabel(coverFile, movieFile, icon, SwingConstants.CENTER);
}
box.add(label);
The images are being loaded and put into a Box sequentially. I have two difficulties if I want to do it multithread
How does a thread return value to parent
How to achieve non-blocking call back which add the image to the
box sequentially
Thank you.
How does a thread return value to parent
Use a call-back mechanism. For Swing that would mean using a SwingWorker and notifying the GUI of thread completion either in the worker's done() method or by adding a PropertyChangeListener to the worker, listening to the worker's "state" property, for when it changes to SwingWorker.StateValue.DONE
How to achieve non-blocking call back which add the image to the box sequentially
The SwingWorker has a publish/process method pair that allows sending data sequentially from the background thread via the publish method, and then handle the data sequentially on the event thread within the process method. This requires use of a SwingWorker<VOID, Image> or SwingWorker<VOID, Icon> or something similar, the 2nd generic parameter indicating the type of object sent via this mechanism.
For example:
public class MyWorker extends SwingWorker<Void, Icon> {
#Override
protected Void doInBackground() throws Exception {
boolean done = false;
while (!done) {
// TODO: create some_input here -- possibly a URL or File
Image image = ImageIO.read(some_input);
Icon icon = new ImageIcon(image);
publish(icon);
// TODO: set done here to true when we ARE done
}
return null;
}
#Override
protected void process(List<Icon> chunks) {
for (Icon icon : chunks) {
// do something with the icon here
// on the event thread
}
}
}
And to use it within a GUI:
// may need constructor to pass GUI into worker
final MyWorker myWorker = new MyWorker();
myWorker.addPropertyChangeListener(evt -> {
if (evt.getNewValue() == SwingWorker.StateValue.DONE) {
// We're done!
// call get to trap errors
try {
myWorker.get();
} catch (InterruptedException | ExecutionException e) {
// TODO: real error handling needed here
e.printStackTrace();
}
}
});
myWorker.execute(); // start worker in a background thread
For more on Swing concurrency, please check out Lesson: Concurrency in Swing
Multithreading will speed up the application but I think doing a lazy load is a better approach (you can do both). You can't be displaying all these images at the same time so I suggest you load the images that will be visible at the start and after that load the image as needed this will hugely increase your performance and use less memory/resource.
If you really want to load all 1000 images:
It is enough to use one background thread, so that you don't slow down the main Swing Event loop thread.
Create a custom class which implements runnable, and has references to all the context to do the job. Like so:
public static class IconLoader implements Runnable{
private List<File> movies;
private File coverFile;
private JPanel box;
public IconLoader(JPanel box, File coverFile, List<File> movies) {
this.box = box;
this.coverFile = coverFile;
this.movies = movies;
}
#Override
public void run() {
for(int coverCount=0;coverCount<movies.size();coverCount++) {
try {
final JLabel label;
File movieFile = movies.get(coverCount);
ImageIcon icon = new ImageIcon(Files.readAllBytes(coverFile.toPath()));
// ImageIcon icon = createImageIcon(coverFile);
if (coverCount % 2 == 0) {
label = createLabel(coverFile, movieFile, icon, SwingConstants.LEFT);
} else {
label = createLabel(coverFile, movieFile, icon, SwingConstants.CENTER);
}
SwingUtilities.invokeLater( new Runnable() {
#Override
public void run() {
box.add(label);
}
});
}catch(IOException e) {
e.printStackTrace();
}
}
}
private JLabel createLabel(File coverFile, File movieFile, ImageIcon icon, int direction) {
//Create the label and return
return null;
}
}
Then start the loading process during your app initialization, by passing the runnable to a new thread, and starting the thread. Like so:
new Thread( new IconLoader(box, coverFile, movies) ).start();
I want a progress indicator to stop only after completely updating the ui. But it stops after executing last line of code in ui method. The indicator should work as:
1> Start the progress
2> Run the progress until all nodes are added to the scene
3> Stop after completion
The way i update is, i pass BorderPane to the thread and set its center a gridpane, which is the last line of code after which the indicator stops.
And the loginTask, if i start it inside Application Thread the indicator does not spin !
borderpane.setCenter(gpane);
UI method
{
Loading loadBar = new Loading(stage);
Task<Boolean> loginTask= checkCredTask();
loginTask.setOnSucceeded(value -> {
loadBar.hideProgress(); });
loadBar.startTask(loginTask);
(new Thread(loginTask)).start();
}
Progress Bar
public class Loading{
private static Stage stage;
private static ProgressIndicator p;
private static Alert alert;
public Loading(Stage s){
stage=s;
p=new ProgressIndicator();
alert = new Alert(AlertType.NONE);
}
public void startTask(Task<Boolean> cm){
if(p != null){
p.setProgress(-1);
p.progressProperty().unbind();
p.progressProperty().bind(cm.progressProperty());
alert.initOwner(stage);
alert.getDialogPane().setStyle("-fx-background-color:rgba(0,0,0,0);");
alert.getDialogPane().getScene().setFill(Color.TRANSPARENT);
alert.initStyle(StageStyle.TRANSPARENT);
alert.getDialogPane().setContent(p);
alert.show();
}
}
public void hideProgress(){
alert.setResult(ButtonType.CLOSE);
}
}
Task
private Task<Boolean> checkCredTask() {
Task<Boolean> loginTask = new Task<Boolean>() {
#Override
public Boolean call() {
Boolean result = false;
int flag = verifyCredential();
if (flag == 1) {
loadUI();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
result = true;
} else if (flag == 2) {
result = false;
}
return result;
}
};
return loginTask;
}
load UI method
ExecutorService execsrv = Executors.newSingleThreadExecutor();
execsrv.execute(new AdminUI(stage,pane,mb));
execsrv.shutdown();
Your code won't even compile. Task<Boolean> loginTask does not override abstract call() method. Even if you wrap
ExecutorService execsrv = Executors.newSingleThreadExecutor();
execsrv.execute(new AdminUI(stage,pane,mb));
execsrv.shutdown();
in call() method it makes no sense, because you are executing new task inside another task.
Assumig that new AdminUI(stage,pane,mb) is long running process and return boolean you should do it in this way:
Task<Boolean> loginTask = new Task<Boolean>() {
#Override
protected Boolean call() throws Exception {
// Start the UI
AdminUI ui = new AdminUI(stage, pane, mb);
return ui.getBooleanValue();
}
};
EDIT
As I said, you are executing AdminUI task inside loginTask what makes no sense. For now you are waiting only for login task but not for AdminUI task. Login task finishes faster than AdminUI that is why indicator stops to early. Extract AdminUI to another Task. This is pseudo code so you have to do it by your self.
Task<Boolean> loginTask= checkCredTask();
loginTask.setOnSucceeded(value -> {
//****** THIS IS PSEUDO CODE ***********
//start AdminUITask
//AdminUITask.setOnSucceeded(value -> {
//loadBar.hideProgress();
//});
});
I have a task to work with threads and JavaFX library. A separate thread 1 need to be started by pressing a button. The thread is supposed to fulfill a list with Integer values (100 - 150) with a small interval (e.g. 5 ms).
And after values are generated, it should stop. A new thread 2 must start and fill a ViewList with generated values.
But I get an exception each time when a new value is added to my list by thread 1:
Exception in thread "Thread-4" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-4
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:204)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:364)
at javafx.scene.Scene.addToDirtyList(Scene.java:485)
at javafx.scene.Node.addToSceneDirtyList(Node.java:424)
at javafx.scene.Node.impl_markDirty(Node.java:415)
I tried to use Platform.runLater() in button event listener instead of creating a new Thread, but the program stops responding in that case.
Could anyone please help me, how to fill a collection with values in a separate thread and how to start a second one to update ViewList element after the first thread finishes?
Here is my class:
int itemName = 100;
Button btnOne = new Button("Button one");
Label label = new Label("Press the button to start");
ObservableList<String> listOptions = FXCollections.observableArrayList();
ListView<String> list;
#Override
public void start(Stage primaryStage) throws Exception{
primaryStage.setTitle("Hurry");
list = new ListView<>(listOptions);
list.setPrefSize(120, 120);
MultipleSelectionModel<String> lvSelModel =
list.getSelectionModel();
FlowPane rootNode = new FlowPane(10, 10);
rootNode.setAlignment(Pos.CENTER);
Scene myScene = new Scene(rootNode, 180, 200);
primaryStage.setScene(myScene);
lvSelModel.selectedItemProperty().addListener(
(changed, oldValue, newValue) -> {
label.setText("List option selected: " + newValue);
});
rootNode.getChildren().addAll(btnOne, list, label);
primaryStage.show();
Task<Integer> threadOne = new Task<Integer>(){
#Override
protected Integer call() throws Exception{
while(itemName < 130){
final int finalValue = itemName++;
listOptions.add(String.valueOf(itemName));
Platform.runLater(
() -> label.setText("Generating: " + finalValue));
Thread.sleep(100);
}
label.setText("Thread 1 finished");
return itemName;
}
};
btnOne.setOnAction(
ae -> {
Thread th = new Thread(threadOne);
th.setDaemon(true);
th.start();
});
}
public static void main(String[] args) {
launch(args);
}}`
The result program should be like this:
Thanks everyone for your time!
Since listOptions is the list of items in the list view, calling listOptions.add(...) modifies the UI (the list view). Thus it needs to be executed on the FX Application Thread, similarly to setting the text of the label. Just move that line in side the Platform.runLater(...):
Task<Integer> threadOne = new Task<Integer>(){
#Override
protected Integer call() throws Exception{
while(itemName < 130){
final int finalValue = itemName++;
Platform.runLater(() -> {
listOptions.add(String.valueOf(itemName));
label.setText("Generating: " + finalValue);
});
Thread.sleep(100);
}
label.setText("Thread 1 finished");
return itemName;
}
};
To start another task (or, indeed, do anything) when the first task finishes, use the task's onSucceeded handler:
threadOne.setOnSucceeded(e -> {
// create another task and run it in another thread...
});
I am probably missing something here, but I'll try and explain what I want to achieve and then someone please tell me that I am doing it wrong(which I am :) ) and point me in the right direction?
I am using JavaFX 2.0, but I think this problem would lend itself to Swing, or any UI framework.
I want to develope a simple splash screen for my application, when the splash screen starts, I want to have a message label that will be used to update a user on whats happening, in regards to configuring up the back end of the application. My application start up has 2 steps, the first step uses Spring to initialise the Application Context, which in turn initialises the DB (JPA 2.0/Hibernate/etc). The second part of my application start up process will query the DB for the initial data which will be used to populate the UI. Both these steps need to be complete before I can close the splash screen, and between each step I want to update the label in the splash screen to let a user know which stage is being done at that time.
I have broken this down into the following simple program which uses JavaFX and a button, when the button is pressed a new thread is created, that starts another class, which just performs some count to an abitary value, and then another another thread is created to simlate the second step of the start up process, But my issue is here that the second thread attempts to run before the first thread has finished, and as a result runs into a NPE.
Below is a breakdown of some simple code that highlights this issue:
public class Test extends Application
{
private LongTester lt;
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
Button btn = new Button();
final Label lblText = new Label("Starting");
btn.setText("Say 'Hello World'");
btn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent event)
{
new Thread(new ConstructorRunnable()).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable()).start();
lblText.setText("Finished");
}
});
HBox root = new HBox();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
private class ConstructorRunnable implements Runnable
{
#Override
public void run()
{
lt = new LongTester();
}
}
private class MethodRunnable implements Runnable
{
#Override
public void run()
{
lt.countAgain();
}
}
private class LongTester
{
public LongTester()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Constructor: " + idx);
}
}
public Boolean countAgain()
{
for (int idx = 0; idx < 1000000; idx++)
{
System.out.println("Method: " + idx);
}
return Boolean.TRUE;
}
}
}
Can anyone point out my mistake?
I'd advise using a Task to execute your startup tasks and message progress back to your splash screen (similar to the approach in this sample created for a prior stackoverflow question on splash screens). If you want stuff in your task to run sequentially, just use one thread for the task rather than two.
Sample code for your task might look something like:
final Task<Data> initTask = new Task() {
#Override protected Data call() throws InterruptedException {
updateMessage("Initializing Application");
MyApp.initializeAppContext();
updateMessage("Loading Data");
Data data = DB.loadData();
updateMessage("Data Loaded");
return data;
}
showSplash(initStage, initTask);
new Thread(initTask).start();
showMainStage(initTask.valueProperty());
To fix your problem, you can use a CountDownLatch
This can be used the following way:
private class ConstructorRunnable implements Runnable {
CountDownLatch gate_ = null;
public ConstructorRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run() {
lt = new LongTester();
gate_.countDown(); // Signal the second thread to start
}
}
private class MethodRunnable implements Runnable{
CountDownLatch gate_ = null;
public MethodRunnable(CountDownLatch gate){
gate_ = gate;
}
#Override
public void run(){
CountDownLatch.await(); // Wait for the first thread to finish
lt.countAgain();
}
}
This can now be used like this:
CountDownLatch gate = new CountDownLatch(1);
new Thread(new ConstructorRunnable(gate)).start();
lblText.setText("More Loading?");
new Thread(new MethodRunnable(gate)).start();
lblText.setText("Finished");
On a side note: as your tasks are sequential, why is there a need for having several threads? Threads are made to run multiple tasks running in parallel and your case does not make a use case for threads as these operations are sequential