3

nice job , now i just wanna know why if i add into while loop the instruction System.out.println below the progress is shown on both , cmd and Pgbar in the Gui ?? :

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(); } }

need some help around , i can't get the JProgressBar to update, i can't use SwingWorker, i have to solve this without it . the variable Path.operationProgress is a static variable from a "Path" class instance, and it's updated from another thread, so i think the PBar and Path instances are both executed in user's Threads and not in the EDT . here is the Code of the progress bar :

    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();
              }}}
     }

this is the action that launches the threads :

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)

{
Thread sa = new Thread(){ @Override public void run(){ result = p.SimulatedAnnealing(neighborHood_Type); String lastCostString = result.Cost() + ""; lastCostLabel.setText(lastCostString); }}; sa.start(); Pbar pb = new Pbar(operationProgressBar); pb.start(); } //Some other Stuff ... }

The Eighth Ero
  • 417
  • 4
  • 13
  • 1
    Despite your care to try to do things in a background thread, your problem smells like a threading issue -- either that or the JProgressBar being updated is not the one being displayed. Without more code, though, it's difficult to say. If the code above is run on a background thread, you must take care to call the progress bar setValue(...) on the EDT, although this won't solve your problem, it may prevent some intermittent exceptions from occurring. I suggest that you show us more code, preferably an [sscce](http://sscce.org). – Hovercraft Full Of Eels Feb 19 '12 at 13:28
  • Please use a consistent and logical indent for code blocks, and there is no need for a blank line after every single code line! – Andrew Thompson Feb 19 '12 at 13:38
  • Also, you should strive to implement Runnable rather than extend Thread. Also how are you running the thread? Are you calling `start()` or `run()` on it? ... your question leads to many more questions that again would best be answered by an [sscce](http://sscce.org). I know I'm sounding like a broken record here, but it's just that those darn things are so dang helpful if written well. – Hovercraft Full Of Eels Feb 19 '12 at 13:43
  • Updated code unreadable. See my comments below my answer as well. – Hovercraft Full Of Eels Feb 19 '12 at 20:30

2 Answers2

5

If you can't use SwingWorker then use SwingUtilities.invokeLater, e.g.:

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);
        }
    });
}

Note: When doing this, everything used in run has to be final or there have to be other measures to access the variables. This code is symbolic in that regard.

You need to do operations on Swing components outside the event dispatching thread, there is no way around this.

Hauke Ingmar Schmidt
  • 11,559
  • 1
  • 42
  • 50
  • Nice, but as @HovercraftFullOfEels said , this doesn't seem to solve the problem . – The Eighth Ero Feb 19 '12 at 17:04
  • @TheEighthEro: You've still got colliding threads, and it may not even be the EDT, but rather quite possibly a background thread that's colliding. I strongly urge you to post code that is small, that is *compilable* and *runnable* for us, an [sscce](http://sscce.org). I also recommend that you not do 100% polling of your variable but rather let the observable push the result out to the observers whenever it changes. – Hovercraft Full Of Eels Feb 19 '12 at 17:28
0

I would use a PropertyChangeListener to allow you to make the annealing progress value a "bound" property of the class. Than any observer can follow this property if desired. For example:

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);
   }   
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • @TheEighthEro: ya can't post code in comments as it's simply unreadable. – Hovercraft Full Of Eels Feb 19 '12 at 18:29
  • @TheEighthEro: consider formatting the new code and clarifying the question. Also, it would be much easier to help solve your problem if you simplified your code greatly and in fact created and posted an [sscce](http://sscce.org) similar to what I've posted above. The long-running annealing process can be simulated with a simple `Thread.sleep(...)`. – Hovercraft Full Of Eels Feb 19 '12 at 18:47