【问题标题】:Can a progress bar be used in a class outside main?进度条可以在 main 之外的类中使用吗?
【发布时间】:2011-06-05 22:50:04
【问题描述】:

现在,我的 main 只调用了一个 10 行的 gui。根据这些行中有多少有文本,调用 9 个类中的 1 个(两行必须有文本)。被调用的类执行我希望将进度条绑定到的计算。这是一个被调用类的示例(每个类都相似,但差异足以保证一个新类。)我认为问题是违反 EDT 规则,但我在它们上看到的所有示例都涉及一个主要的争论。代码运行时会出现框架,但在所有计算完成之前进度条不会更新。

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class twoLoan extends JFrame {

    static JFrame progressFrame;
    static JProgressBar progressBar;
    static Container pane;
    double amountSaved = 0;
    int i = 0;

    public void runCalcs(Double MP, Double StepAmt,
        Double L1, Double L2, Double C1, Double C2,
        Double IM1, Double IM2, Double M1Start, Double M2Start) {

        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (Exception e) {
        }

        int iterations = (int) (MP - (M1Start * M2Start));

        //Create all components
        progressFrame = new JFrame("Calculation Progress");
        progressFrame.setSize(300, 100);
        pane = progressFrame.getContentPane();
        pane.setLayout(null);
        progressFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        progressBar = new JProgressBar(0, iterations);

        //Add components to pane
        pane.add(progressBar);

        //Position controls (X, Y, width, height)
        progressBar.setBounds(10, 10, 280, 20);

        //Make frame visible
        progressFrame.setResizable(false); //No resize
        progressFrame.setVisible(true);

        double M1 = M1Start;
        double M2 = M2Start;

        // Set MinLoop as maximum to start
        // Loan 1
        double N1 = (Math.log10(1 - IM1 * L1 / M1) * -1) / Math.log10(1 + IM1);
        double M1Sum = M1 * N1;
        // Loan 2
        double N2 = (Math.log10(1 - IM2 * L2 / M2) * -1) / Math.log10(1 + IM2);
        double M2Sum = M2 * N2;
        double minLoop = M1Sum + M2Sum;
        double MTotal = 0;


        // Define variables for mins
        double MP1 = 0;
        double MP2 = 0;
        double NP1 = 0;
        double NP2 = 0;
        double MP1Sum = 0;
        double MP2Sum = 0;

        while (M1 <= MP - M2Start && M2 >= M2Start) {
            N1 = (Math.log10(1 - IM1 * L1 / M1) * -1) / Math.log10(1 + IM1);
            M1Sum = N1 * M1;
            N2 = (Math.log10(1 - IM2 * L2 / M2) * -1) / Math.log10(1 + IM2);
            M2Sum = N2 * M2;
            MTotal = M1Sum + M2Sum;
            if (MTotal < minLoop) {
                minLoop = MTotal;
                MP1 = M1;
                MP2 = M2;
                NP1 = N1;
                NP2 = N2;
                MP1Sum = M1Sum;
                MP2Sum = M2Sum;
            } // end if
            M1 = M1 + StepAmt;
            M2 = MP - M1;
            // Reset monthly sums
            M1Sum = 0;
            M2Sum = 0;
            i++;
            progressBar.setValue(i);
            progressBar.repaint();
            if (i >= iterations) {
                progressFrame.dispose();
            }
        } // end while

        // if there's a value for current payments, calculate amount saved
        if (C1 > 0) {
            double CN1 = (Math.log10(1 - IM1 * L1 / C1) * -1) / Math.log10(1 + IM1);
            double CT1 = CN1 * C1;

            double CN2 = (Math.log10(1 - IM2 * L2 / C2) * -1) / Math.log10(1 + IM2);
            double CT2 = CN2 * C2;

            double CTotal = CT1 + CT2;
            amountSaved = CTotal - minLoop;
        }

    } // end method runCalcs

    //Workbook wb = new HSSFWorkbook();
    public double savedReturn() {
        return amountSaved;
    }
} // end class twoLoans  

【问题讨论】:

    标签: java swing swingworker jprogressbar


    【解决方案1】:

    感谢您的帮助。我开始尝试使用第一个响应,但我无法让该栏同时运行,并且它在程序完成时运行。我确信它会起作用,但我无法弄清楚。使用trashgod 的响应和其他一些示例,我能够使用SwingWorker 让它工作。不幸的是,我并不完全理解它是如何工作的,但我暂时先接受它。

    运行计算的 gui 和方法首先在另一个类中调用:

    iterations = (int) (MPay - (M1Start + M2Start));
            twoLoan myLoan = new twoLoan();
            myLoan.createGui(iterations);
            myLoan.runCalcs(MPay, Step, L1, L2, C1, C2, IM1, IM2, M1Start, M2Start);
    

    然后运行如下:

    public class twoLoan extends JFrame {
    
        JFrame progressFrame;
        JProgressBar progressBar;
        JLabel label = new JLabel("Calculating...");;
        Container pane;
    
        double amountSaved = 0;
        int i = 0;
        int iterations;
    
        public void createGui(int iterations) {
               //Create all components
              progressFrame = new JFrame("Calculation Progress");
              progressFrame.setSize(300, 100);
              pane = progressFrame.getContentPane();
              pane.setLayout(null);
              label = new JLabel("Calculating...");
              label.setBounds(115, 35, 200, 25);
              progressBar = new JProgressBar(0, iterations);
              progressBar.setBounds(10, 10, 280, 20);
              progressBar.setStringPainted(true);
              //Add components to pane
              pane.add(progressBar);
              pane.add(label);
              //Make frame visible
              progressFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              progressFrame.setResizable(false); //No resize
              progressFrame.setLocationRelativeTo(null);
              progressFrame.setVisible(true);
        }
    
        public void runCalcs (double MP, double StepAmt, double L1, double L2,
                double C1, double C2, double IM1, double IM2, double M1Start, double M2Start) {
    
            progressBar.setIndeterminate(false);
            TwoWorker task = new TwoWorker(MP, StepAmt, L1, L2, C1, C2, IM1, IM2, M1Start, M2Start);
            task.addPropertyChangeListener(new PropertyChangeListener() {
    
                @Override
                public void propertyChange(PropertyChangeEvent e) {
                    if ("progress".equals(e.getPropertyName())) {
                        progressBar.setIndeterminate(false);
                        progressBar.setValue((Integer) e.getNewValue());
                    }
                }
            });
            task.execute();
        } //end method runCalcs
    
        public class TwoWorker extends SwingWorker<Double, Double> {
    
            private final double MP, StepAmt,L1, L2,
                C1, C2, IM1, IM2, M1Start, M2Start;
    
            public TwoWorker(double MPa, double StepAmta, double L1a, double L2a,
                double C1a, double C2a, double IM1a, double IM2a, double M1Starta, double M2Starta) {
    
                MP = MPa;
                StepAmt = StepAmta;
                L1 = L1a;
                L2 = L2a;
                C1 = C1a;
                C2 = C2a;
                IM1 = IM1a;
                IM2 = IM2a;
                M1Start = M1Starta;
                M2Start = M2Starta;
               }
            @Override
            protected Double doInBackground() {
    
                double M1 = M1Start;
                double M2 = M2Start;
    
            // Set MinLoop as maximum to start
            // Loan 1
            double N1 = (Math.log10(1 - IM1 * L1 / M1) * -1)/Math.log10(1 + IM1);
        double M1Sum = M1 * N1;
        // Loan 2
        double N2 = (Math.log10(1 - IM2 * L2 / M2) * -1)/Math.log10(1 + IM2);
        double M2Sum = M2 * N2;
        double minLoop = M1Sum + M2Sum;
        double MTotal = 0;
    
            // Define variables for mins
        double MP1 = 0;
        double MP2 = 0;
        double NP1 = 0;
        double NP2 = 0;
        double MP1Sum = 0;
        double MP2Sum = 0;
    
            while ( M1 <= MP - M2Start && M2 >= M2Start ) {
                N1 = (Math.log10(1 - IM1 * L1 / M1) * -1)/Math.log10(1 + IM1);
                M1Sum = N1 * M1;
                N2 = (Math.log10(1 - IM2 * L2 / M2) * -1)/Math.log10(1 + IM2);
                M2Sum = N2 * M2;
                MTotal = M1Sum + M2Sum;
                if (MTotal < minLoop) {
                    minLoop = MTotal;
                    MP1 = M1;
                    MP2 = M2;
                    NP1 = N1;
                    NP2 = N2;
                    MP1Sum = M1Sum;
                    MP2Sum = M2Sum;
                } // end if
                            i++;
                            progressBar.setValue(i);
                        M1 = M1 + StepAmt;
                M2 = MP - M1;
                // Reset monthly sums
                M1Sum = 0;
                M2Sum = 0;
            } // end while
    
            System.out.printf("MP1 = %.2f\n", MP1);
            System.out.printf("MP2 = %.2f\n", MP2);
            System.out.printf("NP1 = %.2f\n", NP1);
            System.out.printf("NP2 = %.2f\n", NP2);
            System.out.printf("MP1Sum = %.2f\n", MP1Sum);
            System.out.printf("MP2Sum = %.2f\n", MP2Sum);
                    System.out.printf("MTotal = %.2f\n", minLoop);
                    System.out.printf("i = %d\n",i);
                    System.out.printf("M1Start = %.2f\n", M1Start);
            System.out.printf("M2Start = %.2f\n", M2Start);
                    System.out.printf("MP= %.2f\n",MP);
    
        // if there's a value for current payments, calculate amount saved
        if( C1 > 0 ) {
            double CN1 = (Math.log10(1 - IM1 * L1 / C1) * -1)/Math.log10(1 + IM1);
            double CT1 = CN1 * C1;
    
            double CN2 = (Math.log10(1 - IM2 * L2 / C2) * -1)/Math.log10(1 + IM2);
            double CT2 = CN2 * C2;
    
            double CTotal = CT1 + CT2;
            amountSaved = CTotal - minLoop;
            } // end if
    
            return null;
    
        } // end doInBackGround
    
            @Override
            protected void done() {
                label.setBounds(133, 35, 200, 25);
                label.setText("Done!");
            }
        } // end TwoWorker
    
    
        public double savedReturn() {
            return amountSaved;
        }
    
    } // end class twoLoans
    

    【讨论】:

      【解决方案2】:

      SwingWorker 非常适合这种情况。下面的示例在后台执行简单的迭代,同时在窗口中报告进度和中间结果。您可以在合适的SwingWorker 构造函数中传递您需要的任何参数。

      import java.awt.EventQueue;
      import java.awt.GridLayout;
      import java.beans.PropertyChangeEvent;
      import java.beans.PropertyChangeListener;
      import java.text.DecimalFormat;
      import java.util.List;
      import javax.swing.*;
      
      /** @see http://stackoverflow.com/questions/4637215 */
      public class TwoRoot extends JFrame {
      
          private static final String s = "0.000000000000000";
          private JProgressBar progressBar = new JProgressBar(0, 100);
          private JLabel label = new JLabel(s, JLabel.CENTER);
      
          public TwoRoot() {
              this.setLayout(new GridLayout(0, 1));
              this.setTitle("√2");
              this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
              this.add(progressBar);
              this.add(label);
              this.setSize(161, 100);
              this.setLocationRelativeTo(null);
              this.setVisible(true);
          }
      
          public void runCalc() {
              progressBar.setIndeterminate(true);
              TwoWorker task = new TwoWorker();
              task.addPropertyChangeListener(new PropertyChangeListener() {
      
                  @Override
                  public void propertyChange(PropertyChangeEvent e) {
                      if ("progress".equals(e.getPropertyName())) {
                          progressBar.setIndeterminate(false);
                          progressBar.setValue((Integer) e.getNewValue());
                      }
                  }
              });
              task.execute();
          }
      
          private class TwoWorker extends SwingWorker<Double, Double> {
      
              private static final int N = 5;
              private final DecimalFormat df = new DecimalFormat(s);
              double x = 1;
      
              @Override
              protected Double doInBackground() throws Exception {
                  for (int i = 1; i <= N; i++) {
                      x = x - (((x * x - 2) / (2 * x)));
                      setProgress(i * (100 / N));
                      publish(Double.valueOf(x));
                      Thread.sleep(1000); // simulate latency
                  }
                  return Double.valueOf(x);
              }
      
              @Override
              protected void process(List<Double> chunks) {
                  for (double d : chunks) {
                      label.setText(df.format(d));
                  }
              }
          }
      
          public static void main(String[] args) {
              EventQueue.invokeLater(new Runnable() {
      
                  @Override
                  public void run() {
                      TwoRoot t = new TwoRoot();
                      t.runCalc();
                  }
              });
          }
      }
      

      【讨论】:

      • 如果在 actionPerformed 中,我该如何运行它?是否仍然需要 invokeLater 或者我可以实例化 SwingWorker 并直接执行它?
      • 后者,如图here
      • 另见相关JFreeChartexample
      【解决方案3】:

      我觉得你的预感是对的,你需要遵守 Swing 线程规则。

      那该怎么办?

      首先,我不确定您的应用是如何设计的。你说你有一个包含一堆行的主框架,每个都可能调用 9 个类中的一个,它们看起来都像上面的那个。这些类似乎会生成自己的JFrame。我猜这个新框架仅用于进度条。我会假设这是设计,并会提出相应的建议。

      我建议您在 Runnable 的实例中执行几个操作,然后将这些 Runnable 实例放入 SwingUtilities.invokeLater 以让它们在 EDT 上运行。同时,为了便于阅读,我会花时间重新组织您的代码。

      1. 将 GUI 位的创建移到方法中:
      公共无效创建组件(){
            SwingUtilities.invokeLater(new Runnable() {
              公共无效运行(){
                //创建所有组件
                progressFrame = new JFrame("计算进度");
                progressFrame.setSize(300, 100);
                窗格 = progressFrame.getContentPane();
                窗格.setLayout(null);
                progressFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                progressBar = new JProgressBar(0, 迭代);
                //将组件添加到窗格
                窗格.add(进度条);
      
                //位置控件(X、Y、宽度、高度)
                progressBar.setBounds(10, 10, 280, 20);
      
                //使框架可见
                progressFrame.setResizable(false); //不调整大小
                progressFrame.setVisible(true);
             }
            });
      
          }
      
      1. 然后我将系统化您在 calc 中的两个 GUI 操作:
      私人无效updateProgressBar(最终int i){ SwingUtilities.invokeLater(new Runnable() { 公共无效运行(){ 进度条.setValue(i); //不需要下面的 //progressBar.repaint(); } }); } 私人无效killDialog(){ SwingUtilities.invokeLater(new Runnable() { 公共无效运行(){ progressFrame.setVisible(false); } }); }
      1. 最后,将这些新方法中包含的代码替换为对方法的调用。

      【讨论】:

      • 非常感谢您的帮助,我已经在这个问题上停留了一段时间。我一直在研究它,但我无法弄清楚如何实时调用新方法。使用我更新的代码,创建了 GUI,并在执行计算后更新了进度条。你介意帮助我调用这些方法吗?我在“runCalcs”中类似地调用了所有内容,如下所示: SwingUtilities.invokeLater(new Runnable() { public void run() { createComponents(iterations); } });
      猜你喜欢
      • 2015-07-18
      • 2012-11-22
      • 2019-06-21
      • 1970-01-01
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多