# Strings an Textarea anderer Klasse append(en)



## Azu (30. Nov 2008)

Hallöle!

Ich bin noch relativ neu auf dem Gebiet Java und habe nun seit 2 Tagen das Problem dass ich nicht weiß,  wie ich gewisse Strings in eine Textarea anderer Klasse append(en) kann.

Generell läuft das ganze etwa so ab:
------------------------------------------

Klasse "Main" macht Klasse "Aktion" sichtbar und startet damit einen Thread.

in "Main":

```
Aktion akti = new Aktion();
akti.thr.start();
```

in "Aktion":

```
Thread thr = null;
	
public Aktion() {
     this.thr = new Thread(this);
}
```

In diesem Thread werden nun nach bestimmten Kriterien Strings erzeugt.


```
private String results = null;
```

wird somit (während eine while-Schleife läuft) mit diversen Strings überschrieben.

z.B.

```
results = "Dieses ist Durchgang 1";
```

Soweit so gut. Die Ausgabe in der Konsole läuft einwandfrei.

Nun übergebe ich die generierten Strings an die Klasse "Main":

Ich gebe der Klasse "Aktion" eine Instanz der Klasse "Main" um sie miteinander bekannt zu machen und lege die String-Variable vor.


```
private String result = null;
private Main haupt = new Main();
```

und gebe der "Main"-Klasse eine String-Variable, getter- und setter-Methoden für die Resultate und eine Textarea als Ausgabeziel.


```
private String results = null;
private JTextArea jtaAusgabe = new JTextArea("Resultate: \n\n",5,20);

public String getResults() {
     return this.results;
}

public void setResults(String res) {
     this.results = res;
     this.jtaAusgabe.append(this.results);
}
```

Schlussendlich rufe ich die setter in der actionPerformed der "Aktion" auf um mit jedem Durchgang Strings an Klasse "Main" zu senden


```
haupt.setResults(result);
```

Ich bekomme keine Ausgabe. Alles was die Textarea anzeigt ist der vorgegebene Text. Und der einzige Ort der mir meine Resultate ausgibt, ist die Konsole. Langsam werd ich blind für eigene, weitere Ideen :autsch: und vermute, dass ich dem Wald den ich suche nur mit den Rücken zukehre...

Hoffentlich werdet ihr aus meinem Text hier klar. Wenn nicht, bitte sagen ^^

Freu mich auf eure Ideen/Antworten.


Ich hau mich nu hin.

LG, Azu


----------



## SlaterB (30. Nov 2008)

wahrscheinlich ist
private Main haupt = new Main();
ein anders Main-Objekt, als das welches du visuell wahrnimmst,

suche deinen gesamten Quellcode nach noch einer Codestelle "new Main()" ab,
wenn du zwei hast, dann ist das eine zuviel,
dann musst du wahrscheinlich dem Aktions-Thread das Main-Objekt als Parameter mit übergeben


----------



## André Uhres (30. Nov 2008)

Als Alternative hier mal eine mögliche Implementation nach dem MVC Prinzip:
Wir können einen Controller bauen, der alles überwacht (das Datenmodell, die GUI und den Thread):

```
public class Controller {
    private Aktion frame;
    private Model model;
    public Controller(final Model model, final Aktion frame) {
        this.frame = frame;
        this.model = model;
        new MeinThread(this).start();
    }
    public void setResults(final String str) {
        model.setText(str);
        frame.setResults(model.getText());
    }
}
```
Den Thread können wir so implementieren:

```
public class MeinThread extends Thread {
    private Controller controller;
    public MeinThread(final Controller controller) {
        this.controller = controller;
    }
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(300);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
            controller.setResults("Test " + i);

        }
    }
}
```
Das Datenmodell:

```
public class Model {
    private String text;
    public String getText() {
        return text;
    }
    public void setText(final String text) {
        this.text = text;
    }
}
```
Die GUI:

```
import java.awt.*;
import javax.swing.*;
public class Aktion extends JFrame {
    private JTextArea jTextArea1;
    public Aktion() {
        super("Aktion");
    }
    private void initComponents() {
        jTextArea1 = new JTextArea();
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        getContentPane().add(new JScrollPane(jTextArea1), BorderLayout.CENTER);
        setSize(400, 300);
        setLocationRelativeTo(null);
    }
    void createAndShowGui() {
        Runnable gui = new Runnable() {
            public void run() {
                initComponents();
                setVisible(true);
            }
        };
        //GUI must start on EventDispatchThread:
        SwingUtilities.invokeLater(gui);
    }
    public void setResults(final String str) {
        jTextArea1.append(str + "\n");
    }
}
```
Und schliesslich die Main-Klasse:

```
public class Main {
    private Aktion frame;
    private Model model;
    private Controller controller;
    public Main() {
        model = new Model();
        frame = new Aktion();
        controller = new Controller(model, frame);
    }
    public static void main(final String[] args) {
        new Main().frame.createAndShowGui();
    }
}
```


----------



## Guest (30. Nov 2008)

Hallo,

erstmal vielen Dank für die prompten Antworten. Bin begeistert! =)

@ André

In deinem Vorschlag ist die Klasse Aktion für die GUI zuständig und die Main für die Abarbeitung, bzw. den Aufruf von GUI, Abarbeitung und Kontrolle - richtig? In meiner bisherigen Struktur ist allerdings die Main für die GUI allein zuständig und die Aktion eben für die Aktionen.

Ich werde aber mal versuchen dein Beispiel zu integrieren, bzw. mein Projekt entsprechend umzuschreiben.

@ SlaterB

Nein, es existiert keine 2. new Main();

Vielen Dank erstmal an dieser Stelle an euch beide! 


LG Azu


----------



## Azu (30. Nov 2008)

Gast = Azu  :roll:


----------



## Azu (30. Nov 2008)

Ich versuche doch mal den Quelltext zu posten - oder zumindest die wichtigen Snippets.

Ich habe 2 Methoden die hier wichtig sind (momentan):

1. Spiel (für die komplette GUI, hier vorher Main genannt)
2. Battle (für die Aktionen, hier vorher Aktion genannt)

Die Klasse Spiel:


```
import ...;

@SuppressWarnings("serial")
public class Spiel extends JFrame {

        ...

	// Kampfergebnisse
	private String results = null;
	private JTextArea jtaBattle = new JTextArea("Kampfresultate: \n\n",5,20);

        ...

	// Kampfergebnisse
	public String getResults()
	{
		return this.results;
	}	
	// Kampfergebnisse in Textarea einfügen
	public void setResults(String res)
	{
		this.results = res;
		this.jtaBattle.append(this.results);
	}	

	public Spiel() {
		super("Titel");
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		// Größe und Position festlegen
		Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
		setBounds(screen.width / 2 - 400, screen.height / 2 - 300, 800, 600);
		setContentPane(new GameBG("layout/game.png"));
		Container con = getContentPane();
		con.setLayout(null);

		// Fensterrahmen weg, Resize verbieten
		this.setUndecorated(true);
		this.setResizable(false);

		// Label für Kampfergebnisse
		jtaBattle.setForeground(Color.BLACK);
		jtaBattle.setBackground(new Color(245, 233, 192));
		jtaBattle.setBorder(BorderFactory.createLineBorder(Color.BLACK));
		jtaBattle.setFont(new Font("Tahoma", Font.PLAIN, 12));
		jtaBattle.setBounds(200, 100, 400, 400);
		jtaBattle.setVisible(false);
		con.add(jtaBattle);
		
                ...
	}

	// Klasse für JFrame-Hintergrund
	class GameBG extends JPanel {
		Image bgimg = null;

		public GameBG(String imgpath) {
			if (imgpath != null) {
				MediaTracker mt = new MediaTracker(this);
				bgimg = Toolkit.getDefaultToolkit().getImage(imgpath);
				mt.addImage(bgimg, 0);
				try {
					mt.waitForAll();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

		protected void paintComponent(Graphics gr) {
			super.paintComponent(gr);
			gr.drawImage(bgimg, 0, 0, this.getWidth(), this.getHeight(), this);
		}
	}

	// Klasse für Auswahl-Buttons
	public class ImgBtns extends JButton implements ActionListener {

		public ImgBtns(String path, int x, int y, int width, int height,
				Border border) {
                       ...
		}

		@Override
		public void actionPerformed(ActionEvent e) {

			// Instanz der run Methode Battle
			Battle btl = new Battle(getPlayer(),getOpponent());

			if (...) {
                                ...
			} else if (...) {
                                ...
			} else if (e.getSource().equals(btnAccept)) {
                                ...
					// Kampf einleiten!
					btl.t.start();
                                        // Textarea für Resultate sichtbar machen
					jtaBattle.setVisible(true);
					jtaBattle.setEditable(false);
				} else {
					JOptionPane.showMessageDialog(null,"keine Auswahl");
				}
			}
		}
	}

	public static void main(String[] args) {
		new Spiel().setVisible(true);
	}
}
```


----------



## Azu (30. Nov 2008)

Die Klasse Battle:


```
import ...;

public class Battle implements Runnable {

	Spiel game = new Spiel();
	String result = null;

        ...

	Thread t = null;
	
	public Battle() {
		this.t = new Thread(this);
	}

	public Battle(String player1, String player2) {
		this.player1 = player1;
		this.player2 = player2;
		this.t = new Thread(this);
	}

        ...

	public void run() {

               ...

		while (this.bedingung1 > 0 && this.bedingung2 > 0 && !this.t.isInterrupted()) {

                        ...

			if (...) {
                                ...

			} else {
                                ...

			}
                                // Ausgabe an Klasse Spiel übergeben
				game.setResults(result);

                        // Andere Ausgabe hier (Ergebnisse am Ende)
			if (...) {

                                ...

				// Ausgabe an Klasse Spiel senden
				game.setResults(result);
				// Thread hier beenden!
				this.t.interrupt();
			} else if (...) {

                                ...

				// Ausgabe an Klasse Spiel senden
				game.setResults(result);
				// Thread hier beenden!
				this.t.interrupt();
			}
		}
	}
}
```


----------



## André Uhres (30. Nov 2008)

Anonymous hat gesagt.:
			
		

> In deinem Vorschlag ist die Klasse Aktion für die GUI zuständig


Das war wohl ein Missverständis, weil du davon gesprochen hast, daß die Klasse Aktion "sichtbar" gemacht wird.
Aber egal, ich wollte ja auch nur das MVC Prinzip verdeutlichen, da tun die Klassennamen nix zur Sache.
Was ich eigentlich zeigen wollte:
wir machen eine Modelklasse für die Daten,
eine Viewklasse für die Guikomponenten,
eine Controllerklasse für die Listener/Kontrollfunktionen und eine Initialisierungsklasse 
um die drei zu instanzieren. Da diese auch miteinander sprechen
müssen, sorgt die Initialisierungsklasse ebenfalls für die nötigen Bekanntschaften,
z.B. bekommt der Controller eine Referenz zu Model und View..

Aber das, was SlaterB sagte, sollten wir wirklich ernst nehmen. Es ist nämlich ein häufiger Fehler, 
daß man die gleiche Klasse ungewollt zweimal instanziert und sich dann wundert, 
daß die erste Instanz nicht richtig reagiert.


----------



## Azu (30. Nov 2008)

Kein Problem.

Danke nochmal für die Hilfestellung. Ich werd dann mal versuchen, deinen Vorschlag für mein Projekt umzusetzen.

P.S.: Ich sehe nichts was darauf hinweist, dass ich die Klasse Spiel zweimal instanziiere... Vielleicht bin ich aber auch nur blind. =/ Auf jeden Fall weiß ich jeden Hinweis und Rat wirklich zu schätzen 

--------

@ SlaterB: Vielen Dank für den Tipp!
@ André: Vielen Dank für das Beharren darauf, SlaterB's Hinweis ernst zu nehmen ^^

Es läuft nun einwandfrei. Nachdem ich dem "Aufruf der Methode "Aktion" die Klasse "Main" als Parameter mitgegeben habe". Vielen vielen Dank!!! =D


----------



## SlaterB (30. Nov 2008)

wie kann denn hier noch eine Diskussion sein, ob Spiel/ Main einmal oder zweimal erzeugt wurde,
ist doch deutlich zu sehen:

> public static void main(String[] args) {
>      new Spiel().setVisible(true);
>   } 


+

> public class Battle implements Runnable {
>
>   Spiel game = new Spiel();
>   String result = null; 


ich hole meinen Taschenrechner raus, 1 + 1, hmm ja, ne, doch, gleich 2!

> Nachdem ich dem "Aufruf der Methode "Aktion" die Klasse "Main" als Parameter mitgegeben habe".

genau, viel besser,
ob nun nach MVC oder einfach ist ja erstmal egal, nur nicht zwei unterschiedliche Spiel/ Main


----------



## Azu (30. Nov 2008)

Diskussion? Lies doch mal meinen letzen Beitrag ...  :gaen:

Ist doch nun alles geklärt - dank dir und André.


----------



## André Uhres (30. Nov 2008)

Sorry, ich hatte die Klassen Spiel und Battle gar nicht angeschaut.
Jetzt seh ich's auch, sogar ohne Brille.
Es musste ja auch so sein, darum hab ich den Hinweis bekräftigt.
Der Fehler kann einem selbstverständlich mit oder ohne MVC unterlaufen.
Ich dachte nur, MVC wäre eine bessere Struktur für diese Anwendung.


----------



## Azu (30. Nov 2008)

Sagen wirs mal so:

Ihr habt mir beide sehr geholfen und die MVC-Struktur interessiert mich =)


----------

