Using SwingWorker to show a loading animation - java

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.

Related

JFrame opens blank, runs a loop, and then displays components

Okay, so this problem has been plaguing me for the past few days. And before anyone comments about it, yes I have made the jframe visible and I have added all the components that I need to it. Also, all components are added well before the GUI is set to visible and activate() is called.
So I am trying to run a couple simeple lines of code.:
g.setVisible(true);
g.activate();
Simple enough. g is an object made from a class I made GUI which extends JFrame. and activate() is a method that runs an infinite loop that just does a bunch of things until the user tells it to exit. However, when the program gets to the g.setVisible() line it opens a JFrame that is the size I specified however is completely devoid of anything. Then it moves onto the g.activate(); which at the moment runs for a specific amount of iterations and stops. At which point it finally decides that it can go back and display my GUI. The issue with that is that the GUI is meant to be updated by the loop from active() and keep the user in the know of what is going on.
Any help is appreciated let me know if you need more detials and thank you in advance.
In many different UI frameworks, it's common for the methods you call to queue some work rather than perform it immediately. From your description, it seems like setVisible() may be creating a native window but then queuing the rendering of the components. Since this code is (presumably) running in the UI thread, it won't perform the work it queued until after running activate().
Long-running tasks should never be run on the UI thread. In Swing, you can use SwingWorker or explicitly create a background thread.

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.

Java: How should I implement waiting so that Images render?

I'm not sure I've really asked the question correctly...and I'm not even sure if I've relevantly phrased the question or not..So, I apologize in advance...but I'm quite stuck on this issue and appreciate all help.. Further, I'm frankly not an expert so...please be gentle, I'm not trying to be an idiot.
So, the point of my program, frankly, is a simple game, based off of a certain game show on TV which has lifelines.. This specific one is the "phone a friend" one... I have a quote on quote 'button' (really a JPanel that has a MouseListener). Once this button is pressed, I would like it to add, and paint a JLabel or JPanel onto the JFrame, whatever works to draw an animated gif (of a countdown) and to lock the other Components until 30 seconds have occurred. For the reference, I am not using a LayoutManager at the moment...
The way I've been attempting to do this, is:
ImageIcon CountdownImg = new ImageIcon("countdown.gif");
JLabel CountdownLbl = new JLabel(CountdownImg);
this.getContentPane().add(CountdownLbl);
CountdownLbl.setLocation(200, 200);
CountdownLbl.setSize(new Dimension(CountdownImg.getIconWidth(), CountdownImg.getIconHeight()));
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() < startTime + 30000) {
;
}
I know the problem exists with my while loop. Without the loop, the image renders successfully. With it, java waits until after the condition is met to render CountdownLbl. I've also tried creating another JFrame with a content pane that had the image, but (probably again, due to my own misunderstanding or poor threading..) but the Frame simply appears and does not render its contents. Sometimes while running it I notice that there is a Image Fetcher thread, I'm assuming that my very bad loop could be interfering with this thread, and that this thread is what is responsible for rendering my image.
So I guess the question should be...How can I really implement this...in a thread safe way? If that is correct?
Thank you for your time, patience and effort.
Use a SwingWorker to download images in the background. In this example, a single component is updated in done(), but you can publish() and process() images as they arrive. This related example outlines the approach.
Since you're question is tagged AWT, I suggest that you use a MediaTracker to load your images. See the docs for a good description of how to use this to wait until your images are loaded.
You can also try using ImageIO.read(URL) to retrieve a BufferedImage.
To create an ImageIcon from a URL, just use the constructor ImageIcon(URL).
The thread responsible for drawing the image icon is same as the thread which is executing the while loop in your case.There is something called EDT , event dispatcher thread which updates your swing UI.You are using the same EDT to wait the countdown.
You might want to look into this SwingUtilities.invokeLater()
EDIT:
Should have added more information : here it is , Using SwingWorker & SwingUtilities

My Swing Component Graphics Not Updating

I realize that without code this might be hard to answer but the problem is I am not sure what code to post. My problem is that when I load an XML file, unmarshal it and then iterate a ArrayList of values loaded in to repopulate a JLabel array that get placed on a JPanel inside a JScrollPane, the graphics do not update until the entire processing is done. I discovered this when I created a JFrame that opened up with a JProgressBar. The bar does not even show or paint on the pane Frame until everything is done. This defeats the purpose since I am trying to have the progress bar show the progress of the decoding. While debugging that, I discovered that if I isolated the code (except for actually loading the file and doing the unmarshalling) the bar worked. That got me looking and I noticed that the other components mentioned were not updating when the individual JLabels were added and sized until all process was complete despite constant repaints. Since I am still new to JAVA I thought I would ask if anyone might know a reason that all of these components would not be graphically updating while this loop is going on.
As a note, in the loop, I call the add and repaint functions to place the newly decoded JLabel on the pane but it does not show until all is complete just like the bar. And all of this is running single thread (except for the JProgressBar which is spun into it's own thread).ll
I can post code if you like just please direct me to which code you want (IE the XML decoder and loop, the add and size of the JLabels, the instantiations, etc).
Your problem is that you're doing all processing on the Swing event thread or EDT. The solution is to use a background thread such as can be obtained by a SwingWorker object.
For more on this, please check out the Java Swing tutorial called Concurrency in Swing. It will describe the event thread, why it is important to respect and not to block, and how to do background processing with a SwingWorker object.
You are doing your work on the "event dispatch" thread, which is the same thread used to run swing.
You need to do your work in a separate thread. Take a look at the SwingWorker class

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