【问题标题】:JProgressBar doesn't update , can't find a clueJProgressBar 不更新,找不到线索
【发布时间】:2012-02-19 13:23:07
【问题描述】:

干得好,现在我只想知道为什么如果我将指令 System.out.println 添加到 while 循环中,进度会同时显示在 Gui 中的 cmd 和 Pgbar 上? :

while(progress < 99){ 
  System.out.println("into while of PBar Thread progress = "+progress); 
  if(progress != Path.operationProgress){ 
    operationProgressBar.setValue(progress); 
    progress = Path.operationProgress; 
    operationProgressBar.repaint(); } }

需要一些帮助,我无法让 JProgressBar 更新,我 不能使用 SwingWorker,没有它我必须解决这个问题。变量 Path.operationProgress 是来自“Path”类的静态变量 例如,它是从另一个线程更新的,所以我认为 PBar 和 Path 实例都在用户的线程中执行,而不是在 美东时间 。这是进度条的代码:

    import javax.swing.*;
    public class Pbar extends Thread {
      JProgressBar operationProgressBar;
      public Pbar(JProgressBar operationProgressBar) {
          this.operationProgressBar = operationProgressBar;
      }

      @Override
      public void run() {
          int progress = Path.operationProgress;
          while(progress < 99) {
              if(progress != Path.operationProgress) {
                  operationProgressBar.setValue(progress);
                  progress = Path.operationProgress;
                  operationProgressBar.repaint();
              }}}
     }

这是启动线程的操作:

private javax.swing.JProgressBar operationProgressBar;
private javax.swing.JLabel pathImage;
private javax.swing.JButton simulatedAnnelingButton;

public class TSPGUI extends javax.swing.JFrame {

    TSPMG tspInstance;
    Path p, result;
    String filename = "";
    int neighborHood_Type = 1, i = 0;
    // ......Constructor Stuff and init()

private void simulatedAnnelingButtonActionPerformed(java.awt.event.ActionEvent evt)

{
线程 sa = 新线程(){ @Override 公共无效运行(){ 结果 = p.SimulatedAnnealing(neighborHood_Type); 字符串 lastCostString = result.Cost() + ""; lastCostLabel.setText(lastCostString); }}; sa.start(); Pbar pb = new Pbar(operationProgressBar); pb.start(); } //其他一些东西... }

【问题讨论】:

  • 尽管您很小心尝试在后台线程中执行操作,但您的问题闻起来像是线程问题——或者正在更新的 JProgressBar 不是正在显示的问题。但是,如果没有更多代码,就很难说。如果上面的代码在后台线程上运行,你必须注意在 EDT 上调用进度条 setValue(...),虽然这不能解决你的问题,但它可以防止一些间歇性异常的发生。我建议您向我们展示更多代码,最好是sscce。
  • 请对代码块使用一致且符合逻辑的缩进,并且不需要在每个代码行之后都有空行!
  • 另外,你应该努力实现 Runnable 而不是扩展 Thread。另外你是如何运行线程的?你打电话给start() 或run() 吗? ...您的问题会引出更多问题,最好还是由sscce 回答。我知道我在这里听起来像是一张破唱片,但如果写得好,这些该死的东西会非常有帮助。
  • 更新的代码不可读。请在我的答案下方查看我的 cmets。

标签: java multithreading oracle swing jprogressbar


【解决方案1】:

如果您不能使用SwingWorker,则使用SwingUtilities.invokeLater,例如:

if (progress != Path.operationProgress) {
    final int progressCopy = progress; // Probably not final so copy is needed
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        void run() {
            operationsProgressBar.setValue(progressCopy);
        }
    });
}

注意:这样做时,run 中使用的所有内容都必须是最终的,否则必须有其他措施来访问变量。这段代码在这方面是象征性的。

你需要在事件分发线程之外对Swing组件进行操作,没有办法。

【讨论】:

  • 很好,但正如@HovercraftFullOfEels 所说,这似乎并不能解决问题。
  • @TheEighthEro:你仍然有冲突的线程,它甚至可能不是 EDT,而很可能是一个正在冲突的后台线程。我强烈建议您发布对我们来说可编译和可运行的小代码,sscce。我还建议您不要对变量进行 100% 轮询,而是让 observable 在结果发生变化时将结果推送给观察者。
【解决方案2】:

我会使用 PropertyChangeListener 让您将退火进度值设为类的“绑定”属性。如果需要,任何观察者都可以遵循此属性。例如:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;

@SuppressWarnings("serial")
public class TspGui2 extends JPanel {
   private static final String ANNEALING_PROGRESS = "Annealing Progress";
   private JProgressBar progBar = new JProgressBar(0, 100);
   private JLabel valueLabel = new JLabel();
   private JButton beginAnnealingBtn = new JButton("Begin Annealing");
   private MyAnnealing myAnnealing = new MyAnnealing(this);

   public TspGui2() {
      beginAnnealingBtn.addActionListener(new ActionListener() {

         @Override
         public void actionPerformed(ActionEvent e) {
            beginAnnealing();
         }
      });
      myAnnealing.addPropertyChangeListener(new PropertyChangeListener() {

         @Override
         public void propertyChange(PropertyChangeEvent evt) {
            if (evt.getPropertyName().equals(MyAnnealing.ANNEALING)) {
               // be sure this is done on the EDT
               SwingUtilities.invokeLater(new Runnable() {
                  public void run() {
                     int annealedValue = myAnnealing.getAnnealedValue();
                     setValue(annealedValue);
                     if (annealedValue >= MyAnnealing.MAX_ANNEALED_VALUE) {
                        beginAnnealingBtn.setEnabled(true);
                     }
                  }
               });
            }
         }
      });
      progBar.setString(ANNEALING_PROGRESS);
      progBar.setStringPainted(true);

      JPanel northPanel = new JPanel(new GridLayout(1, 0));
      northPanel.add(beginAnnealingBtn);
      northPanel.add(valueLabel);

      setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
      add(northPanel);
      add(progBar);
   }

   public void setValue(int value) {
      valueLabel.setText("Value:" + value);
      progBar.setValue(value);
   }

   public void beginAnnealing() {
      beginAnnealingBtn.setEnabled(false);
      setValue(0);
      myAnnealing.reset();
      new Thread(new Runnable() {
         public void run() {
            myAnnealing.beginAnnealing();
         }
      }).start();
   }

   private static void createAndShowGui() {
      TspGui2 mainPanel = new TspGui2();

      JFrame frame = new JFrame("TspGui2");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

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

class MyAnnealing {
   public static final String ANNEALING = "Annealing";
   public  static final int MAX_ANNEALED_VALUE = 100;
   private SwingPropertyChangeSupport propChangeSupport = 
         new SwingPropertyChangeSupport(this);
   private TspGui2 gui;
   private int annealedValue;

   public MyAnnealing(TspGui2 gui) {
      this.gui = gui;
   }

   public void addPropertyChangeListener(
         PropertyChangeListener listener) {
      propChangeSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(
         PropertyChangeListener listener) {
      propChangeSupport.removePropertyChangeListener(listener);
   }

   public void reset() {
      setAnnealedValue(0);
   }

   // simulate some long process...
   public void beginAnnealing() {
      long sleepDelay = 100;
      while (annealedValue < MAX_ANNEALED_VALUE) {
         setAnnealedValue(annealedValue + 1);
         try {
            Thread.sleep(sleepDelay);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }
   }

   public int getAnnealedValue() {
      return annealedValue;
   }

   private void setAnnealedValue(int value) {
      final int oldValue = this.annealedValue;
      this.annealedValue = value;
      propChangeSupport.firePropertyChange(ANNEALING, oldValue, annealedValue);
   }   
}

【讨论】:

  • @TheEighthEro:你不能在 cmets 中发布代码,因为它根本不可读。
  • @TheEighthEro:考虑格式化新代码并澄清问题。此外,如果您大大简化了代码并且实际上创建并发布了一个类似于我上面发布的sscce,那么帮助解决您的问题会容易得多。可以使用简单的Thread.sleep(...) 模拟长时间运行的退火过程。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
相关资源
最近更新 更多