# Wie mehrere Grafiken auf JPanel anzeigen lassen? (Observer pattern?)



## Drizzit (20. Mai 2009)

Folgende Aufgabenstellung:
http://www.ifi.uzh.ch/rerg/fileadmi...tware_engineering_hs07/uebungen_se/seueb4.pdf


> Die gesamte Landkarte (bzw. ein eigens deﬁnierter Ausschnitt) soll graphisch angezeigt werden und es soll darauf ersichtlich sein wo sich zum aktuellen Zeitpunktwelche Tiere beﬁnden.
> Eine interaktive Steuerung der Simulationsgeschwindigkeit soll möglich sein, zum Beispiel
> 1er, 10er und 100er Schritte. Ausserdem soll ein konstanter Ablauf mit zum Beispiel 50 Schritten pro Sekunde möglich sein.



Es war also eine Konsolenanwendung gegeben und es muss dafür eine GUI erstellt werden, auf der die Tiere (als Kreise) angezeigt werden.
Ich hab es jetzt immerhin soweit geschafft, dass die Tiere mit der aktuellen Position im Panel angezeigt werden. Aber das immer nur für kurze Zeit. Sobald eine neue Iteration der Schleife folgt, verschwindet das jeweilige Tier und es wird nur noch das neue angezeigt.

Wie schaffe ich es, dass ALLE TIERE angezeigt werden und nicht nur das Tier, das gerade gezeichnet wird? Falls ein Tier seine Position wechselt bzw. stirbt, soll das natürlich auch angezeigt werden (Kreis wird verschoben / entfernt).
--> Unser Prof. erwähnte irgendwas von "Observer Pattern" implementieren, aber wie?!


```
public SavannahSim(int lions, int antilopes) {

		IO.writeLn("----------------------------------------------");
		IO.writeLn("Savannah Simulation, Version 0.9");
		IO.writeLn("Animals: Lions: " + lions + ", Antilopes: " + antilopes
				+ ".");
		IO.writeLn("----------------------------------------------");
		animal = new Animal[lions + antilopes];

		// creating lions and antilopes
		for (int i = 0; i < lions; i++) {
			animal[i] = new Lion(i + 1/* , s */);
		}
		for (int i = lions; i < (lions + antilopes); i++) {
			animal[i] = new Antilope(i + 1 - lions/* , s */);
		}

		UnserPanel p1 = new UnserPanel();

		new UnserFrame(p1);

		while (livingAnimals() > 1) {
			for (int i = 0; i < animal.length; i++) {

				// Verzoegern des Zeichnens um x ms
				long t0, t1;
				t0 = System.currentTimeMillis();
				do {
					t1 = System.currentTimeMillis();
				} while (t1 - t0 < 500);

				if (animal[i].isAnimalAlive()) {
					System.out.println(animal[i]);

					//Loewe oder Antilope einzeichnen
					p1.paint(p1.getGraphics(), animal[i]);

					animal[i].move();
				}
				for (int k = 0; k < animal.length; k++) {
					if (k != i && animal[i].isAnimalAlive()
							&& animal[k].isAnimalAlive()
							&& animal[i].isNear(animal[k])) {

						p1.paint(p1.getGraphics(), animal[k]);

						System.out.println(animal[i] + " Meets " + animal[k]);
						animal[i].meet(animal[k]);
						System.out.println("Result: " + animal[i] + ", "
								+ animal[k]);
					}
				}
			}
			iterations++;
			
		}
```

Bin für jeden Tipp dankbar!


----------



## Schandro (20. Mai 2009)

> p1.getGraphics()


Die goldenen Regeln dieses Forums:

1.) Strings vergleicht man mit equals()

2.) *NIEMALS* getGraphics() auf ein Component zum zeichnen aufrufen!

und ein paar weitere^^

Hier mal ein Beispielcode wie man normalerweise zeichnet:

```
public class XXX{
 
    public static void main(String[] args){
        new XXX();}
 
 
    private JFrame window = new JFrame();
    private int cnt = 50;
 
    public XXX(){
        window.setBounds(100,100,290,150);
 
        window.add(panel);
 
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                window.setVisible(true);
            }
        });
 
        Thread myThread = new Thread(new Runnable(){
            public void run(){
                while(true){
                    try{Thread.sleep(20);}catch(Exception e){e.printStackTrace();}
                    ++cnt;
                    if(cnt > 200){
                        cnt = 50;
                    }
                    panel.repaint();
                }
            }
        });
        myThread.start();
    }
 
 
    JPanel panel = new JPanel(){
        public void paintComponent(Graphics g){
            super.paintComponent(g);
            g.drawRect(cnt,50,30,20);
        }
    };
 
}
```
Es wird immer alles innerhalb der paintComponent Methode gezeichnet (man kann einzelne Sachen natürlich in Methoden auslagern, diese dürfen dann aber nur von paintComponent aus aufgerufen werden).
Durch Membervariablen kann man "von außen" paintComponent sagen was es zeichnen soll.
Solange man den repaint() Aufruf ohne Parameter benutzt muss man immer die komplette Zeichenfläche neu malen, bei jedem Aufruf von paintComponent .


----------



## Drizzit (20. Mai 2009)

Ok. Danke schonmal!

Aber wie wende ich das dann an?
Einfach:

```
XXX x = new XXX();
```
in meiner main und dann x.paintComponent(); ??

Und wie übergebe ich paintComponent ein Objekt, damit ich Zugriff auf die Koordinaten + Objekttyp habe?


```
public void paintComponent(Graphics g, Animal a) {
			super.paintComponent(g);
			if(a.getSpecies().equals("Lion")){
				g.setColor(Color.red);		
			}
			if(a.getSpecies().equals("Antilope")){
				g.setColor(Color.green);
			}

			g.fillOval(a.coord.getX(), a.coord.getY(), 10, 10);
		}
```
So? Eher nicht, oder? ^^

Bin mit GUI Programmierung im moment bissl überfordert, wie man sicher merkt.


----------



## Schandro (20. Mai 2009)

Eben nicht!

1.) Du rufst niemals selber paintComponent auf! Das Swing-Framework ruft es für dich auf wenn es das für notwendig hält oder wenn du es darum bittest:
panel.repaint()

2.) Du kannst paintComponent keine Variablen übergeben. Deswegen muss man den Umweg über Membervariablen benutzen. Guck dir einfach nochmal meinen Beispielcode an, die einzige Membervariable die zur Kommunikation mit paintComponent dient ist bei meinem Code "cnt". Man kann aber natürlich beliebig viele Membervariablen beliebiger Typen dafür einsetzen.


Übrigens benutz ich dieses XXX als Klassennamen nur in Beispielcodes, in richtigen Codes sollte man natürlich passendere Namen benutzen^^


----------



## Drizzit (20. Mai 2009)

Schandro hat gesagt.:


> Übrigens benutz ich dieses XXX als Klassennamen nur in Beispielcodes, in richtigen Codes sollte man natürlich passendere Namen benutzen^^


Das ist das einzige, was ich an deinem Beispiel bisher verstanden habe. ^^

Also ich hab wohl gerade den totalen Hänger..... werd den Kram jetzt erstmal über Nacht ruhen lassen, vielleicht hab ich morgen 'nen Geistesblitz :autsch:


----------



## Dragonfire (20. Mai 2009)

Das mit der Nacht kenne ich xD
Ich hab auch ein wenig länger gebraucht um das zu verstehen,
das hier hat mir aber geholfen:

http://www.java-forum.org/awt-swing-swt/43939-zeichnen-schnittstelle-fuer-gui-programmierung-tutorial.html#post272862


----------



## André Uhres (21. Mai 2009)

Drizzit hat gesagt.:


> Das ist das einzige, was ich an deinem Beispiel bisher verstanden habe.


Dieser Artikel erklärt den Gebrauch der Methoden "paintComponent" und "repaint" in einer Swing Anwendung: 
Malen in Swing Teil 1: der grundlegende Mechanismus - Byte-Welt Wiki


----------



## Drizzit (21. Mai 2009)

André Uhres hat gesagt.:


> Dieser Artikel erklärt den Gebrauch der Methoden "paintComponent" und "repaint" in einer Swing Anwendung:
> Malen in Swing Teil 1: der grundlegende Mechanismus - Byte-Welt Wiki


Dankeschön!
Zumindest die Component hab ich in etwa genauso hinbekommen wie im Beispiel auf der Seite. 

Habe jetzt aber noch einige Fragen, vor allem dieses "runnable" irritiert mich dann doch...konnte es jedenfalls nicht zum Laufen bringen, als ich versucht habe es in mein Programm mit einzubauen.

Meine SavannahSim sieht momentan so aus (was ich selbst geschrieben habe, ist mit einem Kommentar versehen):

```
package simulation;

import javax.swing.*;

/**
 * The class SavannahSim handles the execution parameters, does the savannah
 * simulation and also offers methods to count the number of antilopes and lions
 * alive.
 * 
 * @author Projektarbeit
 * @copyright Systems Simulation Inc. 2009
 * @history 2009-03-01 CC built the application. 2009-03-10 CC documentations
 *          and review.
 * @version 2009-05-13 CC v1.0
 * 
 * @responsibilities CC
 * @see simulation.Animal
 * @see simulation.Antilope
 * @see simulation.Lion
 */

public class SavannahSim {

	private Animal[] animal;

	private int iterations = 0;

	public static void main(String[] args) {
		// also hand-over of two parameters when executing e.g. "java
		// SavannahSim 2 4", meaning: 2 Lions and 4 Antilopes.
		new SavannahSim(Integer.parseInt(args[0]), Integer.parseInt(args[1]));
	}

	/**
	 * Creates all the animals, lets the animals randomly meet each other until
	 * there is a winner, outputs all animals status.
	 * 
	 * @pre lions != null && antilopes != null;
	 * @post
	 * @param lions
	 *            The number of lions.
	 * @param antilopes
	 *            The numer of antilopes.
	 */
	public SavannahSim(int lions, int antilopes) {

		IO.writeLn("----------------------------------------------");
		IO.writeLn("Savannah Simulation, Version 0.9");
		IO.writeLn("Animals: Lions: " + lions + ", Antilopes: " + antilopes
				+ ".");
		IO.writeLn("----------------------------------------------");
		animal = new Animal[lions + antilopes];

		// creating lions and antilopes
		for (int i = 0; i < lions; i++) {
			animal[i] = new Lion(i + 1/* , s */);
		}
		for (int i = lions; i < (lions + antilopes); i++) {
			animal[i] = new Antilope(i + 1 - lions/* , s */);
		}
		
		/* VON MIR EINGEFUEGT - ANFANG*/
		JFrame f = new JFrame("Savannah Simulation 2009");
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		Savannah savannah = new Savannah();
		
		f.setSize(400,400);
		f.add(savannah);
		f.setVisible(true);
		/* VON MIR EINGEFUEGT - ENDE*/

		while (livingAnimals() > 1) {
			for (int i = 0; i < animal.length; i++) {

				/* VON MIR EINGEFUEGT - ANFANG*/
				long t0, t1;
				t0 = System.currentTimeMillis();
				do {
					t1 = System.currentTimeMillis();
				} while (t1 - t0 < 500);
				/* VON MIR EINGEFUEGT - ENDE*/

				if (animal[i].isAnimalAlive()) {
					System.out.println(animal[i]);

					/* VON MIR EINGEFUEGT - ANFANG*/
					savannah.setAnimal(animal[i]);
					savannah.repaint();
					/* VON MIR EINGEFUEGT - ENDE*/
					
					animal[i].move();
				}
				for (int k = 0; k < animal.length; k++) {
					if (k != i && animal[i].isAnimalAlive()
							&& animal[k].isAnimalAlive()
							&& animal[i].isNear(animal[k])) {

						System.out.println(animal[i] + " Meets " + animal[k]);
						animal[i].meet(animal[k]);
						System.out.println("Result: " + animal[i] + ", "
								+ animal[k]);
					}
				}
			}
			iterations++;
			
		}

		// simulation as long there isn't a winner.

		// print the results
		IO.writeLn("----------------------------------------------");
		IO.writeLn("All animals, status:");
		IO.writeLn("----------------------------------------------");
		for (int i = 0; i < lions + antilopes; i++) {
			IO.writeLn(animal[i].toString());
		}
		IO.writeLn("Number of iterations: " + iterations); // program execution
															// is done after
															// that.
	}

	public int livingAnimals() {
		int living = 0;
		for (int i = 0; i < animal.length; i++) {
			if (animal[i].isAnimalAlive()) {
				living++;
			}
		}
		return living;
	}

} // class SavannahSim
```

Wie kann ich hier dieses run() einbauen? In die main? Aber wie füge ich dann die Component in den Frame ein?
Meine einzige Idee dazu wäre einfach eine Savannah-Klassenvariable zu erstellen und diese dann in der main zu initialisieren.

Eigentlich bin ich ja jetzt genauso weit wie am Anfang, nur dass es diesmal halbwegs schön programmiert wurde. 
Das Problem mit dem "Verschwinden" der einzelnen Punkte ist damit ja auch noch nicht aus der Welt geschafft....


EDIT
--> jetzt hab ich endlich repaint(x,y,size,size) kapiert...
aber irgendwie wills doch nicht so ganz..
habe eben einfach nur zum Testen folgendes geschrieben (alle tiere anzeigen):

```
for(Animal a : animal){
			savannah.setAnimal(a);
			savannah.repaint(a.coord.getX()*20,a.coord.getY()*20,10,10);
		}
```
hier wird am Ende aber nur ein einziges Tier angezeigt. Sobald ich aber eine Verzögerung einbaue:

```
for(Animal a : animal){
			savannah.setAnimal(a);
			savannah.repaint(a.coord.getX()*20,a.coord.getY()*20,10,10);

			long t0, t1;
			t0 = System.currentTimeMillis();
			do {
				t1 = System.currentTimeMillis();
			} while (t1 - t0 < 500);
		}
```
funktioniert es ohne Probleme! Wie kann das sein? ???:L


----------



## Dragonfire (21. Mai 2009)

"Runnable" ist ein Java Interface. Wenn man einen neuen Thread erstellt, kann man dem Konstruktor ein Object von Runnable mitgeben damit der Thread etwas hat was er ausführen kann.
=> Runnable wird "passiv" benutzt.

Threads sind eigentlich schon ein eigenes Thema ^^

Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 11 Threads und nebenläufige Programmierung

hier direkt ein paar Infos:

Galileo Computing :: Java ist auch eine Insel (8. Auflage) – 11.2 Threads erzeugen

oder:

Processes and Threads (The Java™ Tutorials > Essential Classes > Concurrency)


PS.: Neue Threads sind manchmal vonnöten,
damit die GUI, genau der The Event Dispatch Thread
(The Event Dispatch Thread (The Java™ Tutorials > Creating a GUI with JFC/Swing > Concurrency in Swing)) nicht blockiert.

Klassisch Beispiel sind Ladevorgänge.
Das Programm lädt etwas aus einer Datenbank
und das dauert ein bisschen,
(das Netzwerk ist ja ein Flaschenhals)
deswegen hat man einen Ladebalken mit Abbrechen Button.
Würde die Daten im selben Thread geladen werden,
dann würde der Fortschirtt/Ladebalken nicht nur bei 0% stehen bleiben,
sondern die GUI, vor allem der Abbrechen Button würde blockiert werden,
sodass der Benutzer den ganzen Vorgang nicht abbrechen kann
(typischer Freeze, Fenster ist eingefroren^^).


----------



## Schandro (21. Mai 2009)

> "runnable" ist in Java ein Interface und für die Erzeugung eines neuen Threads zuständig


Nur ne kleine Korrektur, so wäre der Satz richtig:
"Runnable" ist ein Java Interface. Wenn man einen neuen Thread erstellt, kann man dem Konstruktor ein Object von Runnable mitgeben damit der Thread etwas hat was er ausführen kann.
=> Runnable wird "passiv" benutzt.


----------



## Dragonfire (21. Mai 2009)

Verbessert ^^
Gut das ich nicht mehr falsch habe 
(oder ich hoffe es)

So sieht das dann in Quellcode aus:


```
Thread t = new Thread( new ObjectImplementsRunnable() ); 
t.start();
```

der Autor von Byte-Welt Wiki hat gleich eine anonyme innere Klasse für das Object genommen,
dass Runnable implementiert.
Ich glaube das verwirrt schnell.


----------



## Drizzit (21. Mai 2009)

So!
Habe es jetzt mittlerweile so einigermaßen hinbekommen, dass die Tiere richtig gezeichnet werden.
Jetzt folgt aber schon das nächste Problem....ich hab keine Ahnung wie ich es schaffe, dass das Programm erst nach einem Klick auf einen Button startet.

Habe vorhin schonmal einen Versuch gestartet, der aber kläglich gescheitert ist. (Konsole rattert munter vor sich hin, auf der GUI aber tut sich nix :bahnhof: )

Wäre super wenn sich jemand erbarmt und kurz mal über das Projekt drüberschauen könnte.  :rtfm:


----------



## Dragonfire (21. Mai 2009)

Du musst auf den Button ein ActionListener setzten:

How to Write an Action Listener (The Java™ Tutorials > Creating a GUI with JFC/Swing > Writing Event Listeners)

Würde ungefähr so aussehen,
wenn du eine "innere anonyme Klasse" benutzen würdest:

```
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

...

JButton start = new JButton("Start");
start.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        //Simulation starten
    }
});
frame.add(start, BorderLayout.SOUTH);
...
```


----------



## Drizzit (21. Mai 2009)

genau das habe ich vorhin schon probiert. dann läuft zwar die simulation, aber auf der gui wird nix angezeigt! ;(


----------



## André Uhres (21. Mai 2009)

Einen zusätzlichen Thread (Runnable) brauchst du in deinem konkreten Fall nicht direkt, denn du hast schon zwei Threads, ohne es zu wissen: den InitialThread und den EventDispatchThread. Eine Simulation braucht immer eine Verzögerung, sonst läuft alles innerhalb weniger Mirkosekunden ab und ist mit dem menschlichen Auge nicht mehr nachzuvollziehen.

EDIT: Upps, sorry da hab ich wohl einige Beiträge verpasst!


----------



## Dragonfire (21. Mai 2009)

Also ich vermute mal ein Thread Problem
und bei mir läuftst auch.

Soweit wie ich das gesehen habe,
blockiert das Event vom Button dann alle Zeichenvorgänge
(Fenster ist eingefroren).

Deswegen hab ich jetzt erstmal alle Berechnung und Zeichenvorgänge in einen
neuen Thread gepackt:


```
final JButton start = new JButton("Start");
start.addActionListener(new ActionListener()
{
    public void actionPerformed(ActionEvent e)
    {
        start.setEnabled(false);
        new Thread()
        {
            public void run()
            {
                //Starte Sim (keine Parameter übergeben noch abfangen)
                new SavannahSim(2,2);
            }
        }.start();
    }
});
frame.add(start, BorderLayout.SOUTH);
```


Hier zum Nachlesen:

Lesson: Concurrency in Swing (The Java™ Tutorials > Creating a GUI with JFC/Swing)

PS.: Unbedingt den Button deaktivieren,
sonst wird beim erneuten Klicken eine neue Sim gestartet
(sieht lustig aus,
vor allem auf der Konsole^^)

EDIT:Ich bin verwirrt^^ Gibts es eine Lösung ohne neuen Thread oO ? Eigentlich ja schon, den der Intial Frame müsste ja frei sein,
aber er will ja Zeichen ... Hier muss mal ein Experte genauer schauen


----------



## Drizzit (21. Mai 2009)

@Dragonfire
Dankeschön!
Immerhin geht jetzt was, das ist doch schonmal 1000x besser als garnix!  Und dass man extra einen neuen Thread machen muss ist ja nun auch nicht soooooo tragisch.

So.....und jetzt gehts auf zum letzten Punkt der Aufgabenstellung.


> Eine interaktive Steuerung der Simulationsgeschwindigkeit soll möglich sein, zum Beispiel
> 1er, 10er und 100er Schritte. Ausserdem soll ein konstanter Ablauf mit zum Beispiel 50 Schritten pro Sekunde möglich sein.


*Radio Buttons reinfrickeln geh* :-D


----------



## Dragonfire (21. Mai 2009)

Richtige Idee,
hier zum Nachlesen:

1. How to Use Buttons, Check Boxes, and Radio Buttons (The Java™ Tutorials > Creating a GUI with JFC/Swing > Using Swing Components)

2. How to Use Spinners (The Java™ Tutorials > Creating a GUI with JFC/Swing > Using Swing Components)

3. How to Use Sliders (The Java™ Tutorials > Creating a GUI with JFC/Swing > Using Swing Components)


----------



## André Uhres (22. Mai 2009)

Dragonfire hat gesagt.:


> Gibt es eine Lösung ohne neuen Thread oO ?


Am Anfang schon. "repaint" läuft ja eh auf dem EDT, also könnte die Simulation durchaus auf dem IT laufen. Ob das sinnvoll ist, sei dahingestellt. Falls wir die Simulation z.B. stoppen und neu starten wollen, steht der IT nicht mehr zur Verfügung.


----------



## Dragonfire (22. Mai 2009)

André Uhres hat gesagt.:


> Am Anfang schon. "repaint" läuft ja eh auf dem EDT, also könnte die Simulation durchaus auf dem IT laufen. Ob das sinnvoll ist, sei dahingestellt. Falls wir die Simulation z.B. stoppen und neu starten wollen, steht der IT nicht mehr zur Verfügung.



Ich Frage sicherheitshalber nochmal nach:


Ohne Startbutton läuft die Simulation im IT.

Wenn der Startbutton erzeugt wird,
dann ist der IT schon beendet,
deswegen muss ein neues Thread erzeugt werden?


----------



## Drizzit (22. Mai 2009)

Jawoll!! Es funktioniert jetzt alles so wie es soll!
(zumindest dachte ich das noch vor wenigen Minuten ^^)

Es ist jetzt eigentlich alles fertig, aber ich habs eben einem Kumpel zum Testen geschickt. Das war seine Antwort:


> ist das nur bei mir so???
> 
> Als ich die .jar geöffnet habe, konnte ich den Button und die DropDown-liste nicht sehen. Musste erst die Größe des Fensters anpassen (Untere 'ecke' ziehen).


;(

Woran liegt das denn nun wieder? Bei mir öffnet sich das Fenster in der richtigen Größe!


```
// Frame und GUI
		JFrame frame = new JFrame("Savannah Simulation 2009");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLayout(new BorderLayout());
		gui.setPreferredSize(new Dimension(340, 380));
		gui.setBackgroundImage(); // Hintergrundbild
		frame.add(gui, BorderLayout.CENTER);
		frame.pack();
		frame.setVisible(true);
		frame.setLocationRelativeTo(null);

		// ComboBox mit verschiedenen Verzoegerungen zur Auswahl
		String[] delays = { "kein Delay", "empfohlen (100ms)",
				"mittleres Delay (500 ms)", "starkes Delay (1 Sekunde)" };
		final JComboBox delay = new JComboBox(delays);

		// Startbutton mit ActionListener
		final JButton start = new JButton("Start");

		// Panel fuer Start-Button und ComboBox
		JPanel controls = new JPanel();
		controls.setLayout(new FlowLayout());
		controls.add(delay);
		controls.add(start);

		start.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				// Start-Button wird waehrend der Simulation gesperrt
				start.setEnabled(false);

				// Setzen der Verzoegerung (Nach Auswahl in ComboBox)
				int s = delay.getSelectedIndex();
				switch (s) {
				case 0:
					sleep = 0;
					break;
				case 1:
					sleep = 100;
					break;
				case 2:
					sleep = 500;
					break;
				case 3:
					sleep = 1000;
					break;
				}
				new Thread() {
					public void run() {
						if (args.length == 0) {
							// Wenn keine Parameter angegeben wurden: 4 Loewen, 4 Antilopen
							new SavannahSim(4, 4);
							// Nach der Simulation wird der Start-Button wieder freigegeben
							start.setEnabled(true);
						} else {
							// Simulation mit uebergebenen Parametern starten
							new SavannahSim(Integer.parseInt(args[0]), Integer
									.parseInt(args[1]));
							// Nach der Simulation wird der Start-Button wieder freigegeben
							start.setEnabled(true);
						}
					}
				}.start();
			}
		});
		frame.add(controls, BorderLayout.SOUTH);

	}
```


----------



## Dragonfire (22. Mai 2009)

Spontan würde ich sagen,
da fehlt irgendwo zum Schluss ein 

repaint()

oder 

doLayout()


Eins funktioniert auch noch nicht so ganz wie es soll,
dass Hintergrundbild wird nicht angezeigt.
Ich habe gelernt es über die Klasse javax.imageio.ImageIO
zu machen:

Reading/Loading an Image (The Java™ Tutorials > 2D Graphics > Working with Images)


----------



## Schandro (22. Mai 2009)

du solltest JFrame#setVisible immer als letztes aufrufen. Zurzeit addest du noch Componenten nachdem du pack und setVisible aufgerufen hast...


----------



## Drizzit (22. Mai 2009)

@Dragonfire
hab vergessen das hintergrundbild mit hochzuladen --> muss ja immer im selben ordner sein. dann gehts

@Schandro
jo das hab ich gerade gemacht ^^ thx

jetzt wollte ich gerade noch "frame.setResizable(false)" einbauen....aber dann kommt rechts plötzlich noch ein grauer rand zum vorschein

edit:

```
...
		frame.add(controls, BorderLayout.SOUTH);
		frame.setResizable(false);
		frame.pack();
		frame.setVisible(true);
		frame.setLocationRelativeTo(null);
	}
```
hah! so gehts jetzt


----------



## André Uhres (23. Mai 2009)

Dragonfire hat gesagt.:


> Ich Frage sicherheitshalber nochmal nach:
> Ohne Startbutton läuft die Simulation im IT.
> Wenn der Startbutton erzeugt wird,
> dann ist der IT schon beendet,
> deswegen muss ein neues Thread erzeugt werden?


Der IT ist beendet, wenn die main beendet ist. Wenn wir auf einen Button klicken, sind wir automatisch auf dem EDT. Da wir den EDT nicht für die Simulation benutzen können, müssen wir einen neuen Thread erzeugen.


----------

