First of all I want to say I\'m aware this aproach is wrong so I\'m asking this question because of pure curiousity. Lets say I have a swing application like this:
The point I intended to make in my comment:
if you sleep the edt, the resulting mis-behaviour is basically unpredictable.
Unpredictable in the sense that you can't know what will happen or not. All we can do, is guess ...
The technical reason is that most ui updates don't happen immediately but are scheduled: we can't really know what's waiting in the line behind us. Remember: it's only one lane, and when in the actionPerformed, it's we that are sitting in it.
For educational reasons, the code below is the original code with a couple of lines to un/comment to demonstrate different scenarios.
label.repaint()
which is scheduled on the EDT for latter processing (as its api doc states)paintImmediately(...)
which is documented to do exactly what it's name says and allowed - as we are on the EDT - is allowed to be called. Looks like success, the yellow icon shows up.setIcon(..)
reveals that layout is ... scheduled again. We learned in square [1] that we can force thingies to happen immediately, in case of layout that would be the pair invalidate()
/ validate()
. Bingo, yellow icon even when in south.At the end of the day (but before going to sleep the EDT :-), there is simply no way to reliably predict the visual outcome during the sleep. And visuals are only the tip of the ice...
/**
* Unpredictable behaviour when sleeping the EDT.
* http://stackoverflow.com/q/15600203/203657
*
* [0] run as-is: property set but yellow not showing
* [1] uncomment paintImmediately: yellow showing in center
* [2] add label to south: yellow not showing
* [3] force immediate in-/validation: yellow showing in south
* [4] subclass label with invoked property setting:
* property not set, yellow not showing
*
*/
public class ThreadSleeping {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Load");
JLabel label = new JLabel() {
// [4] subclass implemented to schedule the property setting
// @Override
// public void setIcon(final Icon icon) {
// SwingUtilities.invokeLater(new Runnable() {
// public void run() {
// superSetIcon(icon);
//
// }
// });
// }
//
// protected void superSetIcon(Icon icon) {
// super.setIcon(icon);
// }
//
};
public ThreadSleeping() {
panel.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Icon firstIcon = new FixedIcon(Color.YELLOW, 100, 100);
Icon secondIcon = new FixedIcon(Color.RED, 500, 500);
label.setIcon(firstIcon);
// check if the property is already set
System.out.println(label.getIcon());
// following lines try to force the output before going to sleep
// [3] paintImmediately + force immediate re-layout
// label.invalidate();
// label.getParent().validate();
// {1] paintImmediately (fine for center, no effect for south)
// ((JComponent) label.getParent()).paintImmediately(0, 0, 5000, 5000);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setIcon(secondIcon);
}
});
frame.add(panel, BorderLayout.NORTH);
// un/comment one of the following, placing the
// label either in CENTER (= sized to fill)
frame.add(label, BorderLayout.CENTER);
// [2] or in SOUTH (= sized to pref)
// frame.add(label, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(1024, 768);
frame.setVisible(true);
}
/**
* Simple fixed size Icon filling its area.
*/
public static class FixedIcon implements Icon {
private Color background;
private int width;
private int height;
public FixedIcon(Color background, int width, int height) {
this.background = background;
this.width = width;
this.height = height;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(background);
g.fillRect(0, 0, width, height);
}
@Override
public int getIconWidth() {
return width;
}
@Override
public int getIconHeight() {
return height;
}
@Override
public String toString() {
return "[" + background + " w/h " + width + "/" + height + "]";
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ThreadSleeping();
}
});
}
}
works in this case, because you programatically freeze ouf Swing GUI, but there is/aren't another update(s), ot another JComponent(s)
doens't works in the case that there are a few another updated to the Swing GUI, Thread.sleep(int) freeze Event Dispatch Thread,
by default all updates to the JComponents XxxModels
never will be visible on the JComponents view
example until sleep ended you'll lost all updated to the GUI