(In my applicaton with Swing GUI) I want to display GlassPane during some work performed in a loop or method, which is called after clicking JButton.
For example: (action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
someTimeConsumingMethod();
glassPane.setVisible(false);
}
Running this code results in not showing the glassPane during execution of someTimeConsumingMethod() - GUI just freezes for a moment, before result is displayed. Removing last line in that loop (glassPane.setVisible(false);) results in showing glassPane after the method is done (when GUI unfreezes).
Is there a simple way to show that glassPane before GUI freezes, or I need to use some advanced knowledge here? (threads?)
UPDATE1:
I've updated my code according to davidXYZ answer (with two changes):
(action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
new Thread(new Runnable(){
public void run(){
someTimeConsumingMethod(); // 1st change: running the someTimeConsumingMethod in new Thread
// instead of setting glassPane to visible
}
}).start();
// 2nd change: moved glassPane.setVisible(false); inside the someTimeConsumingMethod(); (placed at the end of it).
}
The point of 1st change is that setting glassPane visible in new thread right before running someTimeConsumingMethod in my GUI thread was revealing the glassPane after someTimeConsumingMethod finished (double-checked this).
Now it works fine, thank you for all answers. I will definitely check all the links you provided to actually understand threads!
UPDATE2: Some more info: someTimeConsumingMethod(); in my application is prepering new Swing Components accoriding to the XML data (cards builded from JButtons and JLabels with few JPanels where needed, and adding them in correct places).
UPDATE3:
I am trying to make it work using SwingWorker's invokeLater method. Now it looks like that:
(action performed after clicking a button)
if (item.equals(button)) {
glassPane.setVisible(true);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
someTimeConsumingMethod();
glassPane.setVisible(false);
}
});
}
It works not that good as code from UPDATE1 (but still - it works). Problems are:
glassPane loads without .gif animation (file is setted up in custom glassPane class - it works with UPDATE1 code)
there is small delay at the end of "working" process - first cursor changes to normal (from the WAIT_CURSOR), and after very short moment glassPane disappear. Cursor is changed by the custom glassPane class on activation/deactivation (no delay using new Thread way).
Is it correct way of using SwingWorker's invokeLater method?
EDIT: My mistake, I confused SwingWorker with SwingUtilities.invokeLater(). I guess the image issue is due to GUI freezing when the someTimeCOnsumingMethod starts.
GUI just freezes for a moment, before result is displayed. Removing last line in that loop (glassPane.setVisible(false);) results in showing glassPane after the method is done (when GUI unfreezes).
this is common issue about Event Dispath Thread
, when all events in EDT
are flushed to the Swing GUI
in one moment, then everything in the method if (item.equals(button)) {
could be done on one moment,
but your description talking you have got issue with Concurency in Swing, some of code blocking EDT, this is small delay, for example Thread.sleep(int
) can caused this issue, don't do that, or redirect code block to the Backgroung taks
Is there a simple way to show that glassPane before GUI freezes, or I need to use some advanced knowledge here? (threads?)
this question is booking example why SwingWorker
is there, or easier way is Runnable#Thread
methods implemented in SwingWorker
quite guarante that output will be done on EDT
any output from Runnable#Thread
to the Swing GUI should be wrapped in invokeLater()
easiest steps from Jbuttons Action
could be
show GlassPane
start background task from SwingWorker
(be sure that listening by PropertyChangeListener
) or invoke Runnable#Thread
in this moment ActionListener
executions is done rest of code is redirected to the Backgroung taks
if task ended, then to hide GlassPane
create simple void by wrapping setVisible
into invokeLater()
for Runnable#Thread
in the case that you use SwingWorker
then you can to hide the GlassPane
on proper event from PropertyChangeListener
or you can to use any (separate) void for hidding the GlassPane
best code for GlassPane by @camickr, or my question about based on this code