2012-05-15 58 views
2

好吧,我再次来这里问一个虚拟问题。我有一个自定义的对话框,并有进度条。所以我也有一个遗传算法(其工作量相当大)。进度条没有用线程更新

据我了解所有的情况,我需要为算法,进度条和离开对话框的主线程(给他一个机会来响应用户操作)执行单独的线程。所以,我想实现这一点,并得到了以下内容:

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(backGroundWorker).start();执行后才new Thread(geneticEngineWorker).start();将被停止。
所以,如果我是对的,你可以告诉我如何重新组织代码来完成工作,如果我错了,你能指出我的错误吗?

谢谢大家提前!


加成

我debuged它,因为我以为,BackgroundWorker的开始工作geneticEngineWorker结束或用户关闭对话框(在这种情况下除外)后,才;

+2

也许我失去了一些东西,但该线程更新进度刚刚更新了酒吧一次,然后在完成之前休眠10秒。检查Timer&TimerTask类以安排重复更新。 –

+0

对不起,我无意中发布了旧版本。编辑。其实没有什么变化,如果我添加一个while循环,我不认为它有问题。 –

+2

[如何使用进度条](http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html) – oers

回答

4

是有使用

SwingWorker,需要最深的知识约Java Essential Classes INC两种基方式。 Generics

Runnable#Thread只需要包装输出到GUI为invokeLater()

简单的例子,关于理念Runnable#Thread不需要特别的努力,JProgressBar都在JTable,这就是意味着,代码行model.setValueAt(value, row, column);应包到invokeLater,但在另一方面setText()被宣布为线程安全,我会建议在invokeLater所有情况下包装

enter image description hereenter image description here

import java.awt.Component; 
import java.util.Random; 
import javax.swing.JFrame; 
import javax.swing.JProgressBar; 
import javax.swing.JScrollPane; 
import javax.swing.JTable; 
import javax.swing.SwingUtilities; 
import javax.swing.table.DefaultTableModel; 
import javax.swing.table.TableCellRenderer; 

public class TableWithProgressBars { 

    private static final int maximum = 100; 

    public void createGUI() { 
     final JFrame frame = new JFrame("Progressing"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     Integer[] oneRow = {0, 0, 0, 0}; 
     String[] headers = {"One", "Two", "Three", "Four"}; 
     Integer[][] data = {oneRow, oneRow, oneRow, oneRow, oneRow,}; 
     final DefaultTableModel model = new DefaultTableModel(data, headers); 
     final JTable table = new JTable(model); 
     table.setDefaultRenderer(Object.class, new ProgressRenderer(0, maximum)); 
     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     frame.add(new JScrollPane(table)); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
     new Thread(new Runnable() { 

      @Override 
      public void run() { 
       Object waiter = new Object(); 
       synchronized (waiter) { 
        int rows = model.getRowCount(); 
        int columns = model.getColumnCount(); 
        Random random = new Random(System.currentTimeMillis()); 
        boolean done = false; 
        while (!done) { 
         int row = random.nextInt(rows); 
         int column = random.nextInt(columns); 
         Integer value = (Integer) model.getValueAt(row, column); 
         value++; 
         if (value <= maximum) { 
          model.setValueAt(value, row, column); 
          try { 
           waiter.wait(15); 
          } catch (InterruptedException e) { 
           e.printStackTrace(); 
          } 
         } 
         done = true; 
         for (row = 0; row < rows; row++) { 
          for (column = 0; column < columns; column++) { 
           if (!model.getValueAt(row, column).equals(maximum)) { 
            done = false; 
            break; 
           } 
          } 
          if (!done) { 
           break; 
          } 
         } 
        } 
        frame.setTitle("All work done"); 
       } 
      } 
     }).start(); 
    } 

    public static class ProgressRenderer extends JProgressBar implements TableCellRenderer { 

     private static final long serialVersionUID = 1L; 

     public ProgressRenderer(int min, int max) { 
      super(min, max); 
      this.setStringPainted(true); 
     } 

     @Override 
     public Component getTableCellRendererComponent(JTable table, Object value, 
       boolean isSelected, boolean hasFocus, int row, int column) { 
      this.setValue((Integer) value); 
      return this; 
     } 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new TableWithProgressBars().createGUI(); 
      } 
     }); 

    } 
} 
+0

这是一个很好的例子,但我认为getTableCellRendererComponent的重载和进度的隐式设置很难被不熟悉表模型和东西的人所理解:D – oers

+1

@ mr.nothing please [请阅读我的问题]( http://stackoverflow.com/questions/8169964/is-mvc-in-swing-thread-safe),这可能是最复杂的方式 – mKorbel