Splash screen showing progress of GUI being built in Event Dispatch Thread - java

According to http://www.javaworld.com/javaworld/jw-08-2007/jw-08-swingthreading.html?page=5 all GUI operations should be executed in Event Dispatch Thread.
While I understand the reasons why Swing was designed with single threaded model in mind, I can't figure out how to solve the following problem:
Let's have a method called buildGui() which initializes main GUI of the application. Call to buildGui() method takes 10 seconds to return.
Let's have another method called splashScreen() which shows the JDialog with indeterminate JProgressBar inside. The purpose of the JDialog is obvious: it gives user feedback that application is loading resources, initializing components, etc.
Now, if my program calls:
splashScreen(); // build and show splash screen in EDT
buildGui(); // build main GUI in EDT
the splash screen is freezed for 10 seconds, because it waits for buildGui() to finish.
Do you have any ideas how to show splash screen which depicts the status of GUI initialization (buildGui()) while following Swing's single threaded model?

Use AWT for splash screens, so they can be loaded prior to loading the Swing package. The plug-in's own SplashScreen is pure AWT. See also this question re. use of SplashScreen & the EDT.
While I'm typically saying 'this millennium, use Swing components', it makes a lot of sense to use AWT for a splash.

Take a look at the Swing tutorial about splash screens which contains sample code doing exactly what you want

Related

Using SwingWorker to show a loading animation

My Problem:
I have a long executing task in my application (Needs to fetch data from the web), and I'm trying to display a loading screen with an animation (Just a rotating circle, no progress bar needed) while the task is being executed
What I have done so far:
I created the design for the loading screen in a panel and added it to a JFrame and tried to call instantiate the JFrame before the the code for the long process, and then dispose it after the process is done, like this:
LoadingFrame frame = new LoadingFrame();
//Long Process
Wiring wiring = new Wiring(node.source);
wiring.generateScopeForTargetNode();
// close() calls setVisible(false) and then dispose()
frame.close();
However, the frame did not get repainted until the task was done and all I received was a blank box, and in the end it didn't get disposed.
I searched SO for the problem, and found that it has to do with Threads and concurrency (Which I am unfamiliar with) and found suggestions to use JDialog instead of JFrame, so I followed the suggestion. What I ended up with is this:
The JDialog loads and gets painted but the animation does not play
The JDialog does not get disposed at the end
What I need Help with:
I have tried to search more for the problem and found suggestions that I should use SwingWorker to run one task in a thread and the animation in another if I have understood correctly. However I am unfamiliar with threads and with SwingWorker and need help in creating a simple SwingWorker instance that achieves what I'm trying to do
Use a SwingWorker "to fetch data from the web" in the background. publish() interim results as they arrive. Your implementation of process() can then safely update a view component's model on the event dispatch thread. With even modest granularity, the user will start seeing data instead of an uninformative animation. This complete example updates the TableModel of a listening JTable, but the Document of a listening JTextComponent would work as well.

Initialization of application and splash-screen with progress bar (Swing)

We have built a splash screen for our application. It works fine when the initialization of application is in the main thread, but when I move the initialization in EDT (SwingUtilities.invokeLater in main method), the progress bar and info label do not repaint itself due to blocking of EDT. I know, that using of invokeLater can help me to repaint the GUI. But my problem is: it's really hard to split the initialization of aplication in separate pieces (legacy code). And even if I do it, I will get a ugly matroshka-code (six times invokeLater in invokeLater).
Which solution should I prefer:
Leave initialization in main thread (my current decision)
Try to move it to EDT (if possible) and get matroshka code
Using Foxtrot lib to provide a non-blocking-sleep in EDT each time I update the splash screen (it works fine - the splash screen can repaint itself, but it's a hack for me)
Probably someone has a better solution?
P.S. I've already read some similar questions here but did not found anything helpful for me.
Load the source data in the doInBackground() method of a SwingWorker, and publish() intermediate results; update the GUI component's model in process(). While data continues to load, initial results will be displayed and the GUI will function nominally. The real time to load data will remain unchanged, but the perceived time will be less.

Forcing Java to refresh the Java Swing GUI

Ive coded two Computers to play each other in Reversi, however when they play each other. The board only updates after the game has finished.
From some googling around I know its has something to do the AWT Event Thread, but I still have no idea how to force the JFrame to refresh.
My function works by changing the icons and then calling revalidate and repaint.
Any pointers would be wonderful.
If you start your AI game from an actionPerformed(), it is executed in EDT thread. You should move your logic (and your sleep()'s outside of EDT thread by starting a new Thread to allow Swing to repaint UI properly and post updates to UI as following:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
myUI.update(); // repaint(), etc. according to changed states
}
});
Also consider use of javax.swing.SwingWorker, javax.swing.Timer and take a look at Concurrency in Swing.
Sounds like a threading issue - Event Thread is not being given a chance to execute. I would start with some sleep commands in the logic / action threads to give time for the UI to update.
Also, you could have an "updateUI" thread and run that on an invokeAndWait to force it to update the display. Call that after each move has been completed.
If you need to force the application to redraw, you should invoke the repaint() method on the component containing the game board. This should cause Swing to repaint the board.

Initializing Java Swing in the background

I have a question regarding quick initialization of swing components. At the start of my swing application I have a window that pops up with buttons that allow the user to do a variety of things. Is there I way that I can quickly launch that first window and load the rest of the UI (such as other frames and dialogs) in the background so that there is isn't that initial delay.
Thanks,
Is Swing thread safe?
Yes. Ish. You could do something similar to:
public static void main(String [] args) {
// Construct main Frame on Swing EDT thread
Runnable goVisible = new Runnable() {
public void run() {
JFrame mainFrame = new JFrame();
mainFrame.setVisible();
// etc.
}
};
SwingUtilities.invokeLater(goVisible);
// now the background init stuff
Class.forName("com.yourcompany.view.Dialog1");
Class.forName("com.yourcompany.view.WizardGUI");
Class.forName("com.yourcompany.view.SecondaryFrame");
// Here all the views are loaded and initialized
}
Display blank main frame first and then load the rest of UI. You can use Swing Application Framework (or BSAF now) to init components and build layout when app is ready (main frame is visible) - Application.ready() method. Use http://code.google.com/p/jbusycomponent/ to show that app is loading...
There really is no good solution to this, it is one of the drawbacks of Java. That being said keep reading for my idea.
There are two parts to loading a class.
The JVM loads the class file into
the ClassLoader when it is needed.
The JIT compiles and optimizes the
code the first time the path is run.
You can do what rekin suggests, which is to eagerly load the UI classes before they are needed. That will only partially solve your problem, because you are only getting some of the classes. This will also have the disadvantage of taking up a lot more memory and even the classes in the class loader will be garbage collected if needed.
In order to avoid some of the hassles you are getting with the Reflection Approach.
One method you could try is in your windows make sure the constructor does not display a window, instead have another method that would display the window called init(), Then have a separate Thread from main call create a new on each of the Windows you want to preload.
Do not save the reference to the window.
In the real code you would call the constructor and then init() for each window you wanted to display. This would give you the best possible scenario as far as performance, because now you are loading the classes as well as running the constructor code. Of course the size of the program in memory will be bloated.
public static void main(String [] args) {
// Construct main Frame on Swing EDT thread
Thread thread = new Thread() {
public void run() {
// now the background init stuff
new com.yourcompany.view.Dialog1();
new com.yourcompany.view.WizardGUI();
new com.yourcompany.view.SecondaryFrame();
// Here all the views are loaded and initialized
}
};
JFrame mainFrame = new JFrame();
mainFrame.setVisible();
// etc.
}
That's the goeal of having a Splash Screen(with or without a progress bar - much nicer with it, of course). You should show a nice splash to your users and then you initialize all your components starting with the main window on the EDT thread and at the end you show up your frame. Creating Swing components outside EDT might(it will sure do) create problems with visibility at least but also with concurrent access between your thread and EDT. DON'T do that, it's hard to detect these issues and it might manifest random on different hardware.
Of course, if you have a progress bar you need some free EDT time to render progress bar changes - actually even to refresh the splash screen itself(repainting the background image if another application blocked for a while your splash) you need free time on the EDT.
You should split your initializations in smaller blocks that will not take more than 500ms to run and you schedule them on the EDT with SwingUtilities.invokeLater.

Java swing progress bar from EDT problem

This is for the swing experts out there. I have spent considerable time on this problem, so it is going to take me a few lines to explain the problem.
I have a standalone java swing application (java 6). In my application, I have a frame with a radio button group. I have a single action linked to all the buttons in the group. The action checks to see which radio button is selected and performs some work. The "work" involves some background computation as well as some painting in two other frames in my application. The background computation is multi-threaded.
I would like to display a progress bar when the user selects one of the radio buttons.
However, when a radio button is selected, while the action to the radio button is happening, the progress bar never appears. I have tried jdialog type progress bars, glass panes, etc. None of them appear until the "work" is all completed. This seems to be because Swing does not finish painting the radio button until the "work" in the corresponding action is completed. And since the EDT only does one thing at a time, the progress bar dialog (or glass pane) is never displayed.
I then tried to use a SwingWorker to do all this "work". Start the progress bar (or activate a glass pane), start the SwingWorker and close the progress bar (or deactivate the glass pane) in the done() method for the SwingWorker. This seems to bring up the progress bar fine, but the painting which is part of the "work" is sometimes not completed, leaving me with some painting artifacts (the paintComponent method is pretty complicated, so do not want to reproduce here). The artifacts disappear if I resize the window. In fact, this happens if I use a class which extends Thread instead of SwingWorker too. This is all because Swing is not threadsafe and I am trying to do GUI work from a thread other than the EDT. I understand that part.
What do I do? "work" takes about 30 seconds and that seems too long to go without showing the user some kind of indication that the program is working. I have also tried changing the cursor to a wait cursor and have run into the same problems as above. The only thing that I can do is disable the frame and set the title of the frame to some text like "working..."
Anybody seen this problem before?
I think you are right to do the work in the SwingWorker thread, but you shouldn't be trying to do your painting there.
I'd be inclined to:
Have the ActionListener show() the progress bar, set off the swingworker then exit
Have the worker thread do the work, and periodically call repaint() on the progress bar component (this is guaranteed to be thread safe)
Progress bar has it's own paintComponent (which will be automatically called on the EDT). If necessary, this can read some variable that is updated by the worker thread to measure progress
When the worker thread finishes, have it call invokeLater() to run a final close down function on the EDT, which will hide the progress bar and do any other GUI-related cleanup / show a completion message to the user etc.
When you moved the work from the EDT to the swing worker (which was the right thing to do), it sounds like both the work and the painting moved to the swing worker. The painting should still happen on the EDT. You can achieve this by using SwingUtilities.invokeLater to invoke a repaint from the background thread, or by using the SwingWorker.publish(V...), which will take notifications from your worker thread and make them available on the EDT via the SwingWorker.process(V...) template method (which you override). Your process override can handle the intermediate notifications by repainting a portion of the screen, updating progress, or taking some other appropriate action as desired. Any UI changes done here will be visible without waiting for the rest of the work to complete.

Categories

Resources