【发布时间】:2012-05-22 21:49:58
【问题描述】:
好的,我又来这里问一个愚蠢的问题。我有一个自定义对话框框架,上面有进度条。所以我也有一个遗传算法(它的工作时间相当长)。
据我了解所有情况,我需要为算法、进度条执行单独的线程,并将主线程留给对话框(让他有机会响应用户操作)。所以我尝试实现这一点,并得到以下结果:
public class ScheduleDialog extends JDialog {
private final JPanel contentPanel = new JPanel();
private static Data data;
private static GeneticEngine geneticEngine;
private static Schedule schedule;
private static JProgressBar progressBar;
private static JLabel statusLabel;
public static void showProgress() {
try {
ScheduleDialog dialog = new ScheduleDialog();
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
startScheduleComposing();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void startScheduleComposing() {
BackGroundWorker backGroundWorker = new BackGroundWorker();
GeneticEngineWorker geneticEngineWorker = new GeneticEngineWorker();
new Thread(geneticEngineWorker).start();
new Thread(backGroundWorker).start();
}
private ScheduleDialog() {
this.data = Data.getInstance();
setTitle("");
setModal(true);
setBounds(100, 100, 405, 150);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dialogSize = getSize();
setLocation((screenSize.width - dialogSize.width) / 2, (screenSize.height - dialogSize.height) / 2);
getContentPane().setLayout(new BorderLayout());
contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
getContentPane().add(contentPanel, BorderLayout.CENTER);
contentPanel.setLayout(new GridLayout(0, 1, 0, 0));
{
progressBar = new JProgressBar();
progressBar.setBackground(Color.RED);
contentPanel.add(progressBar);
}
{
statusLabel = new JLabel("");
contentPanel.add(statusLabel);
}
{
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
getContentPane().add(buttonPane, BorderLayout.SOUTH);
{
JButton okButton = new JButton("Прервать");
okButton.setActionCommand("OK");
buttonPane.add(okButton);
getRootPane().setDefaultButton(okButton);
}
}
}
protected static class BackGroundWorker implements Runnable {
@Override
public void run() {
while(true){
int barValue = 100 - (geneticEngine.getCurrentBestFitness() / geneticEngine.getInitialFitness());
progressBar.setValue(barValue);
progressBar.repaint();
statusLabel.setText(String.valueOf(geneticEngine.getCurrentBestFitness()));
statusLabel.repaint();
try{
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
protected static class GeneticEngineWorker implements Runnable{
@Override
public void run() {
geneticEngine = new GeneticEngine(data);
schedule = geneticEngine.GeneticAlgorithm();
}
}
}
看来,new Thread(geneticEngineWorker).start(); 正在工作,但进度条没有任何反应。我认为这部分代码:
private static void startScheduleComposing() {
BackGroundWorker backGroundWorker = new BackGroundWorker();
GeneticEngineWorker geneticEngineWorker = new GeneticEngineWorker();
new Thread(geneticEngineWorker).start();
new Thread(backGroundWorker).start();
}
只有在new Thread(geneticEngineWorker).start(); 停止之后才会执行new Thread(backGroundWorker).start();。
所以,如果我是对的,你能告诉我如何重组代码来完成这项工作,如果我错了,你能指出我的错误吗?
提前谢谢大家!
添加
我调试了它,我想,backGroundWorker只有在genericEngineWorker结束或用户关闭对话框后才开始工作(这种情况下例外);
【问题讨论】:
-
也许我遗漏了一些东西,但更新 ProgressBar 的线程只更新了一次 Bar,然后在完成前休眠 10 秒。检查 Timer 和 TimerTask 类以安排重复更新。
-
对不起,我不小心发布了旧版本。已编辑。实际上如果我添加一个while循环没有任何改变,我认为它没有问题。
-
你的理解是错误的。与所有 Swing 组件一样,进度条必须始终从 EDT 更新。不是来自后台线程。
-
无法运行的理论表明您没有在
EDT-Event Dispatcher Thread上更新您的 GUI,您需要使用 SwingWorker 或在 EDT 上自己进行更新。
标签: java multithreading swing jprogressbar