我正在使用SwingWorker在后台完成一些长时间运行的数据库调用。在执行SwingWorker之前,我启动了一个带有标签的jpanel,以通知用户该应用程序正在做一些后台工作。问题是,如果我使用SwingWorker get()方法获取长时间运行的操作的结果,我的jpanel将冻结,并且什么都不会显示。如果我不使用get()方法,则jpanel会正常显示。
您能告诉我我可能做错了什么吗?我已经花了几个小时在这上,却不知道为什么。在完成所有jpanel创建之后,SwingWorker将被执行,我不明白为什么它会挂起。
非常感谢!
创建jpanel并启动SwingWorker的功能:
private void snapshotOldVariables() {
JFrame loadingJFrame = new JFrame();
LoadingJPanel loadingJPanel = new LoadingJPanel();
Dimension d1 = new Dimension();
d1.setSize(500, 500);
loadingJFrame.setResizable(false);
loadingJFrame.setMinimumSize(d1);
loadingJFrame.setTitle("Loading...");
loadingJFrame.setLocationRelativeTo(null);
loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
loadingJFrame.add(loadingJPanel);
loadingJFrame.setVisible(true);
loadingJPanel.updateStatus("Creating snapshot of values...");
MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
worker.execute();
GMSnapshotVO snap = null;
try {
snap = worker.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println(e);
}
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
}
jpanel的屏幕快照在函数等待worker.get()时冻结:
带有注释worker.get()代码块的函数:私人无效的快照OldVariables(){
JFrame loadingJFrame = new JFrame();
LoadingJPanel loadingJPanel = new LoadingJPanel();
Dimension d1 = new Dimension();
d1.setSize(500, 500);
loadingJFrame.setResizable(false);
loadingJFrame.setMinimumSize(d1);
loadingJFrame.setTitle("Loading...");
loadingJFrame.setLocationRelativeTo(null);
loadingJFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
loadingJFrame.add(loadingJPanel);
loadingJFrame.setVisible(true);
loadingJPanel.updateStatus("Creating snapshot of values...");
MySwingWorker worker = new MySwingWorker(tableRows, selectedItems);
worker.execute();
/* COMMENT STARTS HERE
GMSnapshotVO snap = null;
try {
snap = worker.get();
} catch (InterruptedException | ExecutionException e) {
System.out.println(e);
}
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
COMMENT ENDS HERE */
}
据我所知,除非您确定已完成处理,否则不应直接从UI线程调用SwingWorker
的get()
方法。相反,您应该在覆盖MySwingWorker.done()
内调用它,可以确保在后台执行完任务。
无关紧要的是,所有JPanel
的创建都是在阻塞之前完成的,因为Swing仍需要它的主UI线程来重新绘制和更新UI并保持响应。通过调用get()
,您正在阻止它。
从UI线程中,您应该只调用execute()
,所有结果处理(在您的情况下为productIds = snap.getProductIds(); oldLocationIds = snap.getOldLocationIds(); oldStatusIds = snap.getOldStatusIds();
)应在done()
回调中完成。
this answer中有一个简单的例子。
在您的情况下,它应该像这样:
//inside MySwingWorker
@Override
protected void done() {
try {
System.out.println("My long running database process is done. Now I can update UI without blocking/freezing it.");
GMSnapshotVO snap = get();
loadingJPanel.updateStatus("Complete");
loadingJFrame.dispose();
productIds = snap.getProductIds();
oldLocationIds = snap.getOldLocationIds();
oldStatusIds = snap.getOldStatusIds();
//..do other stuff with ids
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
希望有帮助。