[英]Displaying a message from an ActionListener before and after a function that takes a long time
我有一个方法可能需要很长时间才能执行。 我们称之为longTime();
从按钮上的动作侦听器调用此方法。
我想在执行此方法时显示"Please wait.."
消息。
问题是Jframe
没有响应,似乎卡住或等待某事。
重要说明: longTime()
的运行时间可能不同。 只有超过2-3秒才会出现问题。
我试图在invokeLate
做所有这些,但这没有帮助。
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
JLabel label = new JLabel("Please wait...");
label.setFont(new Font("Serif", Font.PLAIN, 25));
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setUndecorated(true);
frame.pack();
frame.setAlwaysOnTop(true);
frame.setVisible(true);
try{
longTime(); //HERE IS THE FUNCTION THAT TAKES A LONG TIME
}catch(Exception e){ }
frame.dispose(); //AFTER THE LONG FUNCTION FINISHES, DISPOSE JFRAME
}
});
有关如何解决此问题的任何想法?
所有冗长的任务都应该在一个单独的线程中进行,以防止GUI线程( Event Dispatch Thread )被阻塞。 我建议您考虑使用SwingWorker
对象来执行冗长的任务并在完成时执行操作。
您可以在http://docs.oracle.com/javase/tutorial/uiswing/concurrency/worker.html上阅读有关此主题的更多信息。
有两种方法,通过使用基于JXLayer (Java6)
或Glasspane
JLayer (Java7)
,使用JLabel
(带有intermediate Icon
)调用
来自SwingWorker
(最简单)来自Runnable.Thread
(输出到Swing GUI必须包装在invokeLater
)
仔细考虑Swing中的Concurency ,所有更改都必须在EDT上完成
不要重新发明轮子,代码示例由@camickr
通过一个简单的例子突出显示mKorbel和Ducan的推荐(两者都是+1)......
public class RunLongTime {
public static void main(String[] args) {
new RunLongTime();
}
public RunLongTime() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface WorkMonitor {
public void updateProgress(float progress);
public void done();
}
public class TestPane extends JPanel implements WorkMonitor {
private JLabel message;
private JButton button;
public TestPane() {
message = new JLabel("Click to get started");
button = new JButton("Start");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.insets = new Insets(2, 2, 2, 2);
add(message, gbc);
add(button, gbc);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
button.setEnabled(false);
message.setText("Getting started...");
BackgroundWorker worker = new BackgroundWorker(TestPane.this);
worker.execute();
}
});
}
@Override
public void updateProgress(float progress) {
message.setText("Please wait..." + NumberFormat.getPercentInstance().format(progress));
}
@Override
public void done() {
message.setText("All done...");
button.setEnabled(true);
}
}
public class BackgroundWorker extends SwingWorker<Void, Float> {
private WorkMonitor monitor;
public BackgroundWorker(WorkMonitor monitor) {
this.monitor = monitor;
}
@Override
protected void done() {
monitor.done();
}
@Override
protected void process(List<Float> chunks) {
monitor.updateProgress(chunks.get(chunks.size() - 1));
}
@Override
protected Void doInBackground() throws Exception {
for (int index = 0; index < 1000; index++) {
Thread.sleep(125);
publish((float)index / 1000f);
}
return null;
}
}
}
您必须生成另一个线程并在另一个线程中运行longTime()任务。 调用invokeLater()仍然在UI线程中运行它,您不想阻止它。
考虑以下代码:
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
JLabel label = new JLabel("Please wait...");
label.setFont(new Font("Serif", Font.PLAIN, 25));
frame.getContentPane().add(label, BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.setUndecorated(true);
frame.pack();
frame.setAlwaysOnTop(true);
frame.setVisible(true);
new Thread(new Runnable() {
@Override
public void run() {
try{
longTime(); //HERE IS THE FUNCTION THAT TAKES A LONG TIME
}catch(Exception e){ }
frame.dispose(); //AFTER THE LONG FUNCTION FINISHES, DISPOSE JFRAME
}
}).start();
您可能希望从新生成的线程更新数据模型。 那将是使用SwingUtilities.invokeLater()的正确位置。 不要在这个新线程中更新模型。 UI组件的模型必须仅在UI线程中更新。 稍后调用就是这样做的。
只需在新线程中调用longTime()
,例如
new Thread(){ public void run() {longTime();}}.start();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.