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

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.

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.

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.

What is causing slow performance in my JTabbedPane-based Swing application?

I have a Swing application for creating RPG characters.
It has a nested JTabbedPane architecture, so there is a HeroTabsPanel which has HeroPanels and each of those has some more tabs like Stats, Items etc.
So the GUI is comprised of the upper tabbed pane for heroes, the lower tabbed pane for current hero tab and an EditViewPanel which displays an EditingView corresponding to each Tab when the tab is selected.
Performance has been bad from the start, but when I added the upper level hero-tabs (to have multiple heroes in editing simultaneously), switching between tabs became even slower.
It takes a few minutes for something to be displayed in the new JFrame after all the code has finished adding components. Could this be the layout?
I am using MigLayout with absolute positioning. Actually, before I added upper tabs, there had been some “Unstable Cyclic Dependency in absolute-linked values!” issues, but now there aren’t somehow.
In stateChanged() I have what amounts to this:
editViewPanel.activateView(currentTab.getLinkedView());
And in activateView():
removeAll();
currentView = heroView;
add(currentView, "pos 0 0");
currentView.refresh();
revalidate();
But like I said, all the code execution is finished in reasonable time, I've done my profiling, but after it is done, there a delay of considerable length, up to a few minutes in the case of first time adding to a new JFrame.
Another issue is that when I need to update a panel within the lower tabbedpane, especially StatsPanel which is made up of string-int elements added for each parameter in a few columns, I get yet another large delay. It also depends on MigLayout and for some reason (bad design, I know) has absolute positioning as well. But I have changed it so that no components are removed/added after initialization, only setText() is used and still there is a big delay after the code is finished executing.
I’m planning to use SwingWorkers but I would like to understand the problem better before I start solving it. I suspect it's simple, but I am a bit incredulous about how big the delays it's causing are. I'd appreciate some hints/examples about SwingWorkers.
I can add more code if you have some general idea where the issue might hide.
Any suggestions are welcome, thanks!
I never encountered a Swing UI which was slow due to the number of JComponents visible. What I do often see is a sluggish UI because the UI thread is used/abused to perform all kinds of work not related to UI updates.
In Swing, there is only one thread on which you may update the UI, and that same thread is responsible for painting the UI (the Event Dispatch Thread). If you block this thread by e.g. performing calculations on it, the UI will not be able to repaint or react on user input while your calculation is running. That is why you must perform all heavy work on a worker thread. This is clearly explained in the Concurrency in Swing tutorial.
Not 100% sure that is what happening in your case, but it definitely sounds like it. If you want to be sure, take a thread dump while you are waiting for your UI and see what the thread named AWT-EventQueue-0 is doing at that moment. If it really takes 5 minutes before your UI is updated, you must be able to locate fairly quickly what is blocking the UI.
Ok, I finally worked it out by going through the EDT dump. The freeze was due to layout, unlikely though it had seemed.
MigLayout was trying to figure out the sizes of all the components every time new tab was selected, and probably for all the components in all the tabs on init.
The solution is simply to override getPreferredSize() for the JTabbedPanel implementation.
#Robin, thanks for the thread dump hint!

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

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

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

Categories

Resources