I have a panel that displays text. I want the panel to change its text and then have the application pause before anything else happens. I'm using Thread.sleep(1000). For some reason, though, the application doesn't finish painting the panel before Thread.sleep gets called (the text doesn't get changed). I also tried this:
board.invalidate();
board.setLeftMessage("Not");
board.setRightMessage("Here");
board.revalidate();
Date current = new Date();
long timeNow = current.getTime();
Date newDate = new Date(timeNow + 1000);
while (current.before(newDate))
current = new Date();
but no luck there either. Anyone have a suggestion?
Thanks so much.
You are blocking the AWT Event Dispatch Thread (EDT). The EDT handle repainting and input events, so your code need not be multithreaded (which would be effectively impossible). Use javax.swing.Timer to send an event later on the EDT. (Do not confuse javax.swing.Timer with java.util.Timer!)
Take a look at javax.swing.Timer - I think this is what you'll need to accomplish this.
EDIT #1: The Sun\Oracle documentation actually suggests using Swing Timers from here.
In general, we recommend using Swing
timers rather than general-purpose
timers for GUI-related tasks because
Swing timers all share the same,
pre-existing timer thread and the
GUI-related task automatically
executes on the event-dispatch thread.
However, you might use a
general-purpose timer if you don't
plan on touching the GUI from the
timer, or need to perform lengthy
processing.
EDIT #2: It looks like there are some good basic tutorials here.
EDIT #3: Removed suggestion of using TimerTask - in this case it would be a bad idea.
Your "long running task" needs to run in a separate Thread. Then when you want to update the GUI you need the code to run on the Event Dispatch Thread (EDT). Then you can ask the separate Thread to sleep and it won't affect the painting of the GUI.
You should be able to use a SwingWorker for this. Read the section from the Swing tutorial on Concurrency for more information.
If you don't like using the SwingWorker, then you need to create your own Thread and wrap the code that updates the GUI in a SwingUtilities.invokeLater().
You shouldn't be updating GUI components from your main thread. Use SwingUtilities.invokeLater to schedule your update on the event thread:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
board.invalidate();
board.setLeftMessage("Not");
board.setRightMessage("Here");
board.revalidate();
}
};
Thread.sleep is a long running task. When you a running such a task in the EDT it blocks all repaint requests from being executed. All repaint requests which are pending and which were sent during the sleep phase are queued for future processing.
As a result when the EDT comes out of the sleep phase it coalesce all such repaint request (if coalescing is enabled which is the default property) into a single repaint which gets executed. If coalescing is not enabled then all queued request are executed serially without any time gap in between. As a result it seems that the UI did not update.
To correct the situation use a timer which triggers periodically after specific intervals of time.
Related
Here is a snippet
kit.insertHTML(doc, doc.getLength(), "Hello", 0, 0, null);
try{
Thread.sleep(1000);
}catch(Exception e){}
I am using HTMLEditorKit() and HTMLDocument() as a textbox.
The textbox should show "Hello" then wait one second however, when I try this, It waits one second then puts the word "Hello" which is not what I want.
I am not sure why this happens because I put this in the logical order. If anyone can help me with this, that would be great.
EDIT:
Does anyone know an alternative, so I can use the "delay" sort of effect?
Don't ever call Thread.sleep(...) from within the Swing event thread as this will put the event thread itself to sleep. Since this thread is responsible for all Swing painting and user interaction, this will put your application to sleep.
If all you want is a delay in the display, then consider use of a Swing Timer.
If on the other hand your event thread is being compromised by a long-running task, then do the task in the background, using a SwingWorker (as suggested by Guillaume 1+ to him).
You are calling sleep on the EDT (Event Dispatching Thread). You should avoid this situation as indeed, it freezes the UI.
To avoid this situation, use a SwingWorker instead or as suggested by HFOE, use a Swing Timer
Thread.sleep is a long running task. When you a running such a task in the EDT it blocks all repaint requests from being executed. All repaint requests which are pending and which were sent during the sleep phase are queued for future processing.
As a result when the EDT comes out of the sleep phase it coalesce all such repaint request (if coalescing is enabled which is the default property) into a single repaint which gets executed. If coalescing is not enabled then all queued request are executed serially without any time gap in between. As a result it seems that the UI did not update.
To correct the situation use a SwingTimer which triggers periodically after specific intervals of time, or a SwingWorker.
Here is a snippet
kit.insertHTML(doc, doc.getLength(), "Hello", 0, 0, null);
try{
Thread.sleep(1000);
}catch(Exception e){}
I am using HTMLEditorKit() and HTMLDocument() as a textbox.
The textbox should show "Hello" then wait one second however, when I try this, It waits one second then puts the word "Hello" which is not what I want.
I am not sure why this happens because I put this in the logical order. If anyone can help me with this, that would be great.
EDIT:
Does anyone know an alternative, so I can use the "delay" sort of effect?
Don't ever call Thread.sleep(...) from within the Swing event thread as this will put the event thread itself to sleep. Since this thread is responsible for all Swing painting and user interaction, this will put your application to sleep.
If all you want is a delay in the display, then consider use of a Swing Timer.
If on the other hand your event thread is being compromised by a long-running task, then do the task in the background, using a SwingWorker (as suggested by Guillaume 1+ to him).
You are calling sleep on the EDT (Event Dispatching Thread). You should avoid this situation as indeed, it freezes the UI.
To avoid this situation, use a SwingWorker instead or as suggested by HFOE, use a Swing Timer
Thread.sleep is a long running task. When you a running such a task in the EDT it blocks all repaint requests from being executed. All repaint requests which are pending and which were sent during the sleep phase are queued for future processing.
As a result when the EDT comes out of the sleep phase it coalesce all such repaint request (if coalescing is enabled which is the default property) into a single repaint which gets executed. If coalescing is not enabled then all queued request are executed serially without any time gap in between. As a result it seems that the UI did not update.
To correct the situation use a SwingTimer which triggers periodically after specific intervals of time, or a SwingWorker.
With Java Swing, is it possible to pause the current thread Runnable and give room to the Event Dispatching Thread to update the gui?
I know it is possible with multi-threading (SwingWorker class) but I was wondering if there's an easier way to achieve this for single threaded programs (aka: all my code is in the gui's Run()).
E.g. Matlab has the very convenient drawnow; method
If not: how can I split the updating task to a second thread without having to rewrite anything? Would that be the Updating the gui from a running thread from this link?
The short answer is no. If you pause the current thread (which according to you is the EDT) then you pause the EDT...
You can make requests that the UI be updated using methods like repaint, but this also assumes you are not blocking the EDT with things like loops and pauses, as the EDT will need time to process these requests.
And no, I wouldn't follow the link's advice, as it violates the single thread of Swing by updating the components outside of the of EDT
Depending on your needs you would either need to use a javax.swing.Timer or SwingWorker. Yes, you can use a Thread, you become responsible for ensuring that all updates to the UI are synced back to the EDT, which the other two suggest provide mechanisms for.
Take a look at Concurrency in Swing for more details
The task I need to perform involves requesting some data from an external server, performing some (fairly lengthy) processing on the data, and then updating the GUI with the results of the processing. Because the server might be unresponsive, the task is well suited to a SwingWorker: the doInBackground() method gets the results, and then the done method updates the GUI.
I need this to happen once every few seconds. I know I can just use a while loop and Thread.sleep, and create a new SwingWorker after each sleep. But everything I've read frowns upon using loops and sleep. I'd like to use a timer but:
Using a swing timer seems counterproductive; since they run on the EDT, I would essentially have no reason to use SwingWorker's doInBackground method. If the server were not responsive, the GUI would be unresponsive.
Using a java.util.Timer seems a bit wasteful: it seems to create a background thread for the TimerTask(), and since I am just creating a SwingWorker to do the actual work, I'm essentially creating a background thread that creates another background thread.
Can anybody tell me what's the best solution? I'd like to stick with SwingWorker since it seems ideally suited to the task, but I would like to avoid using a while loop if I can help it.
Thanks
You could use a ScheduledExecutorService:
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
// get a scheduled executor service with one thread
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
// schedule the worker at an intervall of 5 seconds
scheduler.scheduleAtFixedRate(myWorker, 0, 5, TimeUnit.SECONDS);
I don't see why you couldn't use a Swing Timer to start a Swing Worker. What have you tried?
I think you're on the right track with SwingWorker. Now you need to look at its publish and process methods. As your processing progresses, you publish() an object from the background thread then the process() method is called on the Swing(EDT) thread so you can update the gui.
This way there aren't a bunch of timers and other threads to coordinate.
The javadocs have a straightforward example with prime numbers:
http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
How large is the set of data you are retrieving? If it is fairly small I would completely detach the task of fetching/processing and displaying.
Use some sort of in memory cache to hold the most recently processed set of data.
Use a javax.swing.Timer to update the GUI with the cached data.
Use a java.util.Timer to fetch the data from the database, process it and update the cache.
Be careful of synchronisation issues between the two times on your cache. You don't want your swing timer grabbing data at the same time as the other timer is updating it.
A GUI using Swing, must update part of its UI from a every 5 seconds. (output.setPage(url))
The code is running in a timer, but on every update, the GUI hangs.
How do I avoid making the UI hang?
Here is my code:
<insert code here>
Assuming you are using a setPage() method of JEditorPane, the event dispatch thread is blocked while the page is fetched. Using SwingWorker is a reasonable alternative.
Addendum: SwingWorker is convenient for showing progress; but as an alternative, you might look into the asynchronous feature of setPage() using setAsynchronousLoadPriority().