How to properly implement a glass pane in Java? - java

I'm attempting to add a fancy InfiniteProgressPanel as a GlassPane for my big Swing program. However, it does not appear. It looks similar to this:
...
InfiniteProgressPanel glassPane = new InfiniteProgressPanel();
setGlassPane(glassPane);
...
glassPane.start();
doSomeStuff();
glassPane.stop();
...
I believe it is running in the same thread as the long process it is meant to cover up. I'll admit, I don't know nearly enough about threads, and I should probably figure out how to run that InfiniteProgressPanel GlassPane in a separate thread, and the long process in its own thread, too.

Be sure to:
Run all long running code in a background thread. This is a must.
Sounds great! How do I do so? Encapsulate all of the long-running code inside of an .invokeLater method? And should that be SwingUtilities.invokeLater or EventQueue.invokeLater? And what's the difference, anyway?
No, by using SwingUtilities.invokeLater(new MyRunnable) you're doing exactly the opposite -- you're guaranteeing that the long-running code will be called on the Swing event thread -- the exact opposite of what you want. Instead use a SwingWorker's doInBackground() method to run the long-running code. Regarding your second point, there's no difference whatsoever between SwingUtilities.invokeLater and EventQueue.invokeLater.
Make most all Swing calls on the Swing event thread, also a must.
Fantastic! Again, how do I do so? Same thing as above?
By using SwingUtilities.invokeLater(new MyRunnable) as noted above, or if you're using a SwingWorker then use its publish/process method pair as the SwingWorker tutorial will show you.
Call setVisible(true) on your glass pane since per the JRootPane API, all glasspanes are by default invisible.
Romain Guy's InfiniteProgressPanel doesn't seem to need a setVisible(true). It appears when the InfiniteProgressPanel.start() method is called.
I am not familiar with this, do you have a link?

Threads are different processes in the same program, per se.
In java, there are many different thread types, and the one you need for this job is SwingWorker.
The definition/use of this, from Oracle's docs, is:
When a Swing program needs to execute a long-running task, it usually uses one of the worker threads, also known as the background threads. Each task running on a worker thread is represented by an instance of javax.swing.SwingWorker. SwingWorker itself is an abstract class; you must define a subclass in order to create a SwingWorker object; anonymous inner classes are often useful for creating very simple SwingWorker objects.
As you can see, this is what you need; a background thread.
final InfiniteProgressPanel glassPane;
...
class GlassPaneHandler extends SwingWorker<String, Object> {
#Override
public String doInBackground() {
glassPane.start();
return setUpPaneAndStuff();
}
#Override
protected void done() {
try {
glassPane.stop();
} catch (Exception e) { } //ignore
}
private void setUpPaneAndStuff() {
//code
}
}
...
(new GlassPaneHandler()).execute(); //place this in your code where you want to initiate the pane
for more see:http://docs.oracle.com/javase/8/docs/api/javax/swing/SwingWorker.html

When you are updating a swing UI you need to do it in Swing's Event Thread. This includes creation of components or any sort of progress updates. You can do this via the SwingUtilities.invokeLater(Runnable) method.
Therefore, you should create the glasspane and show it via the invokeLater if in a background thread. Any progress updates to the glasspane from your long running process thread should be done via the invokeLater.

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

When and Where to call EventQueue.invokeLater() method

I'm totally fresh about threading and GUIs, therefore I couldn't figure out exactly where to call this EventQueue.invokeLater() method.
Am I supposed to call it in every event listeners and something else? What are those "things" to call this method? If so, is there any alternative way to call-once-apply-everywhere method so that It won't take bunch of lines to tuck them to the Event dispatch thread?
Thank you.
therefore I couldn't figure out exactly where to call this EventQueue.invokeLater() method.
Swing components need to be updated on the EDT so you would only use invokeLater(...) if you have code executing in a separate Thread and you want to update a GUI component.
Read the section from the Swing tutorial on Concurrency for more information.
As a general rule, unless you are using Threads, you only need to use this method when you create your GUI. Take a look at the FrameDemo from the section in the Swing tutorial on How to Make Frames for a simple example to get you started.
Am I supposed to call it in every event listeners?
No!
All code in an event handler already executes on the Event Dispatch Thread (EDT)so you don't need to invoke this method.
Swing is not thread safe. Which means that all interactions with Swing objects should be done via the event thread. Swing does this internally as well, so any time Swing calls an event listener, this will be done on the event thread.
This means two things, firstly, if you ever need to interact with a Swing object, your code should be invoked on the event dispatcher thread.
Also, it means that if you have any code in your event listeners that will run for any noticeable period of time, should be invoked on another thread from your listeners. If you do not do this, then your UI will appear frozen. A SwingWorker object can help with this.
To answer your question about needing to check EventQueue.isDispatchThread() that you asked in the some of existing answers' comments:
No, you don't have to check if you are already on the EDT before calling invokeLater().
The SwingUtilities JavaDoc states:
If invokeLater is called from the event dispatching thread -- for example, from a JButton's ActionListener -- the doRun.run() will still be deferred until all pending events have been processed. Note that if the doRun.run() throws an uncaught exception the event dispatching thread will unwind (not the current thread).
Below is further explanation of invokeLater() use.
Notice in ButtonDemo.java that createAndShowGUI() is called using invokeLater(). We must do this because the main() method is not running on the EDT (Event Dispatch Thread). main() is running on its own special main thread that every Java app has.
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
However in actionPerformed(), the invokeLater() method is not used because here we already on the EDT.
//b1, b2, and b3 are all JButtons
public void actionPerformed(ActionEvent e) {
if ("disable".equals(e.getActionCommand())) {
b2.setEnabled(false);
b1.setEnabled(false);
b3.setEnabled(true);
} else {
b2.setEnabled(true);
b1.setEnabled(true);
b3.setEnabled(false);
}
}
As far as I can recall, Event Listener methods such as actionPerformed() are always called from the EDT. (Sorry I don't know supporting documentation off-hand, and I don't have enough reputation yet to post anymore links anyway. Along with reading the pages linked in camickr's answer, try Google searching for "java tutorial swing introduction event listeners".)
So if you are trying to update a Swing component from a thread other than the EDT, call invokeLater(). If you are in an Event Listener method (i.e. already on the EDT), you don't need to call invokeLater().

Does displaying Java GUI requires some special treatment?

I was looking at some example code of GUIs in Java, and I was wondering what the proper way to display a GUI. Suppose a createAndShowGUI() method is written for some GUI. I saw something like this:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
Would it be wrong simply to call createAndShowGUI() at the end of the main method without the javax.swing stuff? Or I guess my real question is about what is going on here. I'm familiar with threads but I am not sure why it's necessary to make a new thread (is that what's going on here?) to display the GUI.
All interactions with the UI (Swing or AWT) MUST be executed from within the context of the Event Dispatching Thread.
Swing (and AWT) components are not thread safe, changing any of them from any thread other the EDT can lead to corrupted updates, paint artifices, dead locks and possibly crash the VM. They are also notoriously difficult to debug.
You might like to have a read through
The Event Dispatch Thread
The Single Thread Rule in Swing
Will the real Swing Single Threading Rule please stand up?
I should also add, when the main method is executed, it is running in what ever thread the VM created for it. This is guaranteed not to be the EDT, as it will not have begin started until it is needed.
This is why good Swing programs always start with something like EventQueue.invokeLater. You could also use SwingUtilities.invokeLater, but it's generally the same thing.
Because everything related to a GUI should be done through the Event Dispatch Thread (EDT), that is how Java manages the whole drawing of interfaces. Basically the method delegates the execution of the run() method of the passed Runnable object to the correct thread.
Mind that Runnable is not a Thread, it's just an interface to provide a method that does something (hence the class is runnable). But there is no thread involved here, the fact that Thread extends from Runnable is just because a thread is also a Runnable object in the sense that can execute something.

Changing Color of a Java graphic object

I'm trying to flash a Java graphic object by changing the color and calling the repaint() method. The color is only updating with the final change color call. Here is my code:
public void start() {
try {
Color origColor = node.getColor();
for (int i=0; i<noOfFlashes; i++) {
Manager.gui.getDrawGraph().changeNodeColor(node, Color.WHITE);
Thread.sleep(500);
Manager.gui.getDrawGraph().changeNodeColor(node, origColor);
Thread.sleep(500);
}
Manager.gui.getDrawGraph().changeNodeColor(node, Graph.VISITED_NODE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
and the change node color method is:
public void changeNodeColor(Node node, Color c) {
node.setColor(c);
repaint();
}
The change node color is in the same class as the paint component.
Any help would be much appreciated.
You need to use separate thread to manage your GUI event.
You can do this, using a SwingWorker, as suggested by Amine, or implement the Runnable interface, or extend the Thread class, developing the run() method, that is the task of your thread.
You can read this old question of SO : How do I use SwingWorker in Java?
A tutorial for SwingWorker : http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html
A tutorial to make a Thread : http://docs.oracle.com/javase/tutorial/essential/concurrency/
The color is only updating with the final change color call.
If you don't use a separate thread, your gui will freezing until the method is completely executed, and you won't see the color change separated by Thread.sleep(500);.
UPDATE
In this link, in the paragraph Why does a Swing GUI freeze or lock up?, you can understand why a Java Swing GUI freezes, with the use of a single thread.
Check also this official link, in the paragraph Creating Threads, and this page, that returns:
Swing's single-thread rule says that Swing components can only be
accessed by a single thread. This rule applies to both gets and sets,
and the single thread is known as the event-dispatch thread.
The single-thread rule is a good match for UI components because they
tend to be used in a single-threaded way anyway, with most actions
being initiated by the user. Furthermore, building thread safe
components is difficult and tedious: it's a good thing not to be doing
if it can be avoided. But for all its benefits, the single-thread rule
has far-reaching implications.
Swing components will generally not comply with the single-thread rule
unless all their events are sent and received on the event-dispatch
thread. For example, property-change events should be sent on the
event-dispatch thread, and model-change events should be received on
the event-dispatch thread.
For model-based components such as JTable and JTree, the single-thread
rule implies that the model itself can only be accessed by the
event-dispatch thread. For this reason, the model's methods must
execute quickly and should never block, or the entire user interface
will be unresponsive.
I think that the sentences above are very useful to understand better the Swing package.
I report the suggestion of trashgod.
You can use the Timer class, from the javax.swing.Timer package. That is also a good alternative.
In this question, trashgod reports some examples of Timer.
Check here for a tutorial about Timer.
Based on what i understand from your code, I will probably recommend the use of SwingWorker.
I know you do not have any cost expensive code but you using SwingWorker, you will be able to update your GUI more easily.
I am not sure which framework you're using here... but you may need a repaint() just before the Thread.sleep(). Is there a Manager.gui.repaint() perhaps? (Sorry, complete guesswork here...)

What is the rationale of SwingWorker?

For what I can read, it is used to dispatch a new thread in a swing app to perform some "background" work, but what's the benefit from using this rather than a "normal" thread?
Is not the same using a new Thread and when it finish invoke some GUI method using SwingUtilities.invokeLater?...
What am I missing here?
http://en.wikipedia.org/wiki/SwingWorker
http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
Yes, you can accomplish what a SwingWorker does with vanilla threads + invokeLater. SwingWorker provides a predictable, integrated way to accomplish tasks on a background thread and report result on the EDT. SwingWorker additionally adds support for intermediate results. Again, you can do all of this yourself but sometimes it's easy to use the integrated and predictable solution especially when it comes to concurrency.
A code example:
import org.jdesktop.swingx.util.SwingWorker; // This one is from swingx
// another one is built in
// since JDK 1.6 AFAIK?
public class SwingWorkerTest {
public static void main( String[] args ) {
/**
* First method
*/
new Thread() {
public void run() {
/** Do work that would freeze GUI here */
final Object result = new Object();
java.awt.EventQueue.invokeLater( new Runnable() {
public void run() {
/** Update GUI here */
}
} );
}
}.start();
/**
* Second method
*/
new SwingWorker< Object , Object >() {
protected Object doInBackground() throws Exception {
/** Do work that would freeze GUI here */
return null;
}
protected void done() {
try {
Object result = get();
/** Update GUI here */
}
catch ( Exception ex ) {
ex.printStackTrace();
if ( ex instanceof java.lang.InterruptedException )
return;
}
}
}.execute();
}
}
The choice always depends on personal preference and use case.
The second method has an advantage when refactoring. You can more easily convert the anonymous class to an inner class when the method it's used in is too large.
My personal preference goes to the second, for we have built a framework where SwingWorkers can be added and are executed one after the other...
SwingWorker is an implementation of a common pattern (in .Net i read there is GuiWorker BackgroundWorker for this), where you have to do some work in a GUI program, but keep the GUI responsive. The problem is that often GUI libraries are not multi thread safe, so the common way to implement such workers is to use the message loop of the library to transfer messages into the event loop of the application.
These classes allow you to easily update your GUI. Usually, they have a update(int status) method that is called by the thread, dispatched by the class, and handled by the GUI, while the thread continues its work.
Using normal threads, you would need to code your own events or some other messaging mechanism for this task, which can be a pain if you need this functionality often. Using invokeLater in Java for example, you would intermix the code for updating the gui into the code for doing the work. The SwingWorker allows you to keep things separate.
to answer your question, you are not missing anything. this class is just a convenient utility for wrapping up the functionality you discribed (start another thread to do the background work and then invoking some final action on the EDT with the results).
When working with Swing, it is important to know that the main swing processing (ie. rendering) happens on a single thread (which is not your main thread). This is often called the Swing or awt event thread. Those familiar with the JDK pre 1.6 will remember the "grey rectangle" bug if you spent too much time in an event dispatcher for a swing component. What does this mean. In any swing application you will have 2 threads running that you will now have to deal with. Normally if all your operations within an event dispatcher (the code that gets fired say when a button is clicked) is short (ie. changing the state of a siwng button) you can just run this inside of the event dispatcher. If your application is going to call a web service or a database, or you application state is driven by external events (ie. jms) or you want to just make your UI more interactive (ie. build a list of items and be able to do something else) you should use a thread other than the awt event thread (the main swing one). So in these cases you spawn a new thread and do what you have to, and when the results finally come back, you then somehow have to create an event that can be executed by the awt/swing dispatcher. SwingWorker is a great little design pattern that allows you do to do this (the other way is SwingUtilities). It is particularly useful for doing fetch data from external sources or say long calculations (rendering a graphics scene). It helps automate the dispatch and subsequent re-integration of the results from an external thread (other than the awt thread). For async events (ie. an event from JMS needs to update a result, use SwingUtilities).
SwingWorker makes trivial example code much more concise. However it creates a ball of mud. Communications to and from the GUI and executed logic are all welded together. So, I'd not like to see it used in real production code.
SwingWorker is far easier than mucking with your own threads because it gives you two things that are painful to manually, thread coordination between the UI and the background process and doing loops effective, background work that keeps working and sending updates back to the UI incrementally, like process a large amount of data, or loading a large list. The disadvantage (or advantage) depends on how you look at it, is that it hides the underlying implementation, so future version may have different behavior, performance, etc, which may be undesirable. I've found it quite useful as the glue between a UI event and my own command code, the SwingWorker maintains the link to the UI and my code pumps data.

Categories

Resources