Java - 进度条不显示(线程)

标签 java multithreading swing jprogressbar

我正在向程序添加一项功能以将一些内容保存到文件中。进度由进度条(在其自己的 JFrame 中)显示,但进度条仅显示在它读取的最后一个值上。我有一个由主线程更新的全局,它表示已完成工作的百分比,另一个线程读取这个全局并相应地更新进度条。 现在当它运行时,JFrame 是空的,然后 Activity 完成,然后进度条显示完整的数量。我如何让它随着进度更新(并从一开始就显示 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

最佳答案

有几个问题:

  • 最重要的是(我最初错过了这一点!),您不是在后台线程中执行长时间运行的代码,而是在 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 事件线程中

更多小问题:

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

对于我的一些代码示例:

关于Java - 进度条不显示(线程),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28591205/

相关文章:

java - 并行执行 TestNG 测试,一个浏览器不会关闭

objective-c - ARC 的线程和对象生命周期

Java - 如果 JBDC 成功连接则切换 Jframe

java - 有没有办法将 ActionListener 添加到此代码

java多线程延迟初始化单例有哪些方法?

c# - 调用设计模式的方法

java - 如何以1秒的间隔执行一段代码?

java - 在 GroupLayout 中填充多列

java - JBoss + RestEasy + Jackson : org. jboss.resteasy.core.ServerResponse 无法转换为 org.jboss.resteasy.specimpl.BuiltResponse

java - Java 同步方法入口点线程是否足够安全?