# Thread macht keine Pause



## flashdog (14. Aug 2008)

Hallo,
ich habe eine kleine Simulation die mit einem Button gestartet wird und dies funktioniert, aber ich bekomme es einfach nicht hin mit dem gleichen Button die Simulation anzuhalten um sie bei erneunten druecken wieder fortzufuehren.


```
import java.awt.*;
import java.awt.Button;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

public class BallRoom extends JApplet implements ActionListener, Runnable {
	private final int WIDTH = 350;
	private final int HEIGHT = 300;
	private PaintSurface canvas;
	private JButton controlSimulation;
	boolean doSuspend = false;
	Thread th;

	public void init() {      
		this.setSize(WIDTH, HEIGHT);
		canvas = new PaintSurface();
		this.add(canvas, BorderLayout.CENTER);
		controlSimulation = new JButton("Start");
		controlSimulation.addActionListener(this);
		this.add(controlSimulation, BorderLayout.SOUTH);
	}

	public void run() {
		while (true){
			repaint();
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException ex){
				if (doSuspend) {
					doSuspend = false;
					controlSimulation.setText("Start");//setText("Start");
					System.out.println("Displayer suspended");
					th.suspend();
				}
			}
		}
	}

	public void update(Graphics g) {
		paint(g);
	}

	public void actionPerformed(ActionEvent e){
		if (e.getSource() == controlSimulation){
			if (th == null) {
				th = new Thread(this);
				th.start();
				controlSimulation.setText("Stop");
			}
			//else th.resume();
			//controlSimulation.setLabel("Stop");
			else if (th != null) {	
				doSuspend = true;
		}

		}
	}
}
```


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;

class PaintSurface extends JComponent {
  int ball1_x_pos = 0; // the starting X position
  int ball1_y_pos = 150; // the starting Y position
  int ball2_x_pos = 60; // the starting X position
  int ball2_y_pos = 150; // the starting Y position
 
  int d = 20; // the diameter of the ball

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    ball1_x_pos++; // move ball1 right one pixel
    ball2_x_pos--; // move ball1 left one pixel
    Shape ball1 = new Ellipse2D.Float(ball1_x_pos, ball1_y_pos, d, d);
    Shape ball2 = new Ellipse2D.Float(ball2_x_pos, ball2_y_pos, d, d);
    g2.setColor(Color.RED);
    g2.fill(ball1);
    g2.fill(ball2);
  }
}
```

Was mache ich falch?

Viele Gruesse


----------



## SlaterB (14. Aug 2008)

die Abfrage
> if (doSuspend) { 
steht nur im catch-Block,
der aber nie ausgeführt wird, da du den Thread nicht unterbrichst,
verwende evtl. thread.interrupt(), da hast du aber vielleicht Pech, wenn das genau in der Zeit passiert, in der der Thread nicht schläft

viel sauberer und einfacher wäre aber, das if nicht im catch sondern sondern ganz normal am Anfang oder Ende der Schleife zu schreiben


----------



## flashdog (14. Aug 2008)

Habe if aus catch rausgeholt und jetzt klappt die Unterbrechung, aber leider wenn ich erneut den Button klicke statet die Simultion nicht.

Wo koennte noch der Fehler sein?


```
public void run() {
		while (true){
			if (doSuspend) {
				doSuspend = false;
				controlSimulation.setText("Start");//setText("Start");
				System.out.println("Displayer suspended");
				th.suspend();
			}
			repaint();
			try {
				Thread.sleep(100);
			}
			catch (InterruptedException ex){
			}
		}
	}
```


----------



## L-ectron-X (14. Aug 2008)

suspend() ist deprecated.
Die run()-Methode kann nur einmal gestartet werden. Du brauchst danach ein neues Thread-Objekt.


----------



## SlaterB (14. Aug 2008)

oder den Thread in ein Dauersleep legen und später aufwecken, z.B. mit interrupt(),
schöner gehts wohl mit wait()/ notify(),

einfach mal Lehrbücher lesen.., suspend habe ich da noch nicht gesehen


----------



## Marco13 (14. Aug 2008)

Für start/stop würde man vielleicht einen neuen Thread erstellen. Für pause/continue (was du ja anscheinen willst) würde man das GANZ GROB so machen

```
import java.awt.*;
import java.awt.Button;
import java.awt.Event;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;
import javax.swing.*;

public class BallRoom extends JApplet implements ActionListener, Runnable {
   private final int WIDTH = 350;
   private final int HEIGHT = 300;
   private PaintSurface canvas;
   private JButton controlSimulation;
   boolean paused = false;
   Thread th;

   public void init() {
      this.setSize(WIDTH, HEIGHT);
      canvas = new PaintSurface();
      this.add(canvas, BorderLayout.CENTER);
      controlSimulation = new JButton("Start");
      controlSimulation.addActionListener(this);
      this.add(controlSimulation, BorderLayout.SOUTH);
   }

   public void run() {
      while (true){
         repaint();
         try {
            Thread.sleep(500);
         }
         catch (InterruptedException ex)
         {
         }
         while (paused)
         {
             System.out.println("Displayer paused");
             synchronized (this)
             {
                 try {
                 wait();
                 }
                 catch (InterruptedException ex)
                 {
                 }
             }
         }
         System.out.println("Displayer running");
      }
   }

   public void update(Graphics g) {
      paint(g);
   }

   public void actionPerformed(ActionEvent e){
      if (e.getSource() == controlSimulation)
      {
         if (th == null)
         {
            th = new Thread(this);
            th.start();
            controlSimulation.setText("Pause");
         }
         else // if (th != null)
         {
             synchronized (this)
             {
                 if (paused)
                 {
                     paused = false;
                     controlSimulation.setText("Pause");
                     notify();
                 }
                 else
                 {
                     paused = true;
                     controlSimulation.setText("Continue");
                 }
             }
         }

      }

      }
}

class PaintSurface extends JComponent {
  int ball1_x_pos = 0; // the starting X position
  int ball1_y_pos = 150; // the starting Y position
  int ball2_x_pos = 60; // the starting X position
  int ball2_y_pos = 150; // the starting Y position

  int d = 20; // the diameter of the ball

  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    ball1_x_pos++; // move ball1 right one pixel
    ball2_x_pos--; // move ball1 left one pixel
    Shape ball1 = new Ellipse2D.Float(ball1_x_pos, ball1_y_pos, d, d);
    Shape ball2 = new Ellipse2D.Float(ball2_x_pos, ball2_y_pos, d, d);
    g2.setColor(Color.RED);
    g2.fill(ball1);
    g2.fill(ball2);
  }
}
```


----------



## flashdog (15. Aug 2008)

@Marco13: Danke, es ist genau das was ich haben wollte, aber ich dachte es waehre auch praktisch die Simulation mit einem zusaetlichen Stop Button zu beenden. 

Die Beendigung funktioniert, aber ich kann die Simulation nicht mit dem Start Button wieder von Anfang an starten.


```
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.Graphics;
import javax.swing.*;

public class BallRoom extends JApplet implements ActionListener, Runnable {
	private final int WIDTH = 350;
	private final int HEIGHT = 300;
	private PaintSurface canvas;
	private JButton controlSimulation, stopSimulation;
	private JPanel controlPanel;
	
	boolean paused = false;
	boolean stop = false;
	Thread th;

	public void init() {
		this.setSize(WIDTH, HEIGHT);
		canvas = new PaintSurface();
		this.add(canvas, BorderLayout.CENTER);
		controlSimulation = new JButton("Start");
		stopSimulation = new JButton("Stop");
		controlSimulation.addActionListener(this);
		stopSimulation.addActionListener(this);
		controlPanel = new JPanel();
		this.add(controlPanel, BorderLayout.SOUTH);
		controlPanel.add(controlSimulation);
		controlPanel.add(stopSimulation);
	}

	public void run() {
		while (!stop){
			repaint();
			try {
				Thread.sleep(500);
			}
			catch (InterruptedException ex)
			{
			}
			while (paused)
			{
				System.out.println("Displayer paused");
				synchronized (this)
				{
					try {
						wait();
					}
					catch (InterruptedException ex)
					{
						System.out.print("InterruptedException");
					}
				}
			}
			System.out.println("Displayer running");
		}
	}

	public void update(Graphics g) {
		paint(g);
	}

	public void actionPerformed(ActionEvent e){
		if (e.getSource() == controlSimulation)
		{
			if (th == null)
			{
				stop = false;
				th = new Thread(this);
				th.start();
				controlSimulation.setText("Pause");
			}
			else // if (th != null)
			{
				synchronized (this)
				{
					if (paused)
					{
						paused = false;
						controlSimulation.setText("Pause");
						notify();
					}
					else
					{
						paused = true;
						controlSimulation.setText("Continue");
					}
				}
			}
		}
		if (e.getSource() == stopSimulation){
			if (th != null){
				stop = true;
				controlSimulation.setText("Start");
				System.out.print("Stop");
			}
		}
	}
}
```

Was mache ich falsch, dass die Simulation nicht von Anfang an startet?


----------



## SlaterB (15. Aug 2008)

so ein großer Kopf über den Hals, da darf man auch mal eigenständig denken,

schaue dir doch genau die Bedingung für das Starten an,
was steht da?: 

> if (th == null)
> { 

und was ist wohl th nach dem Drücken des Stop-Buttons?
nicht null, denn du setzt die Variable nirgendwo auf null,


sowas kann dir auch das Programm auf denkbar einfachste Weise sagen,
wenn man sich nur ein bisschen bemüht:


```
public void actionPerformed(ActionEvent e){
      System.out.println("bin in ActionPerformed");
      if (e.getSource() == controlSimulation)
      {
         System.out.println("controlSimulation gedrückt");

         if (th == null)
         {
            System.out.println("th ist null, starte neuen Thread");

            stop = false;
            th = new Thread(this);
            th.start();
            controlSimulation.setText("Pause");
         }
         else // if (th != null)
         {
            System.out.println("th ist nicht null, bearbeite aktuellen Thread");
            // usw mit den Ausgaben

            ...
         }
      }
      if (e.getSource() == stopSimulation){

         ...
      }
   }
```


----------



## flashdog (15. Aug 2008)

verflickst anscheind ist mein Kopf nicht gross genug. Ich habe mich lange Zeit mit dem Problem beschaeftigt und bin einfach nicht auf die Loesung gekommen.

Leider funktioniert der Stop Knopf wie der Pause Knopf. Ich wollte erreichen, dass nachdem der Stop Knopf gedrueckt wurden ist und man anschliessend den Start Knopf drueckt beginnt die Simulation von Anfang an und nicht wo sie aufgehoert hat.

Vielleicht ist es moeglich die Bealle auf die Anfangsposition zu setzen wenn der Stop Knopf gedruck worden ist und dann mit Start beginnt die Simulation von Anfang an.

Wenn ich dich richtig verstanden habe sollte ich nur dies aendern:
	
	
	
	





```
if (e.getSource() == stopSimulation){
			if (th != null){
				stop = true;
				controlSimulation.setText("Start");
				System.out.print("Stop");
				th = null;
			}
		}
```


Macro13 hat geschrieben: "Für start/stop würde man vielleicht einen neuen Thread erstellen.", aber passiert dies nicht hiermit:

```
if (th == null)
			{
				stop = false;
				th = new Thread(this);
				th.start();
				controlSimulation.setText("Pause");
			}
```

Leider weiss ich nich wie die Simulation von Anfang starten kann.


----------



## SlaterB (15. Aug 2008)

der Thread macht ja nicht viel, er ruft nur repaint auf, setzt keine Variablen,
das passiert bei dir anscheinend in repaint und der paint-Methode ist es sicher herzlich egal, wer denn da repaint() aufgerufen hat,

du brauchst gewiss so eine Art reset()-Methode, die irgendwelche Werte auf den Standard zurücksetzt,
die kannst du bei einen der Buttons aufrufen oder auch zu Beginn der run-Methode vor der while-true-Schleife,

dann würde schon einen Unterschied machen ob ein neuer Thread startet oder ein vorhandener fortgesetzt wird,
denn nur ein neuer Thread kommt an den Code in der run-Methode vor der while-true-Schleife ran


----------



## Marco13 (15. Aug 2008)

Du wirst die Bälle schon wieder auf dei Startposition setzen müssen (von Hand). 

Eine (auch sauberere, modularere und in vieler Hinsicht ggf. vorteilhafte) Alternative wäre, den Simulationszusatnd in einer eigenen Klasse zu speichern. Dass der Simulationszustand (die Ballpositionen) im Moment in der PaintSurface gespeichert werden, ist schon ziemlicher Murks  :autsch: Und die Ballposition bei jedem neuzeichnen zu verändern, ist noch viel murksiger  :autsch:  :autsch: (Stell mal au Pause, und schieb' mal ein Fenster vor dein Applet, nimm es wieder weg, schiebe es wieder davor, nimm es wieder weg....... und beobachte, wie sich die Bälle bewegen, owohl eigentlich garnicht simuliert wird..... :roll: )

Ein bißchen Pseudocode nach dem Model-View-Controller-Pattern (Websuche!). 


```
interface SimulationListener
{
    void simulationStepPerformed();
}

SimulationModel
{
    // Array mit allen Ballpositionen
    private Point ballPositions[] = ...

    // Liste der objekte, die bei jedem Simulationsschritt benachrichtigt werden
    private List<SimulationListener> simulationListeners = ...
    // (dazu noch add/remove-Methoden für SimulationListener)
 

    // Liefert eine Ballposition
    public Point getBallPosition(int ballIndex) { ... }

    public int getNumBalls() { ... }

    public void doSimulationStep()
    {
        // bewege bälle....

       // Benachrichtige alle Listener, dass ein Schritt gemacht wurde
       // (ruft die Methode auch in der PaintSurface auf, die daraufhin
       // die Shapes für die Bälle aktualisiert und neu zeichnet)
       for (SimulationListener simulationListener : simulationListeners)
       { 
           simulationListener.simulationStepPerformed();
       }
    }
}

// zeichnet das aktuelle SimulationModel
class PaintSurface extends JComponent implements SimulationListener
{
    private SimulationModel simulationModel;
    private Shape ballShapes[] = .... (Einmal erstellen, nicht bei jedem neuzeichnen!)

    public PaintSurface(SimulationModel simulationModel)
    {
        this.simulationModel = simulationModel;
        // erstelle ballShapes....
    }


    public void paintComponent(Graphics g) // paintComponent überschreiben, NICHT paint!!!
    {
        for (i=0...n)
        {    
            zeichne(ballShape[i]);
        }
    }

    // Wird bei jedem Simulationsschritt aufgerufen
    public void simulationStepPerformed()
    {
        for (i=0...n)
        {    
            setze Position von ballShape[i] auf simulationModel.getBallPosition(i);
        }
        repaint();
    }

}


class Main
{
    private SimulationModel simulationModel;

    void reset()
    {
        simulationModel = new SimulationModel();
        simulationMode.addSimulationListener(paintSurface);
    }
}
```

Wenn die Simulationsdaten in einer eigenen Klasse liegen, kann diese Klasse eine "Reset"-Methode anbieten, die sie auf den Anfangszustand zurücksetzt. Oder man kann für ein "reset" einfach ein neues SimulationModel erstellen....


----------



## flashdog (16. Aug 2008)

Danke euch beiden fuer die Tipps. Das ursprungliche Beispiel stammt aus "Java All-in-One Desk Reference for Dummies".

Gibt es ein gutes Buch fuer die Design Paterns?


----------



## flashdog (26. Aug 2008)

@Marco13: Leider habe ich dein Pseudocode nicht verstanden und habe es versucht wie folgt modular aufzubauen. Ich habe geschafft das sich ein JDialog Fenster mit Paintsurface (JComponent) und Startbutton oeffnet, aber leider bekomme ich die Simulation bei betteatigen des Strat-Button nicht zum laufen.

Diese ControlVariables Klasse verwende ich um die Variablen als Referenz an JDialog zu uebergeben.

```
public class ControlVariables {
  public Thread th;
  public boolean paused = false;
  public boolean stop = false;
  public int speed = 20;
}
```


```
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JOptionPane;

public class Settings extends JApplet implements ActionListener, Runnable{
	private final int WIDTH = 350;
	private final int HEIGHT = 300;
	private Frame rootFrame;
	private JButton InitButton;
	private ControlVariables controlVariables;
	@Override
	public void init() {
		this.setSize(WIDTH, HEIGHT);
		rootFrame = JOptionPane.getFrameForComponent(this); //For JDialog
		controlVariables = new ControlVariables();
		System.out.print(controlVariables.speed);
		InitButton = new JButton("Init");
		InitButton.addActionListener(this);
		this.add(InitButton, BorderLayout.SOUTH);      
	}

	public void run() {
		while (!controlVariables.stop){
			repaint();
			try {
				System.out.println(controlVariables.speed);
				Thread.sleep(controlVariables.speed);
			}
			catch (InterruptedException ex)
			{
			}
			while (controlVariables.paused)
			{
				System.out.println("Displayer paused");
				synchronized (this)
				{
					try {
						wait();
					}
					catch (InterruptedException ex)
					{
						System.out.print("InterruptedException");
					}
				}
			}
			System.out.println("Displayer running");
		}
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == InitButton){
			Simulation dialog = new Simulation(rootFrame, 
					"Simulations Fenster", true, controlVariables);
			dialog.setSize(500, 300);
			//dialog.pack();
			dialog.setResizable(false);
			dialog.setVisible(true);
		}

	}
}
```


```
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;

public class Simulation extends JDialog implements ActionListener {
	private PaintSurface canvas;
	private JButton controlSimulation;
	private JPanel controlPanel;
	ControlVariables controlVariables;

	public Simulation(java.awt.Frame parent, String title, 
			boolean modal, ControlVariables controlVariables) {
		super(parent, title, modal);
		this.controlVariables = controlVariables;
		System.out.print(controlVariables.speed);
		canvas = new PaintSurface();
		getContentPane().add(canvas, BorderLayout.CENTER);
		controlSimulation = new JButton("Start");
		controlSimulation.addActionListener(this);
		controlPanel = new JPanel();
		controlPanel.add(controlSimulation);
		getContentPane().add(controlPanel, BorderLayout.SOUTH);

	}
	public void actionPerformed(ActionEvent e){
		if (e.getSource() == controlSimulation)
		{
			if (controlVariables.th == null)
			{
				System.out.println(controlVariables.speed);
				controlVariables.stop = false;
				controlVariables.th = new Thread((Runnable) this);
				controlVariables.th.start();
				controlSimulation.setText("Pause");
			}
			else // if (th != null)
			{
				synchronized (this)
				{
					if (controlVariables.paused)
					{
						System.out.println(controlVariables.speed);
						controlVariables.paused = false;
						controlSimulation.setText("Pause");
						notify();
					}
					else
					{
						controlVariables.paused = true;
						controlSimulation.setText("Continue");
					}
				}
			}
		}
	}
}
```

Wenn ich im JDialog Fenster auf den Strat Button klicke um die Simmulation zu starten bekommen ich diese Fehlermeldung.

```
Exception occurred during event dispatching:
java.lang.ClassCastException: Simulation cannot be cast to java.lang.Runnable
	at Simulation.actionPerformed(Simulation.java:35)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.Dialog$1.run(Unknown Source)
	at java.awt.Dialog$3.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.awt.Dialog.show(Unknown Source)
	at java.awt.Component.show(Unknown Source)
	at java.awt.Component.setVisible(Unknown Source)
	at java.awt.Window.setVisible(Unknown Source)
	at java.awt.Dialog.setVisible(Unknown Source)
	at Settings.actionPerformed(Settings.java:62)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)
```

Wo liegt mein Fehler?


----------



## flashdog (26. Aug 2008)

Habe den Fehler gefunden, aber leider wenn ich JDialog Fenster schliesse und wieder oeffne und dann auf den Start-Button klicke funktioniert die Simulation wieder nicht.

```
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JButton;
import javax.swing.JOptionPane;

public class Settings extends JApplet implements ActionListener {
	private final int WIDTH = 350;
	private final int HEIGHT = 300;
	private Frame rootFrame;
	private JButton InitButton;
	private ControlVariables controlVariables;
	@Override
	public void init() {
		this.setSize(WIDTH, HEIGHT);
		rootFrame = JOptionPane.getFrameForComponent(this); //For JDialog
		controlVariables = new ControlVariables();
		System.out.print(controlVariables.speed);
		InitButton = new JButton("Init");
		InitButton.addActionListener(this);
		this.add(InitButton, BorderLayout.SOUTH);      
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == InitButton){
			Simulation dialog = new Simulation(rootFrame, 
					"Simulations Fenster", true, controlVariables);
			dialog.setSize(500, 300);
			//dialog.pack();
			dialog.setResizable(false);
			dialog.setVisible(true);
		}

	}
}
```


```
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;

public class Simulation extends JDialog implements ActionListener, Runnable {
	private PaintSurface canvas;
	private JButton controlSimulation;
	private JPanel controlPanel;
	ControlVariables controlVariables;

	public Simulation(java.awt.Frame parent, String title, 
			boolean modal, ControlVariables controlVariables) {
		super(parent, title, modal);
		this.controlVariables = controlVariables;
		System.out.print(controlVariables.speed);
		canvas = new PaintSurface();
		getContentPane().add(canvas, BorderLayout.CENTER);
		controlSimulation = new JButton("Start");
		controlSimulation.addActionListener(this);
		controlPanel = new JPanel();
		controlPanel.add(controlSimulation);
		getContentPane().add(controlPanel, BorderLayout.SOUTH);

	}
	public void actionPerformed(ActionEvent e){
		if (e.getSource() == controlSimulation)
		{
			if (controlVariables.th == null)
			{
				System.out.println(controlVariables.speed);
				controlVariables.stop = false;
				controlVariables.th = new Thread(this);
				controlVariables.th.start();
				controlSimulation.setText("Pause");
			}
			else // if (th != null)
			{
				synchronized (this)
				{
					if (controlVariables.paused)
					{
						System.out.println(controlVariables.speed);
						controlVariables.paused = false;
						controlSimulation.setText("Pause");
						notify();
					}
					else
					{
						controlVariables.paused = true;
						controlSimulation.setText("Continue");
					}
				}
			}
		}
	}
	@Override
	public void run() {
		while (!controlVariables.stop){
			repaint();
			try {
				System.out.println(controlVariables.speed);
				Thread.sleep(controlVariables.speed);
			}
			catch (InterruptedException ex)
			{
			}
			while (controlVariables.paused)
			{
				System.out.println("Displayer paused");
				synchronized (this)
				{
					try {
						wait();
					}
					catch (InterruptedException ex)
					{
						System.out.print("InterruptedException");
					}
				}
			}
			System.out.println("Displayer running");
		}
		
	}
}
```

Wahrscheinlich liegt es daran dass die run Methode nur einmal gestartet werden darf, kann man dies irgendwie umgehen, so dass ich beliebig oft das JDialog Fenster schliessen kann?


----------



## SlaterB (26. Aug 2008)

ein vollständiger ProgrammCode würde helfen, 
ControlVariables, PaintSurface  usw sind unbekannte Klassen,

wieso muss es eigentlich immer noch JApplet sein?
ich zumindest habe keine Lust, das jedesmal auf JFrame umzubiegen, damit es normale Menschen auch ausführen können.
falls ich helfen soll, musst du das auch noch machen


----------



## flashdog (26. Aug 2008)

Sorry für die fehlende Programm Teile. Ich würde es dir gerne JFrame umschreiben nur unter JFrame gibt es eine keine run Methode und ich weiss nicht wie man es ohne macht. Wahrschein ist es besser ohne die run Methode, da diese nur einmal gestartet werden kann. Könntest du mir trotzdem bitte Helfen?


```
public class ControlVariables {
  public int speed = 20;
  public Thread th;
  public boolean paused = false;
public boolean stop = false;
  public String teststring = null;
}
```


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import javax.swing.JComponent;

class PaintSurface extends JComponent {
  int ball1_x_pos = 0; // the starting X position
  int ball1_y_pos = 150; // the starting Y position
  int ball2_x_pos = 60; // the starting X position
  int ball2_y_pos = 150; // the starting Y position
 
  int d = 20; // the diameter of the ball

  @Override
  public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D)g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
        RenderingHints.VALUE_ANTIALIAS_ON);
    ball1_x_pos++; // move ball1 right one pixel
    ball2_x_pos--; // move ball1 left one pixel
    Shape ball1 = new Ellipse2D.Float(ball1_x_pos, ball1_y_pos, d, d);
    Shape ball2 = new Ellipse2D.Float(ball2_x_pos, ball2_y_pos, d, d);
    g2.setColor(Color.RED);
    g2.fill(ball1);
    g2.fill(ball2);
  }
}
```


----------



## SlaterB (26. Aug 2008)

sorry musst du nicht sagen, ich schreibe nur wie es ist, korrigieren und gut 

--------

also dann merke dir mal genau wie das mit dem JFrame hier aussieht, sind nur minimale Änderungen,
mit run-Methoden hat das nix zu tun:

```
public class Settings
    extends JFrame
    implements ActionListener
{
    private final int WIDTH = 350;
    private final int HEIGHT = 300;
    private JButton InitButton;
    private ControlVariables controlVariables;

    public Settings()
    {


        this.setSize(WIDTH, HEIGHT);
        controlVariables = new ControlVariables();
        System.out.print(controlVariables.speed);
        InitButton = new JButton("Init");
        InitButton.addActionListener(this);
        this.add(InitButton, BorderLayout.SOUTH);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
    }

    public void actionPerformed(ActionEvent e)
    {
        if (e.getSource() == InitButton)
        {
            Simulation dialog = new Simulation(this, "Simulations Fenster", true, controlVariables);
            dialog.setSize(500, 300);
            // dialog.pack();
            dialog.setResizable(false);
            dialog.setVisible(true);
        }

    }

    public static void main(String[] args)
    {
        new Settings();
    }
}
```

-------

das Problem ist, dass
controlVariables.th nur im ersten JDialog gesetzt wird,
danach wirds nie auf null gesetzt, der zweie JDialog macht nix,
außer 
a) auf sich selber dann notify aufzurufen, worauf der andere immer noch laufende Thread nicht reagiert, der wait()ed ja auf das erste Dialog-Objekt
b) pause = true/false wird gesetzt, darauf würde der erste Thread auch reagieren wenn er nicht per wait() ewig warten muss,


also:
unbedingt den ersten Thread beenden, sonst läuft der ewig nebenher weiter,
+ th auf null setzen,

du müsstest dafür auf das Schließen des JDialogs reagieren,
WindowListener hilft vielleicht


----------



## flashdog (26. Aug 2008)

Der WindowListener hielft, aber nur wenn ich zuerst auf den Pause Button klicke und dann auf schliesse. Wenn ich aber sofort auf schließe klicke läuft der Thread weiter. 

```
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import sun.awt.WindowClosingListener;

public class SimulationWindowNew extends JDialog implements ActionListener, ChangeListener, Runnable, WindowListener {
	private PaintSurface canvas;
	private JButton controlSimulation, stopSimulation;
	private JPanel controlPanel;
	private JLabel speedControlLabel;
	private JSlider speedControl;
        private ControlVariables controlVariables;

  public SimulationWindowNew(java.awt.Frame parent, String title, 
          boolean modal) {
    super(parent, title, modal);
    controlVariables = new ControlVariables();
    this.addWindowListener(this);
		canvas = new PaintSurface();
		getContentPane().add(canvas, BorderLayout.CENTER);
                controlSimulation = new JButton("Start");
		stopSimulation = new JButton("Stop");
		controlSimulation.addActionListener(this);
		stopSimulation.addActionListener(this);
		
		speedControlLabel = new JLabel("Speed:");
		
		speedControl = new JSlider(1,20,20);
		speedControl.addChangeListener(this);
		speedControl.setInverted(true); 
		controlPanel = new JPanel();
		controlPanel.add(controlSimulation);
		controlPanel.add(stopSimulation);
		controlPanel.add(speedControlLabel);
		controlPanel.add(speedControl);
              getContentPane().add(controlPanel, BorderLayout.SOUTH);
    
    }
  public void actionPerformed(ActionEvent e){
		if (e.getSource() == controlSimulation)
		{
			if (controlVariables.th == null)
			{
        System.out.println(controlVariables.teststring);
				controlVariables.stop = false;
				controlVariables.th = new Thread(this);
				controlVariables.th.start();
				controlSimulation.setText("Pause");
			}
			else // if (th != null)
			{
				synchronized (this)
				{
					if (controlVariables.paused)
					{
						controlVariables.paused = false;
						controlSimulation.setText("Pause");
						notify();
					}
					else
					{
						controlVariables.paused = true;
						controlSimulation.setText("Continue");
					}
				}
			}
		}
		if (e.getSource() == stopSimulation){
			if (controlVariables.th != null){
				controlVariables.stop = true;
				controlSimulation.setText("Start");
				System.out.print("Stop");
				controlVariables.th = null;
			}
		}
	}
  	@Override
	public void run() {
		while (!controlVariables.stop){
			repaint();
			try {
				System.out.println(controlVariables.speed);
				Thread.sleep(controlVariables.speed);
			}
			catch (InterruptedException ex)
			{
			}
			while (controlVariables.paused)
			{
				System.out.println("Displayer paused");
				synchronized (this)
				{
					try {
						wait();
					}
					catch (InterruptedException ex)
					{
						System.out.print("InterruptedException");
					}
				}
			}
			System.out.println("Displayer running");
		}
}
		@Override
		public void windowClosed(WindowEvent arg0) {
			// TODO Auto-generated method stub
		}
		@Override
		public void windowActivated(WindowEvent e) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void windowClosing(WindowEvent e) {
			System.out.print("windowClosing");
			controlVariables.th = null;
			
		}
		@Override
		public void windowDeactivated(WindowEvent e) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void windowDeiconified(WindowEvent e) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void windowIconified(WindowEvent e) {
			// TODO Auto-generated method stub
			
		}
		@Override
		public void windowOpened(WindowEvent e) {
			// TODO Auto-generated method stub
			
		}
}
```

Woran kann dies liegen?


----------



## flashdog (26. Aug 2008)

Danke es hat funktioniert ich habe nur vergessen "controlVariables.paused = true;" zu setzen.


----------



## SlaterB (26. Aug 2008)

> Woran kann dies liegen?

du setzt eine Variable auf null, na und? 
warum in alles in der Welt soll der Thread anhalten, nur weil du irgendwo irgendeine Variable setzt?

das interessiert den Thread nicht die Bohne,
selbst wenn der Pausen-Button geklickt ist würde der Thread so nicht beendet werden, sondern wartet bis in alle Ewigkeit

ein Thread ist beendet, wenn seine run-Methode ausgelaufen ist, schon mal davon gehört?
du hast sogar eine stop-Variable und eine gute Schleife
> while (!controlVariables.stop){ 
in dem Thread, willst du diese nicht nutzen?

hier noch eine Hilfe


```
public void run() { 
      while (!controlVariables.stop){ 
         .....
      } 
       System.out.println("Displayer macht Feierabend"); 
}
```
solange diese Meldung nicht kommt, bist du mit dieser Aufgabe noch nicht fertig

----

>  ich habe nur vergessen "controlVariables.paused = true;" zu setzen.

der Thread schläft dann, ist aber weiter vorhanden,
naja, damit kann man in einem einfachen Programm wohl auch leben


----------



## flashdog (26. Aug 2008)

Ich haette noch eine Frage, warum musst 6 weiter Methoden überschreiben. Gibt es noch eine andere Möglichkeit?


----------



## SlaterB (26. Aug 2008)

eine anonyme innere Klasse, die von WindowAdapter erbt,
dann sind alle Methoden des Interface schon implementiert,
musst nur noch die überschreiben, die zu brauchst,

zu anonymen inneren Klassen:
http://www.dpunkt.de/java/Die_Sprache_Java/Objektorientierte_Programmierung_mit_Java/64.html


----------



## flashdog (27. Aug 2008)

Danke fuer die Hilfe und den Link.


----------

