# JProgressBar für einen Thread



## maximilian1 (25. Jul 2011)

Hallo, ich möchte gerne eine JProgressBar benutzen um den aktuellen Fortschritt eines Threads anzuzeigen. Ich habe mal ein Tutorial umgeschrieben. Mein Problem ist, dass ich auf das Ende des Threads warten muss, bevor das Programm weiter läuft. In dem Tutorial wird ein SwingWorker genutzt und da gibt es kein .join(), ich habe es mit .get() versucht, aber dann wird die ProgressBar nicht mehr aktuallisiert. Hier mein code:


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

public class ProgressBarDemo extends JPanel
                             implements ActionListener, 
                                        PropertyChangeListener {

    private JProgressBar progressBar;
    private JButton startButton;
    private JTextArea taskOutput;
    private Task task;
    private boolean done;

    class Task extends SwingWorker<Void, Void> {
        /*
         * Main task. Executed in background thread.
         */
        @Override
        public Void doInBackground() {
            int progress = 0;
            setProgress(0);
            while (progress <= 1000) {
            	setProgress( (int)((double)progress/(double)10) );
            	progress++;
            	try {
					Thread.sleep(1);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
            }
            return null;
        }

        /*
         * Executed in event dispatching thread
         */
        @Override
        public void done() {
        	done = true;
            //Toolkit.getDefaultToolkit().beep();
            //startButton.setEnabled(true);
            //setCursor(null); //turn off the wait cursor
            //taskOutput.append("Done!\n");
        	System.out.println("done");
        }
    }

    public ProgressBarDemo() {
        super(new BorderLayout());

        //Create the demo's UI.
        startButton = new JButton("Start");
        startButton.setActionCommand("start");
        startButton.addActionListener(this);

        progressBar = new JProgressBar(0, 100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);

        taskOutput = new JTextArea(5, 20);
        taskOutput.setMargin(new Insets(5,5,5,5));
        taskOutput.setEditable(false);

        JPanel panel = new JPanel();
        panel.add(startButton);
        panel.add(progressBar);

        add(panel, BorderLayout.PAGE_START);
        add(new JScrollPane(taskOutput), BorderLayout.CENTER);
        setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));

    }

    /**
     * Invoked when the user presses the start button.
     */
    public void actionPerformed(ActionEvent evt) {
        startButton.setEnabled(false);
        //setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        //Instances of javax.swing.SwingWorker are not reusuable, so
        //we create new instances as needed.
        task = new Task();
        task.addPropertyChangeListener(this);
        task.execute();
        
        while( !task.isDone() ){
        }
        
        System.out.println(task.getProgress());
    }

    /**
     * Invoked when task's progress property changes.
     */
    public void propertyChange(PropertyChangeEvent evt) {
        if ("progress" == evt.getPropertyName()) {
            int progress = (Integer) evt.getNewValue();
            progressBar.setValue(progress);
            progressBar.paint(progressBar.getGraphics());
            taskOutput.append(String.format(
                    "Completed %d%% of task.\n", task.getProgress()));
        } 
    }


    /**
     * Create the GUI and show it. As with all GUI code, this must run
     * on the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("ProgressBarDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new ProgressBarDemo();
        //newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
```


----------



## Gast2 (25. Jul 2011)

Mit 

```
while( !task.isDone() ){
        }
```
blockierst du den EDT, damit kann sich die GUI dann nicht aktualisieren.
Nimm die while-schleife raus und du erhälst das gewünschte verhalten.


----------



## maximilian1 (25. Jul 2011)

aber dann ist die berechnung noch nicht zuende und er gibt das falsche ergebniss aus. Er soll erst weiter machen, wenn er bei 100% angekommen ist.


----------



## Gast2 (25. Jul 2011)

Wenn du den EDT unterbrichst dann friert dir deine GUI ein, deswegen muss die schleife da raus.

Warum soll der Code denn da stehen bleiben? Außer nen sysout machst du da ja nichts, da könntest du dann auch in den Task schreiben.


----------



## maximilian1 (25. Jul 2011)

So ich habs jetzt mal umgeschrieben. Jetzt funktioniert das so wie ich es will. Das hier ist aber nur ein kleines Test Programm. In meinem Richtigen Programm macht diese Lösung noch probleme. Da funktioniert das mit .join() nämlich nicht. Da wird die ProgressBar nicht altuallisiert. Woran liegt das?


```
package testing;

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

public class ProgressBarDemo extends JPanel implements ActionListener {

	private static final long serialVersionUID = 1L;
	private JProgressBar progressBar;
    private JButton startButton;

    public class ProducerDo extends Thread {
    	
    	private int counter;
    	
    	public ProducerDo(){
    	}
    	
    	public void run(){
    		try {
    			while( counter <= 100 ){
    				System.out.println("Producer: " + counter);
    				Thread.sleep(10);
    				counter++;	
    			}
    		} catch (InterruptedException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		} 
    	}
    	
    	public int getProcess(){
    		return counter;
    	}
    }
    
    public class ConsumerDo extends Thread {

    	private ProducerDo producer;
    	private JProgressBar progressBar;
    	
    	public ConsumerDo( ProducerDo producer, JProgressBar progressBar){
    		this.producer = producer;
    		this.progressBar = progressBar;
    	}

    	public void run(){
    		try {
    			int counter = 0;
    			while( counter <= 100 ){
    				progressBar.setValue(counter);
    				progressBar.paint(progressBar.getGraphics());
    				counter = producer.getProcess();
    				Thread.sleep(5);
    			}
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}

    	}
    }

    public ProgressBarDemo() {
        super(new BorderLayout());

        //Create the demo's UI.
        startButton = new JButton("Start");
        startButton.setActionCommand("start");
        startButton.addActionListener(this);

        progressBar = new JProgressBar(0, 100);
        progressBar.setValue(0);
        progressBar.setStringPainted(true);

        JPanel panel = new JPanel();
        panel.add(startButton);
        panel.add(progressBar);

        add(panel, BorderLayout.PAGE_START);

    }

    /**
     * Invoked when the user presses the start button.
     */
    public void actionPerformed(ActionEvent evt) {
    	progressBar.setValue(0);
        ProducerDo producer = new ProducerDo();
        ConsumerDo consum = new ConsumerDo(producer, progressBar);
        producer.start();
        consum.start();
        
        try {
			producer.join();
			consum.join();
		} catch (InterruptedException e) {
		}
        
        System.out.println("done");
    }

    /**
     * Create the GUI and show it. As with all GUI code, this must run
     * on the event-dispatching thread.
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("ProgressBarDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        JComponent newContentPane = new ProgressBarDemo();
        //newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
```


----------



## Gast2 (25. Jul 2011)

> Da wird die ProgressBar nicht altuallisiert. Woran liegt das?


Weil du sicherlich irgendwie/irgendwo den EDT blockierst.
Was willst du mit diesem Konstrukt eigentlich erreichen?


----------



## maximilian1 (25. Jul 2011)

Das Programm soll eine Datenbank durchsuchen und die progressbar soll über den aktuellen prozess informieren. wenn die Datenbank komplett durchsucht ist soll sie über die Gui in einer JTabel ausgegeben werden. Wie kann ich dieses blokierte EDT aufspüren. bzw. was muss ich beachten, damit sowas nicht geschieht?


----------



## Gast2 (25. Jul 2011)

Zeig mal deinen Code wie du das bisher gelöst hast.
Ich würde das so machen:

User löst aktion aus:
-> Thread starten der die Datenbank durchsucht
-> Nebenbei schreibt der Thread seine Ergebnisse in eine Liste (oder eine anderen Datenstruktur) und setzt den Wert der Progressbar.
-> Wenn der Thread fertig ist schreibt er die Daten in die JTable
-> Thread stirbt

Da musst du eigentlich nichts großartig beachten, du brauchst auch kein join oder ähnliches dafür.


----------



## maximilian1 (25. Jul 2011)

der Code ist ziemlich groß aber vllt kannst du mir ja sagen was es mit dieser Fehlermeldung aufsich hat:

Exception in thread "Thread-4" fertig zusammengebaut!
java.lang.NullPointerException
	at javax.swing.JComponent.getComponentGraphics(Unknown Source)
	at javax.swing.JComponent.paint(Unknown Source)
	at core.Search.run(Search.java:141)

141: progressBar.paint(progressBar.getGraphics());

die kommt sobald nem neuen Tread wieder die progressBar zuweise.


----------



## Gast2 (25. Jul 2011)

```
141: progressBar.paint(progressBar.getGraphics());
```
ARG!! Böse Böse Böse *dreimalschwarzerkater* :shock:


```
java.lang.NullPointerException
```
 heißt, dass du irgendeine Methode auf ner null Referenz aufrufst.

Der Code schaut aber erschreckend falsch aus, willst du damit bezwecken dass sich die progressbar aktualisiert?


----------



## maximilian1 (25. Jul 2011)

ja das hatte ich in nem Forum gelesen. gibt es da ne bessere Möglichkeit. Muss ich mein Problem eigentlich mit nem Tread lösen.


----------



## Gast2 (25. Jul 2011)

Dann vergiss das am besten ganz schnell wieder, das ist totaler murks.

Es reicht wenn du dein datenbankdurchsuchen in nem extra Thread aufrufst der dann setValue auf der progressbar aufruft.


----------



## maximilian1 (25. Jul 2011)

ja aber er aktualiesiert die progressbar einfach nicht


----------



## Gast2 (25. Jul 2011)

EikeB hat gesagt.:
			
		

> [...]blockierst du den EDT





			
				EikeB hat gesagt.:
			
		

> Wenn du den EDT unterbrichst dann friert dir deine GUI ein





			
				EikeB hat gesagt.:
			
		

> Weil du sicherlich irgendwie/irgendwo den EDT blockierst.



Poste doch mal deinen Code...


----------



## maximilian1 (26. Jul 2011)

danke ich habe es hinbekommen


----------

