我有一个在EDT中执行的方法。大概是这样的:
myMethod()
{
System.out.prinln(SwingUtilities.isEventDispatchThread());
for (int i = 0; i < 10; i++)
{
Thread.sleep(3000);
someJPanel.remove(otherJPanel);
}
}我期望发生的事情:十个JPanels将从它们的父级中一个接一个地移除,每次移除之间有三秒钟的暂停……
实际发生了什么:所有的东西都冻结了30秒,之后所有10个元素都被一次性删除了。
控制台中的行始终为true (SwingUtilities.isEventDispatchThread())。
既然我是在EDT中做这些的,为什么这些变化不是即时的呢?为什么它要等待方法首先到达它的结尾?
我应该如何修改我的代码,以实现删除之间的三秒延迟?
发布于 2013-03-01 10:10:57
Swing使用单个线程来调度事件和处理重绘请求。只要你阻塞这个线程,你就会停止EDT处理这些重绘请求,让UI看起来像是“停止”了。
取而代之的是,使用javax.swing.Timer之类的东西来插入延迟并执行操作。这将在EDT中执行操作,但将在后台线程中等待。
请通读The Event Dispatching Thread以了解详细信息...
使用计时器更新的示例
public class SlowDecline {
public static void main(String[] args) {
new SlowDecline();
}
private TestPane last;
public SlowDecline() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
TestPane parent = new TestPane(Color.RED);
TestPane tp = add(parent, Color.BLUE);
tp = add(tp, Color.GREEN);
tp = add(tp, Color.CYAN);
tp = add(tp, Color.LIGHT_GRAY);
tp = add(tp, Color.MAGENTA);
tp = add(tp, Color.ORANGE);
tp = add(tp, Color.PINK);
last = tp;
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(parent);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (last != null) {
Container parent = last.getParent();
if (parent != null) {
parent.remove(last);
parent.repaint();
if (parent instanceof TestPane) {
last = (TestPane) parent;
}
} else {
last = null;
}
} else {
(((Timer)e.getSource())).stop();
}
}
});
timer.setRepeats(true);
timer.setCoalesce(true);
timer.start();
}
});
}
public TestPane add(TestPane parent, Color color) {
TestPane child = new TestPane(color);
parent.add(child);
return child;
}
public class TestPane extends JPanel {
public TestPane(Color background) {
setLayout(new BorderLayout());
setBorder(new EmptyBorder(10, 10, 10, 10));
setBackground(background);
}
@Override
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
}
}发布于 2013-03-01 10:13:46
这是因为UI线程负责绘制屏幕以及处理事件。当您将UI线程置于休眠状态时,不会再发生绘制或事件处理。当线程恢复绘制时,所有面板都已被移除。
这个网址在how to handle threading with Swing上是相当全面的。
最好创建一个删除面板的Thread。
(未测试)
Thread t = new Thread() {
@Override
public void run() { // override the run() for the running behaviors
for (int i = 0; i < 10; i++)
{
Thread.sleep(3000);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
someJPanel.remove(...);
});
}
}
};
t.start(); // call back run()https://stackoverflow.com/questions/15149242
复制相似问题