I have written a nifty thing in Java with a GUI that includes a JDialog that starts out rather small and then uses pack() to accommodate things the progam later puts in it. All of this is going on before the JDialog renders.
Then, to my surprise, about 80% of the time, when I run it, the window fails to resize. It seems to be entirely random, as it's theoretically doing exactly the same thing every time. Why on Earth would it do something different with the same code on the same machine five seconds later?
This problem, by the way, popped up when I enabled the native Windows look-and-feel for this GUI.
In my experience, when the GUI does random funny stuff like this, it might be a symptom of not doing all your GUI calls on the Event Dispatch Thread.
Make sure all your GUI calls from non-GUI threads are wrapped in SwingUtilities.invokeLater or invokeAndWait.
A quick google search turned up what seems to be a nifty way to check that your application conforms to the EDT-rules: http://thejavacodemonkey.blogspot.com/2007/08/using-aspectj-to-detect-violations-of.html
Related
I start several(threads) instances of a java class that receives an "input" and based on that generates an "output" on out it out on the standard output(screen). I would like to add an option that would enable me to send this output to a single JFrame (text area). What is the best way of doing this? Up to this point my program was totally GUIless but I would like to make it a bit more GUI friendly and add this option.
The challenge is that at any given point I could have several threads running. Any design or code snippets would be greatly appreciated.
As MadProgrammer points out, a nice, encapsulated way of doing this is SwingWorker.
That said, here is the general theory:
All updates to Swing components must be done on the Swing event dispatch thread (there are some exceptions, but not relevant here). This is achieved by SwingUtilities.invokeLater() (and occasionally invokeAndWait() ).
The Swing runtime will then queue up the changes you want to make and call them one at a time. This makes the entire problem of updating your text area pretty trivial: just create a Runnable with the text you want to append, pass that to invokeLater(), and have your Runnable grab the document model of the text area and append your desired text to it.
SwingWorker can encapsulate some of the complexities of background thread management, but I encourage you to do it the 'hard way' a time or two (and your use-case is actually easier to do the 'hard way'). That way you can appreciate what SwingWorker does for you when you do need it.
You need not to convert your existing threads to SwingWorkers. Just let them from time to time send messages to JFrame in a way like this:
EventQueue.invokeLater(new Runnable(){
// update GUI
});
To avoid boilerplate code, it is good to wrap programming interface to the screen with a java.lang.reflect.Proxy. An example of such wrapping is at SwingProxyActorTest.java.
Before I go on discussing the basic query I would first like to state that I am fully aware of my question being against the standards of the AWT/Swing framework. My query is meant merely as a academic experience and should (hopefully) never be applied to real world applications.
The AWT/Swing framework is built upon a event based model which uses a single thread to dispatch events. All AWT/Swing related events events must be processed on the Event Dispatcher Thread (EDT) and any custom events that the programmer has programmed must be queued through the functions invokeAndWait() and invokeLater(). While this model ensures that the framework never suffers from any sort of thread concurrency issues it gives a big pain to programmers trying to write code around it (search swing issues on stackoverflow... quite a handful).
However... Years ago, before I got more familiar with the AWT/Swing model and the EDT I used to write code that violates many many java standards (code that'll make any reasonable programmer recoil in horror). One of these standards I violated was calling methods that updated the GUI through a thread thats not the EDT. To be precise it was a standard "long" task that resided on a secondary thread which periodically updated a JLabel with the current progress. Reviewing the code now I realized that despite the fact that the code directly violated the standard, it worked 100% of the time. I noticed no flickering, no corruption of text (since it was a JLabel), no random exceptions being thrown and no abnormal GUI behavior. Of course I know from one tiny example, one cannot simply determine the AWT/Swing standards are over-protective or unnecessary. And with this, my query lies:
For simple tasks like updating a JLabel (not even at a constant rate, maybe once or twice a second) is it truly necessary to perform it through the EDT? And what are the possible implications (apart from being despised by the whole java programming community) of this (I want a list of solid implications, not just "it might cause the EDT to mess up")?
Assume a model where only one thread updates the GUI (which is not the EDT) and the updates are infrequent and only update in atomic operations (updating strings, primitive data, etc) is it possible that the program can run free of problems caused by the EDT (I guess this counts as a hack?).
As a challenge, I was wondering if its possible anyone can come up with code that demonstrates a violation of the AWT/Swing model by dispatching events from another thread causing obvious and constant (as in I don't have to wait 2 hours for the GUI to flicker for 1 frame) problems?
And by the way, this might be unrelated but does a new EDT thread spawn for a new JFrame/Window object or do all of them run off the same thread? I can't imagine a resource-heavy multi-window system all running off one thread.
NB: I have never seen nor analyzed the source code of the AWT/Swing framework and all my knowledge is based on internet research and personal experience. If there is any mistake above, please feel free to correct me.
For those programmers still in shock from my example above, I have updated all my projects to comply to the standard (what a pain).
An example of where this fails: Set your JLabel to be right-aligned. Then drawing requires two steps - measuring the text, in order to calculate the position, and then drawing it. If you change the text while it is painting (say, due to an animation loop) the text will seem to jump occasionally.
In answer to your other question - there is only one EDT, for all GUI components.
Example of "constant and obvious" change: Suppose the JLabel has HTML content. In your background thread, after the text is set and a repaint is fired, a PropertyChange is also fired, which causes the UI delegate to reparse the HTML and set it in a client property (working in the background thread, although the UI assumes it is in the EDT because it is receiving an event).
So now you have a race condition: If the UI repaints the label (in the EDT) before it finishes calculating the HTML view in the background thread, it will paint the old HTML and your label will appear to not update.
You could say, "Well then, I just won't use HTML in my label." But the point is that situations like this are pervasive in the Swing libraries - a strong assumption is made everywhere that events are passed only on the EDT, and without reading a huge amount of the Swing source you can't guarantee that you won't run into a problem like this.
I started writing a small program to learn a bit more about java and try to design my layouts by hand without always using NetBeans.
Thing is, when I run my project and close it, it won't stop running in NetBeans, so everytime I re-run it creates another run. By searching and looking at another GUI I had created using NetBeans I thought adding the
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
would do the trick, but I guess I am wrong.
Can someone please explain me what I should do?
Here is a SSCCE of my programa: http://pastebin.com/QhKpwdDw
Thank you very much in advance!
You might want to take a look at this question: How to close a Java Swing application from the code, as it deals with closing the application in general and also how to ensure it completely terminated.
But to answer your question quickly, there are a couple of options.
Option 1
Since you are extending JFrame in your class, you can just use EXIT_ON_CLOSE to quit.
setDefaultCloseOperation(EXIT_ON_CLOSE);
NOTE: EXIT_ON_CLOSE exits all JFrames in your application, not just the one it is applied to.
Option 2
This is most likely not the answer you want, but DISPOSE_ON_CLOSE will close only the JFrame you are applying it to.
If you have multiple JFrames open, or if you have any other Threads, they will keep running and the program will not end. But if you only have one Thread and one JFrame, this will close the application.
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
My Preference
I would go with Option 1, disagreeing with everyone else. It is directly tied to JFrame and not dependent on WindowConstants, which makes things cleaner and more reliable. But more importantly, it closes all of the windows, not just the one that you apply it to.
Even though it looks like you only have one window, you may have other internal Threads elsewhere in your program that NetBeans is throwing in there.
To be sure everything closes, you want to use EXIT_ON_CLOSE.
Extra Information
For a discussion on how DISPOSE_ON_CLOSE and EXIT_ON_CLOSE differ: http://www.coderanch.com/t/340183/GUI/java/DISPOSE-CLOSE-vs-EXIT-CLOSE
Documentation on JFrame's EXIT_ON_CLOSE: http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/JFrame.html#EXIT_ON_CLOSE
Documentation on DISPOSE_ON_CLOSE and other WindowConstants: http://docs.oracle.com/javase/1.5.0/docs/api/javax/swing/WindowConstants.html#DISPOSE_ON_CLOSE
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
http://docs.oracle.com/javase/1.4.2/docs/api/javax/swing/WindowConstants.html#DISPOSE_ON_CLOSE
DISPOSE_ON_CLOSE
public static final int DISPOSE_ON_CLOSE
The dispose-window default window close operation.
Note: When the last displayable window within the Java virtual machine (VM) is disposed of, the VM may terminate. See AWT Threading Issues for more information.
See Also:
Window.dispose(), JInternalFrame.dispose(), Constant Field Values
Try this...
Place it inside the constructor of your JFrame or the class which extends JFrame
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
As you can see here (setDefaultCloseOperation doc) you can use DISPOSE_ON_CLOSE if you want to trigger a window listener (for example to close a database connection).
In such a case it make sense to choose DISPOSE_ON_CLOSE instead of EXIT_ON_CLOSE.
PS : Don't forget although to add a System.exit(0) at the end of the window listener code, so that the application exits.
The following line:
SwingUtilities.updateComponentTreeUI(aComponent);
is making my GUI unresponsive.
When invoking this method to update the laf on a large portion of a GUI, it takes a lot of time, and so makes the GUI unresponsive during this operation.
Since this operation is manipulating the GUI, one can't use a SwingWorker for this either.
From the SwingWorker documentation:
Time-consuming tasks should not be run on the Event Dispatch Thread.
Otherwise the application becomes
unresponsive.
Swing components should be accessed on the Event Dispatch Thread
only.
The problem here though, is that the operation is accessing Swing components and is time-consuming.
Is there a good way to prevent this unresponsiveness?
Since what you do is changing the L&F, and that might severely impact the appearance and usability of the GUI, ask yourself whether you really want the application to be responsive during that time. It may be better to display a message ("Please wait..." or something) using the glass pane, and freeze the GUI while the L&F is updated.
Now, as others have suggested, you may want to investigate why updating the component tree is so slow.
I was going to suggest looking through your GUI to identify any custom or third-party components that contained a lot of sub-components or that had any unusual or inefficient method to revalidate itself. It looks like that was the case, as you mentioned the date picker was a serious bottleneck.
You suggested splitting the calls to updateComponentTree into several sub-tasks that allow events to occur in between, which might be a 'hack' but isn't too bad, unless the change of font changes the sizes of elements and may cause the user to miss a button etc.
If possible, I would suggest looking at the code in the date picker component and see if you can rewrite it so that instead of hiding the components in the pop-up, it actually removes/disposes them, and recreates them when necessary. This should have no noticeable effect on the responsiveness of the date picker when it's being used, but will certainly speed up component tree updates when the pop-up is not visible.
The scenario is this: I have Java swing application with JFrame. There is textarea where you can type things, then you get the search results in another textarea and when you select one of the results, there is a button "Download". And here comes the problem. When you hit "Download" the application should display information about the completness of the downloaded files. I've do this with a class extending Thread called DownloadManager which updates the information on a period of time. However I'm concerned that there may be problems with synchronization. Is there a standard way to update such dynamic info without threads? Is there a mainloop or something like this in Java swing classes. How do you do it?
Have a look at SwingWorker:
http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.html
There may be better ways but that's what I used for my progress bar when downloading things and updating progress bars.
Anything that updates the GUI in Java should be done by the GUI event dispatch thread. To force a method to be run in this thread, you need to use the SwingUtilities.invokeLater. Doing anything else could potentially cause your GUI to hang, not update, or other strangeness!
This is a good tutorial that describes it better than I did:
http://www.javamex.com/tutorials/threads/invokelater.shtml
No there are not so much problems with synchronization. If working with background threads in Swing consider to use a SwingWorker.