首先,我想说我知道这种方法是错误的所以我问这个问题是因为纯粹的好奇心。假设我有一个这样的swing应用程序:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ThreadSleeping {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Load");
JLabel label = new JLabel();
public ThreadSleeping() {
panel.add(button);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
label.setIcon(new ImageIcon(
"C:/Users/Public/Pictures/Sample Pictures/Tulips.jpg"));
System.out.println("Tulips painted");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
label.setIcon(new ImageIcon(
"C:/Users/Public/Pictures/Sample Pictures/Koala.jpg"));
System.out.println("Koala painted");
}
});
frame.add(panel, BorderLayout.NORTH);
frame.add(label, BorderLayout.CENTER);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(1024, 768);
// frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new ThreadSleeping();
}
});
}
}
基本上,当我单击Load
按钮时,我希望显示Tulips.jpg
图像,然后GUI会冻结2秒钟,之后我希望显示Koala.jpg
图像。但是会发生什么:我点击按钮,GUI冻结2秒钟,Koala.jpg
显示。之前没有Tulips.jpg
。但让我感到困惑的是当我放置System.out.println("Tulips painted");
和System.out.println("Koala painted");
时。因此,当我点击按钮时,它会打印“郁金香画”,并在2秒后“考拉画”。谁能告诉我这里发生了什么?问候。
答案 0 :(得分:3)
适用于这种情况,because you programatically freeze ouf Swing GUI, but there is/aren't another update(s),或其他JComponent
如果有一些其他更新到Swing GUI,Thread.sleep(int)冻结事件调度线程
默认情况下,JComponents XxxModels
JComponents view
的所有更新内容
example until sleep ended you'll lost all updated to the GUI
答案 1 :(得分:2)
我打算在评论中提出这一点:
不可预测的,因为您无法知道会发生什么。我们所能做的就是猜...如果你睡觉了edt,那么产生的错误行为基本上是不可预测的。
技术原因是大多数ui更新不是立即发生的,而是安排的:我们无法真正知道在我们后面排队等待的是什么。请记住:它只是一条通道,当它在actionPerformed中时,它就是我们坐在它里面。
出于教育原因,下面的代码是原始代码,有几行代替/评论以演示不同的场景。
label.repaint()
进行,该paintImmediately(...)
计划在EDT进行后续处理(如其api doc所述)setIcon(..)
被记录为完全按照名称所说和允许 - 正如我们在EDT上 - 被允许被调用。看起来很成功,黄色图标显示出来。invalidate()
的来源显示布局已......再次安排。我们在square [1]中了解到,如果是validate()
/ /**
* 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();
}
});
}
}
对的布局,我们可以立即强制发生。宾果,黄色图标,即使在南方。在一天结束时(但在睡觉之前,EDT :-),在
睡眠期间无法可靠地预测视觉结果。视觉效果只是冰的一角......{{1}}