Java - JProgressbar没有显示(线程)

时间:2015-02-18 18:31:58

标签: java multithreading swing jprogressbar

我正在为程序添加一项功能,以便将一些内容保存到文件中。进度条(在其自己的JFrame中)显示进度,但进度条仅显示在它读取的最后一个值上。我有一个由主线程更新的全局,表示已完成工作的百分比,另一个线程读取此全局并相应地更新进度条。 现在,当它运行时,JFrame为空,然后活动完成,然后进度条显示自己的完整数量。如何让它随着时间的推移更新进度(并从头开始显示JProgressbar)?这是我的代码:

public class GenomeAnnotator{
    private JProgressBar csvProgressBar;
    private JFrame csvSaveLoadFrame;     //for the progress bar
    private Container csvCon;
    private double csvPercentSaved;  //% of work completed

    public JFrame m_frame;    //main program frame


....



public static void main(String[] args){
    ...
    showGUI();
    ...
}

public void showGUI(){
   ...

   JMenu file = new JMenu("File");
   JMenu exptann = new JMenu("Export annotation..);
   JMenuItem exptcsv = newJMenuItem("CSV format");
   exptcsv.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {

          ..determine output file + checks...

          System.out.println("Writing to .csv file......"); 

          csvSaveLoadFrame = new JFrame("Saving to csv file..");
          csvProgressBar =new JProgressBar(0,100);

          csvSaveLoadFrame.setSize(300,100);
          csvCon = csvSaveLoadFrame.getContentPane();
          csvCon.setLayout(null);
          csvProgressBar.setBounds(10,10,280,20);
          csvCon.add(csvProgressBar);
          csvSaveLoadFrame.setResizable(false);
          csvSaveLoadFrame.setVisible(true);

          ORF [] ora= orfPanel.getAcceptedOrfs();
          int val;
          double toload = blastData.size() + ora.length; //how much work
          double loaded=0.0; //how much work completed


          /*Thread that will read % value from global and update prog. bar*/
          Thread progressBarMover = new Thread() {
              @Override
              public void run() {
                  int previous=0;
                  while(csvPercentSaved<100){

                      csvProgressBar.setValue((int)csvPercentSaved);
                      //tried putting a sleep() in here when testing
                      //values from global is read successfully


                      }
                  }
                  System.out.println("Thread done!");
                  csvPercentSaved = 0; //reset value when done
                  csvSaveLoadFrame.setVisible(false);
              }
          };
          progressBarMover.start();


          for (int k=0; k<blastData.size(); k++) {

              ..do output work...

              loaded+=1; //update % values
              csvPercentSaved = (loaded/toload)*100;
              val = (int)csvPercentSaved;
              System.out.println("main complete "+val+"%");
          }



          for (int k=0; k<ora.length; k++) {

              ...do more ouput work...

              loaded+=1;
              csvPercentSaved = (loaded/toload)*100; //update % value
              val = (int)csvPercentSaved;
              System.out.println("main complete "+val+"%");

          }
          System.out.println("Output file finished!");
          csvPercentSaved = 100;

      }

  });
exptann.add(exptcsv);
file.add(exptann);
}

修改

在这里找到解决方案: https://weblogs.java.net/blog/mkarg/archive/2010/01/03/did-you-know-swingworker-can-send-progress-status

1 个答案:

答案 0 :(得分:5)

那里有几个问题:

  • 最重要的(我最初错过了这个!),你不是在后台线程中执行长时间运行的代码,而是在Swing事件线程EDT中。我的意思是这两个for循环:A)for (int k=0; k<blastData.size(); k++) {...}和B)for (int k=0; k<ora.length; k++) {...},它们看起来是您正在加载或保存信息的代码。这将立即冻结您的GUI。
  • 同样重要的是,你正在后台线程中进行Swing调用,包括设置进度条的值和设置JFrame的可见性,这是​​你永远不想做的事情,并且大多否定了使用后台线程的好处第一名。
  • 换句话说,您正在完全向后执行所有Swing线程工作 - 从后台线程调用Swing并在事件线程中运行长进程。
  • 相反,做相反的事情 - 在后台线程中完成所有长时间运行的工作,并在EDT上进行所有非线程安全的Swing调用。
  • 一种方法是使用SwingWorker,在doInBackground(...)方法中进行加载和保存
  • 并设置进度字段,因为正在进行中..
  • 然后,您将在PropertyChangeListener中监视工作人员的进度字段,这在EDT上完成,然后使用它来设置进度条的值。
  • 或者,如果你必须使用自己的后台线程,那么
    • 让内部类实现Runnable,而不是扩展Thread
    • 如果从后台线程中进行Swing调用,则将这些调用包装在Runnable中,并通过SwingUtilities.invokeLater(yourRunnable)将其排入Swing事件线程

更多小问题:

  • 您不应该使用空布局和绝对定位,而应使用布局管理器。虽然null布局和setBounds()似乎是Swing新手,比如创建复杂GUI的最简单和最好的方法,但是你创建的Swing GUI越多,在使用它们时会遇到更严重的困难。当GUI调整大小时,它们不会调整组件的大小,它们是增强或维护的皇室女巫,当它们被放置在滚动窗格中时它们完全失败,当它们在所有平台上观看时或者与原始平台不同的屏幕分辨率时它们看起来很糟糕
  • 您的辅助对话窗口应该是JDialog,可能是模态JDialog,而不是另一个JFrame。您不是在创建和显示新的独立程序,而是在主GUI窗口之外显示一个对话框窗口。如果你希望在显示对话框时主GUI窗口不起作用,那么模态JDialog就是这样,因为它就像一个JOptionPane(它是模态JDialog的一种形式),并使调用窗口非功能虽然可见。

对于我的一些代码示例: