As most Java programmers know, updates to Swing GUIs should only be done on the AWT event dispa开发者_StackOverflow中文版tching thread and the recommendation is that long-running processes be executed on a "worker" thread, with updates sent to the event dispatching thread using SwingUtilities.invokeAndWait()
or SwingUtilities.invokeLater()
.
How do you stop the user from proceeding with the application while the long-running process is completed? Do you gray out the controls and then have the worker thread reenable them using the SwingUtilities
calls mentioned above?
Is there a better alternative pattern?
I would consider 3 solutions :
- disable the components of the panel : it's generally what I do. Unfortunately, Swing does not provide a simple way to disable a panel and all its children, but it is easy to do the recursion (see this other SO answer for that). Another problem is that some Swing components look the same when enabled and disabled (JList, for example)
- hide the panel with a CardLayout : in a panel with a
CardLayout
, add 2 components. The first is the panel that hosts the components to inactivate, and the second is a panel showing a "loading" or "please wait" message. A simpleJLabel
in aGridbaglayout
does the trick. Then, you just have to switch from one to another. I use this technique for places where a result of a computation/request is to be displayed. - put some kind of component on top of the panel that consumes the mouse events : you can do it yourself with a
LayeredPane
, or you can use a dedicated utility. JXLayer can do that (I read that JXLayer will be included in Java 7, so this may become the 'standard' solution to this kind of problem).
There are several ways and the selection of which, mostly depends on the design and layout of your GUI.
- Use a Progress Bar - Replace the panel or an area that you don't want a user touching with a progress bar. This will prevent you from having to deal with events you don't want yet, while still making it clear to the user that something is happening in the background.
- Disable buttons and add a Wait Cursor - Use setEnable(false) while work is being done and nd possibly change the cursor to a Wait Cursor. This again makes it clear that an option is not available yet only for a temporary period.
- Don't respond to events or throw up a GlassPane - This is less user-friend as it makes the application look unresponsive, however it can acceptable in some situations.
One way I have seen it done is to use Jframe.setGlassPane() and set a component that eats all events. You can also be creative and use flash kind of rotating-wait gif in your glasspane. But note that setting a glass pane may not be all you want. For more advanced requirements, you may have to play around with event-queues.
精彩评论