Creating Wait message in Java For when thread finishes [duplicate] - java

I have simple Java Swing application which uses zip4j to encrypt and unpack zip file. It's done by this part of code:
ZipFile zipFile = new ZipFile("dataStorage.zip");
zipFile.setPassword(password);
zipFile.setRunInThread(true);
ProgressMonitor progressMonitor = zipFile.getProgressMonitor();
if (!verify(zipFile)) {
JOptionPane.showMessageDialog(null, "You have entered incorrect password!", "ERROR", 0);
return;
}
zipFile.extractAll("./"); //runs in new thread
//After entering this while GUI freezes
while (progressMonitor.getState() == ProgressMonitor.STATE_BUSY) {
System.out.print("."); // this works normally...
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
//
}
pbEncryptionProgress.setValue(progressMonitor.getPercentDone()); //this is not updating progress bar, but getPercentDone is returning correct data
}
Problem is that progress bar is not being updated. Application GUI seems frozen. However, dots are being printed to console. How can I fix it to update that progress bar?

Please read Concurrency in Swing.
What you are doing is using up all resources of the EDT by sleeping and updating, not leaving any time for it to actually redraw your GUI. The EDT is meant for small operations on the GUI. You should never call Thread.sleep() on the EDT.
What you could do is make a Timer that would run your check every second until the check passes. That way the EDT would be free to not freeze.
A much better way of doing this is by using a SwingWorker. It has methods that do your specific thing:
A task to do in the background (In your case - unzip)
A method to publish a partial result to the GUI (in your case % done)
A method to react to partial results (In your case - update progress)
A method to invoke when done (Not shown in your case, but useful anyway).

Wrap the call pbEncryptionProgress.setValue(progressMonitor.getPercentDone()); in SwingUtilities.invokeAndWait

You shouldn#t do your zipping on the event dispacher thread (which is where all your event-handling takes place). Create a SwingWorker or someething like it to offload your heavy duty on a separate processing thread that can then inform the progress bar that can be updated on the EDT. With your solution all updates to the progress bar can only be processed when the EDT is free again, that is after your zip-operation is finished.

Related

Detect when user finished writing - Thread.sleep() called in loop

I wanted to build a search that shows you the results when the user finishes writing.
If I had to search in a local db I would have triggered the search every time the user releases a key.
In my case I have to send Web Requests to an API point that exposes the search function. The server allows only 20requests per minute from a single IP.
So, I wrote a Thread that detects when user really finishes writing:
(while true)
save the searchbox text
wait for 400ms
check if the searchbox text is the same as the one saved before
Code:
private void checkIfUserFinishedWritingFunction() {
while(true) {
String previousText = textField.getText();
try {
Thread.sleep(400);
} catch (InterruptedException ex) {
return;
}
String actualText = textField.getText();
//WHEN USER FINISHED WRITING...
if(previousText.equals(actualText)) {
//IF SEARCHBOX ISN'T EMPTY
if(!textField.getText().trim().isEmpty()) {
//START A THREAD THAT SENDS WEB REQUEST
}
//IF SEARCHBOX IS EMPTY...
else {
//HIDE RESULTS POPUP
if(resultsList.isShowing())
resultsList.hide();
}
return;
}}}
NetBeans is telling me that Thread.sleep() called in loop could be dangerous. I think it's because of the cost, and in my the loop runs every 400ms.
How can I fix this algorithm?
I think it's because of the cost, and in my the loop runs every 400ms.
Actually, it is because when you call sleep in a GUI-based application, you are liable to cause the event listener thread to freeze.
(And if this is not on the event listener thread, then calling hide is probably a thread-safety hazard.)
A better alternative would be to use a combination of an event listener for update events on the text box that pays attention to the time since the last query you sent, and something like a ScheduledExecutorService.
Calling Thread.sleep() isn't costly, but creating a thread might be.
As a rule of thumb, if you write code that calls sleep(), then you are either (A) trying to do something that nobody's ever thought of before, or (B) re-inventing something you could have had for free, or (C) making a mistake.
For most of us, it's usually (B) or (C) or both.
In this case, instead of dedicating a thread to polling the GUI state, you could do the polling from within the Event Dispatch Thread (EDT) itself by using a javax.swing.Timer. See the Java tutorials for examples: https://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html

Thread.sleep interrupts the code [duplicate]

I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).

Thread.sleep putting to sleep all active threads [duplicate]

I im creating a simple testing app that runs a check every hour on the selected directory/s using thread.sleep() through JFileChooser. But when i select the directory and the method runs the ui panel goes grey and the swing bits disappear. The thread seems to be putting the ui to sleep as well as the method its calling.
if (option == JFileChooser.APPROVE_OPTION) {
selectedDirectory = chooser.getSelectedFiles();
try {
while (true) {
runCheck(selectedDirectory);
Thread.sleep(1000*5);//1000 is 1 second
}
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
e1.printStackTrace();
}
}
Im looking for a way around this issue so that i can print the results of the checks being run in the ui .setText(result)
You are correct about the code putting the UI to sleep. Since sleep is called on the Event Dispatch Thread (the thread responsible for running the gui) the UI stops processing events and 'goes to sleep'.
I think what you want is a javax.swing.Timer.
Timer t = new Timer(1000 * 5, new ActionListener() {
public void actionPerformed(ActionEvent e) {
// do your reoccuring task
}
});
This will cause your reoccurring task to be performed off of the EDT, and thus it wont leave your ui unresponsive.
If the code you have posted runs on the EventDispatchThread, then there is no way Swing can redraw the GUI. You're blocking (sleeping in) the thread that's supposed to handle that!
This is because you are running you check in the main GUI thread and are using an infinite loop. This check is a background task and should be executed in it's own thread so that the GUI can still receive and react to input by the user.
You also do not need to write your own implementation, Java has a Timer object.
Edit: There is also a Swing specific Timer object. This will have the action occur in the GUI thread, so if your task is long, it can cause the GUI to still lock up while the action is occurring (but not while it is waiting).

How to get GUI to update while program is running?

I am trying to get the GUI to update after each iteration of the loop. I have read other answers to similar questions and still can't get it to work. In the code below I call simulate which runs through the loop calling step which calculates and changes GUI components as needed but the GUI isn't updating until after the loop completely ends. How can I get it to update after each iteration?
public void step(View v) {
for (int i = 0; i < cells.length; i++)
update(i);
count++;
Toast.makeText(getApplicationContext(), count + "", 1000).show();
}
public void simulate(View v) {
while (!pause) {
step(v);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void update(final int i)
{
//This goes through each button and counts the neighbors (this is the
//intensive work
int neighbors = getNeighbors(i);
//With the information provided from the getNeighbors the following if
//statement updates the GUI using the dead and alive method calls.
if (isAlive(cells[i])) {
if (neighbors < 2)
dead(cells[i]);
else if (neighbors > 3)
dead(cells[i]);
}
else {
if (neighbors == 3)
alive(cells[i]);
}
}
The problem is that you are running that code in the main thread of your application. The GUI runs on the same thread and can not be updated while you are blocking it.
You have to do the calculations in a different task and then send a message to the main process to update the GUI.
Read this for background-information (if you are new to this, you have read the backgrounds first):
http://developer.android.com/guide/topics/fundamentals/processes-and-threads.html
The easiest way to do this is to use AsyncTask and then do the GUI update with "onProgressUpdate()".
Although AsyncTask already makes things pretty easy, you have to mind that the underlying activity can be destroyed while AsyncTask is running. This is not really well covered in the documentation but I find that the use of Fragments is probably the best way of dealing with it. Read this article for a quite nice description:
http://blogactivity.wordpress.com/2011/09/01/proper-use-of-asynctask/
Remark: read also the AsyncTask documentation. I could not post the link due to restrictions of the forum.
We are always adviced that , UI work should be on the UI-Thread, and Non-UI work on Non-UI Thread, but from HoneyComb android version it became a LAW. When we start an application in Android, it start on the Dedicated UI thread, creating any other thread will drop you off the UI thread, you normally do this to do some process intensive work, but when you want to display the output of the non-ui thread process, on the ui thread then you will experience lagging, exception etc...
From my view this can be done in two ways....
Using Handler... Handler stores the reference of the thread on which it was created, Initialize Handler inside the onCreate() method, and then use handler.post() to update the UI thread.
Use AsyncTask<> provided by android, it synchronizes the UI and Non-UI threads
Methods in AsyncTask<>
doInBackground(String...) // Work on the Non-UI thread
postExecute(String result) // Getting the Output from the Non-Ui thread and
Putting the Output back on the UI Thread
I think you have to use AsyncTask for this.
Try to read the documentation..
http://developer.android.com/reference/android/os/AsyncTask.html

Java Threads with Swing UI

After having some trouble with setting up a thread to start my MIDI sequencer I decided to simply remove it, although it would slow my UI down I would be able to use it correctly.
What I noticed however was that even when playing the Sequencer the UI was very much active, even if it was playing around 500 notes the UI worked perfectly fine.
Now I know that in C# if you are doing something intensive it is advisable to load it on a new Thread as it will free the UI. Is it the same principle in Java, it's really confused me. If so can someone explain how the UI is not being blocked?
Thanks
Edit:
The following code actually plays the Sequence
public static boolean Play() {
if(!_sequencer.isRunning()) {
try {
_sequencer.setSequence(_sequence);
_sequencer.start();
return true;
} catch (Exception e) {
Logger.Add(e.getMessage());
}
}
return false;
//Already running
}
Yes, it is the same theory. Only the Event Thread can modify the UI, and thus if you are doing anything on that thread, then you are preventing other events from working on the UI.
It may be easier to think about the Event Thread as a queue:
Show Form
Click Button
Do your work (Action)
Reset focus of Button
Update Progress Bar
Et cetera
If #3 takes long, then it may mean that your form will appear locked up. Obviously it completely depends on your definition of long. In general, it's better to work off of the Event Thread rather than on it.
It's definitely the same principal. Generally speaking you want to only do minimal work with the UI thread. If it ends up taking any significant time, it can cause the UI to be unresponsive and you can get a "Not Responding" error. You want to keep the UI thread as free as possible so it can respond to user interaction.
If your application has a graphical user interface, it's advised that you perform expensive calculations on a new Thread to keep your graphics from freezing. You can either create a SwingWorker, or use the Callable/Future idiom.
Yes, you're right. Read Threads and Swing for more info.

Categories