Java Swing Updating before processing - java

I have a little app that at the moment consists of a JPanel with an "Open File" button.
Once the user clicks the button a new JFileChooser is created so the user can select a file.
Once the user selected a file, this file will be processed.
What I want to do, is to set the text on the JPanel to "Processing File" While the file is being processed.
I have all the code for this and then after the code, I call the method to actually process the file, but what happens is that it processes the file first and then update the gui components
How do I get around this?

You should process your task in another thread rather than in Event Dispatch Thread (EDT).
public void actionPerformed(ActionEvent e) {
statusLabel.setText("Processing File");
new Thread(new Runnable() {
public void run() {
// do something long task
SwingUtilities.invokeLater(new Runnable() {
public void run() {
statusLabel.setText("Done!");
}
});
}
}).start();
}
Using a Swing Worker Thread

As you've identified, processing the file means the Swing thread (which invoked this) is waiting for the processing to complete. So you need to invoke this in a separate thread.
The processing should run in parallel with other stuff (including the GUI updates). Once it's complete, it can call back on another component to signal that the GUI can update a status message (See SwingUtilities.invokeLater() and create an appropriate Runnable to do this)

You should process the file in a separate thread. This will allow you to kill two birds with one stone: First, your app will be more responsive. Second, the title change will actually happen.
OTOH, dealing with multithreading is a bit tricky. In particular, you may want to block some operations while the processing thread is running and then you need to rollback upon completion.
Keep in mind that the new thread cannot do GUI operaions directly: The non-GUI thread must use SwingUtilities.invokeLater() to ask the GUI thread to carry out operations on its behalf.

Related

Java: "please wait" GlassPane not correctly loaded

I have a java routine that takes several second to be completed. I'd like to load a GlassPane (possibly with a "prease wait" message inside) that prevents the user to modify the UI while that routine is under execution and that is automatically hidden when the routine finishes.
To do this, I use the following code:
Thread t = new Thread(new Runnable(){
#Override
public void run() {
/*
* `getPresentation().getFrame()` are methods that return the
* Frame which contains my UI
*/
getPresentation().getFrame().setGlassPane(myGlassPane);
getPresentation().getFrame().getGlassPane().setVisible(true);
}
});
t.start();
//this is the routine that takes several seconds to be executed
runCEM();
//hide the GlassPane
getPresentation().getFrame().getGlassPane().setVisible(false);
I set a specific java.awt.Cursor to myGlassPane. When I run the above code, I can see the new java.awt.Cursor appearing, but not the whole GlassPane with the "please wait" message and so on...
Any idea about what could cause this issue? Are there maybe other better ways to get what I'm looking for instead of using GlassPane and Thread?
Swing is not thread safe, so already, you're violating the single thread rules of Swing, possibly on two accounts. First, the glassPane should be shown and hidden from within the context of the EDT (Event Dispatching Thread).
Your long running process should be executed off the EDT.
The simplest solution I can think of is to use a SwingWorker. This provides a number of useful mechanisms which you can use to perform long running or blocking processes in another thread and update the UI safely with.
Take a look at Concurrency in Swing and Worker Threads and SwingWorker for more details

New thread and calling thread will be blocked Java Semaphore

I have some trouble with my java swing program. I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread.
I implemented that with java.util.concurrent.Semaphore.
The appearing Frame shows only an empty Frame, the buttons, lables and so on won´t be shown and both threads are blocked. I think there is a deadlock but I don´t find it.
My code for the new warning Frame, which will be called from the main Frame:
public class ExportWithoutEntryPointFrm extends javax.swing.JFrame implements Runnable
{
private Semaphore sema;
private boolean decision = false;
public ExportWithoutEntryPointFrm(Semaphore semaphore)
{
initComponents();
this.setLocationRelativeTo(null);
this.sema = semaphore;
}
#Override
public void run()
{
this.setVisible(true);
try
{
sema.acquire();
}
catch (InterruptedException e)
{
this.decision = false;
this.sema.release();
this.setVisible(false);
}
}
}
And the calling code from the main Frame:
Semaphore waitForDecisionSema = new Semaphore(1, true);
ExportWithoutEntryPointFrm warningFrm = new ExportWithoutEntryPointFrm(waitForDecisionSema);
warningFrm.run();
waitForDecisionSema.acquire();
First of all, calling a run() method of a Runnable doesn't start a new thread.
Second, even if it did, Swing components like JFrame MUST be used from the event dispatch thread only.
Third: since everything is done from a single thread, the EDT, as soon as this line is executed:
waitForDecisionSema.acquire();
the EDT is blocked waiting for some other thread to release the semaphore, and that will never happen, so the EDT is blocked forever, making your GUI unresponsive.
You seriously need to reconsider your design. But I don't know what you're trying to achieve, so it's hard to advise. Given the name of your semaphore, I think that what you're looking for is a modal JDialog, that would prevent the user to use the parent frame of the dialog until the dialog is closed.
I try to stop my main Frame thread when the ExportWithoutEntryPointFrm Frame appears in an own thread
Well, that's a massive contradiction in terms, Swing is a single threaded framework, you can operate components/frames/windows in separate threads, it won't work and you'll end up within no end of issues, dead locks been the most obviously.
Start by having a look at Concurrency in Swing for more details.
Now, there a number of mechanisms you can use to off load long running or blocking code to a separate thread and still interact with Swing, a Swing Timer for regular scheduled callbacks, SwingWorker for long running or potentially blocking calls, but which supports callbacks to the EDT, making it easy to use and even SwingUtilities.invokeLater for those times you have no other choice.
Have a look at How to use Swing Timers and Worker Threads and SwingWorker for more details
Based on you description though, I would suggest that what you really want, is a modal dialog, which will block the current frame/code execution at the point the dialog is made visible, but which will allow the UI to continue responding to the user.
See How to Make Dialogs for more details

Asynchronously control the BusyIndicator

Apparently all Eclipse/SWT has in the way of managing the busy mouse indicator is
BusyIndicator.showWhile(Runnable synchronousStuffToDo)
However, I have a fundamentally event-oriented project where "stuff to do" doesn't happen within a sequential line of execution: an action gets ordered and a continuation-callback is provided to the execution manager. Therefore I have nothing meaningful to put into that synchronousStuffToDo runnable.
Is there another, however low-level and clumsy, but platform-independent way of manipulating the busy indicator asynchronously, which means two separate method calls, "activate it" and "deactivate it"?
I should add ProgressMonitorDialog to this question because it appears to suffer from the same problem. Yes, within the ProgressMonitorDialog#run method an inner event loop will be spinned, but SWT event loop is just one of my execution managers, so the chain will still be broken. Apparently without this class I can't even show a progress monitor except if I reimplement from lower-level primitives.
There is no way you can manipulate the Cursor using the BusyIndicator class.
You can invoke the below util method to show a Busy Icon while running your job on a background Thread
public static void imBusy(final boolean busy){
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
Shell shell = Display.getDefault().getActiveShell();
if(busy){ //show Busy Cursor
Cursor cursor = Display.getDefault().getSystemCursor(SWT.CURSOR_WAIT);
shell.setCursor(cursor);
}else{
shell.setCursor(null);
}
}
});
}
Your runnable should wait for the task completion. E.g. (code written in browser, will not compile - I'm ignoring exceptions):
final Object condition = new Object();
BusyIndicator.showWhile(new Runnable() {
public void run() {
synchronized(condition) {
while (!isMyTaskDoneFlag()) {
condition.wait();
}
}
}
});
doTask(new MyTask() {
public void perform() {
try {
// Task logic
...
} finally {
// When done
setMyTaskDoneFlag();
synchronized(condition) {
condition.notify();
}
}
}
});
Make sure all code paths in your tasks do not forget to unblock the runnable. Pretty much the same approach can be used with progress monitors - you may wake your runnable to update progress monitor value.
Note: You need to make sure the waiting runnable is not executed on SWT thread (e.g. set fork to true if running in progress monitor) or else your application will become unresponsive.
I found a solution (which I don't particularly like, but it works) in an older SWT application I'm working on now. It uses BusyIndicator#showWhile, and the synchronous stuff it does inside is:
Start the asynch task in a background thread
Loop waiting for the background thread to finish up while at the same time spinning the
SWT event loop explicitly:
while (!taskDone){
if (!display.readAndDispatch() && !shell.isDisposed()) {
display.sleep();
}
taskDone = //check for task progress
//update something on the main window status bar
}
I'm trying to convert this to something cleaner (along the lines of what Marko suggested):
Set the busy icon
Submit background task
Unset the busy icon
but I'm not sure what would be best for updating the status bar (background tasks are actually remote calls so their thread is blocked until they finish up). I'm thinking of having a dedicated thread that detects when background jobs are running and update the status bar accordingly (the update is just an unfolding dotted line, nothing task specific), but using a thread just for this seems a bit of a waste.

UI thread waiting for other threads to execute - Not working

I have read that the main UI thread in android should not call sleep.
However, my application needs to :
call thread1 from main UI thread
call thread2 from main UI thread.
Use the output (2 images) of the 2 thread, add them and then display them.
I am using Thread.sleep() so that the main thread waits thread1 and thread2 till they are done. However mImageview.setbitmap is not working after i call it in the main thread (after sleep).
can u pls advise me how i should do this?
Multithreading in Android should be done Asynchronously. For this purpose, you should use the AsyncTask-class.
For your case, you would for example create a taks to load (or process) those two images. While the process is running (in another thread, off the UI-thread), you could show a ProgressBar that shows to the user that your application is currently busy (this is then done on the UI-thread).
When the task has finished, you get the results (your two images) from the task, hide the progress-bar and show everything to the user.
Despite the fact that a non-reacting GUI always has the feeling that your application frooze, if a UI-Thread is blocked for more then 5 seconds (which is a looong time), your application will be Force-closed as it is not "reacting" (and an ANR will be raised).
It's not just Thread.Sleep(). In the GUI thread, do whatever you need to to start the two threads/tasks/whatever and then exit the event handler.
Do not wait in GUI event-handlers! Not in Java, C++, C, Delphi, anything. Use an async task, or a Handler, and signal to the GUI thread. Thread 1 signals that it is done, thread 2 signals that it is done. In either case check to see if the data has been returned by the other thread. If it has, you have both sets of returned data and so you can add them and display them.
Do not wait in GUI event-handlers.
You can simply use Threads And Handlers for this purpose.
Here is a small demo for this,
Create a Handler in your onCreate like this,
Drawable d=null;
Handler handler=new Handler()
{
public void handleMesaage(Message msg)
{
if(msg.what==0)
{
imageView.setBackgroundDrawable(d);
}
}
};
And now call Your Thread like this,
Thread t=new Thread(new Runnable()
{
#Override
public void run() {
InputStream is = (InputStream) new URL(url).getContent();
d = Drawable.createFromStream(is, "src name");
handler.sendEmptyMessage(0);
}
});t.start();
I would suggest to use the ExecutorService. Here is how
Create the two image loading activities as Runnable tasks.
Execute them with the ExecutorService.
Use ExecutorService.awaitTermination(); for the main thread to wait for Runnable tasks to complete. Its documentation reads
Blocks until all tasks have completed execution after a shutdown
request, or the timeout occurs, or the current thread is interrupted,
whichever happens first.
This is the Asynch way of doing it and I guess should be preferred.

invokeAndWait method in SwingUtilities

Please explain invokeAndWait() method in SwingUtilities.I am unable to understand this.
Explain it very clearly. It would be of great help if you try out with an example.
Edited to add #noob's expansion of the question:
What's not clear about this?
Here's a modified usage example:
import javax.swing.SwingUtilities;
public class InvokeAndWaitStuff
{
public static void main(String[] args)
{
final Runnable doHelloWorld = new Runnable() {
public void run() {
System.out.println("Hello World on " + Thread.currentThread());
}
};
Thread appThread = new Thread() {
public void run() {
try {
SwingUtilities.invokeAndWait(doHelloWorld);
}
catch (Exception e) {
e.printStackTrace();
}
System.out.println("Finished on " + Thread.currentThread());
}
};
appThread.start();
}
}
Output:
Hello World on Thread[AWT-EventQueue-0,6,main]
Finished on Thread[Thread-0,5,main]
And why is this important?:
Causes doHelloWorld.run() to be
executed synchronously on the AWT
event dispatching thread. This call
blocks until all pending AWT events
have been processed and (then)
doHelloWorld.run() returns. This
method should be used when an
application thread needs to update the
GUI.
As far as I can tell, this is basically a bottleneck that forces GUI updates to be executed synchronously by a single thread, rather than asynchronously by multiple threads, which can potentially be unsafe.
To understand what invokeAndWait() does, you first need to understand the event/thread model of Swing.
Basically, everything that affects the GUI in any way must happen on a single thread. This is because experience shows that a multi-threaded GUI is impossible to get right.
In Swing, this special GUI thread is called the Event Dispatch Thread, or EDT. It is started as soon as a Swing top-level component is displayed, and it's bascially a worker thread that has a FIFO queue of event objects that it executes one after another.
When a Swing GUI needs to be drawn or updated, the JRE places an event on the EDT queue. User actions that cause listeners to be called start as events on the EDT queue. And (this is this is the important part) everything your program does that changes the GUI (like registering listeners, adding/removing GUI components or changing model data that the GUI displays) must be placed in the EDT queue, or the GUI can get corrupted.
And now for the finish: invokeAndWait() places the Runnable you pass to it into the EDT event queue and waits until the EDT has executed it. This should be used when a non-GUI thread needs to do something that affects the GUI, but also needs to wait until it is actually done before it can continue. If you just want to do something that affects the GUI but do not care when it is finished, you should instead use invokeLater().
I had a similar problem in a JTable. The program was blocked somewhere in "scrollRectToVisible" method. I have replaced the call by wrapping it in an invokeLater call.
The invokeAndWait did not resolve my block problem.
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
table.scrollRectToVisible(r);
}
});

Categories

Resources