Threads Paint Multiple Objects

Leo123

Mitglied
Hallöchen,
wir haben in der Uni als Aufgabe bekommen, eine kleine Simulation zu schreiben.
Ich werde jetzt nicht auf das Spielprinzip eingehen, da dies für mich eigentlich
nicht so das Problem ist.
Da ich bisher bewegte Gui nur mithilfe von Engines geschrieben habe (Unity 3D(C#).., fällt
es mir extrem schwer das in Java umzusetzen. (sprich: paint bzw paintcomponent).
Die Aufgaben bauen wöchentlich aufeinander auf.. und ich hab bestimmt schon mehr als 20 Stunden
gebraucht, um genau gar nix hinzubekommen.

Zurück zum eigentlichen Problem:
http://s1.directupload.net/images/131123/9fctpqr7.jpg
Der "Raum" in der Mitte soll immer vorhanden sein.
Im Hauptprogram soll man mit new Kreis() ein Kreis auf die GUI
zeichnen der über ein Thread gestartet werden soll. (sollen sich random bewegen).
Ich habe schon einige Versionen geschrieben bei denen dies klappt.
Allerdings wenn ich mehrere Objekte (Kreise) hinzufüge, wird immer nur einer angezeigt..
Ich habe es mit glasspanes und vieles mehr probiert..

Kann mir jemand ein ganz winziges Script schrieben, bei dem man im Hauptprogram mit new Circle()
ein neues Objekt hinzufügen kann und dies über einen Thread läuft?
Ein paar Leute fügen ein Bildchen auf ein JLabel und bewegen dieses... allerdings kann das doch
nicht der Sinn des Erfinders sein ;(

Ich habs mit repaint innerhalb der Run Methode probiert... allerdings wird der vorherige Kreis nicht
neu gemalt oder resettet und ich hatte somit irgendwann einen ungewollten Bildschirmschoner-Effekt. Es gibt ebenfalls g.clearRect oder sowas... damit habe ich es versucht nach jedem repaint wieder zu löschen - allerdings ist der Versuch auch teilweise gescheitert.

Ich wäre euch unglaublich dankbar, wenn ihr ein winziges Programm schreiben könntet, um
mir auf die Sprünge zu helfen, sonst verzweifel ich endgültig und geb jedes mal ein Programm für die GUI und eins um Objekte zu erstellen ab :lol:

Hauptprogramm.java (JFrame) --> new Circle() , new Ciryle(),
Circle.java --> jedes neue Objekt läuft über einen Thread


Gruß
Leo
 

Gucky

Top Contributor
Ich würde nur einen Thread machen, der mittels einer Schleife über eine ArrayList iteriert und dort sämtliche Kreise mittels einer Methode aus dem Kreis den Kreis zeichnet.
 

Gucky

Top Contributor
Dann machst du eine Klasse KreisThread extends Thread implements Runnable.
Im Konstruktor machst du dann einen neuen Kreis und verwaltest den Kreis von dort.
In die run Methode kommt das ausführen des Kreises. (beweg(), render())
Die Kreisthreads verwaltest du in der Logikklasse mithilfe einer ArrayList. Wenn du einen KreisThread zu der Liste hinzufügst, dann startest du ihn auch gleich.
 

Leo123

Mitglied
Vielen Dank - hab es direkt mal versucht umzusetzen.
Zwei Verständnis/Umsetzungsprobleme habe ich dabei allerdings.

Die Logik habe ich in diesem Testprojekt noch nicht wirklich drin.
Nur ein eintöniges Positionshochzählen.

Zu Testzwecken habe ich in meinem "MainProgram.java" die ArrayList
erstellt. Wie kann ich die Objekte (Kreise), die in der ArrayList stecken
dem JFrame hinzufügen? Soll ich mithilfe von einem getter im KreisThread
den JFrame bekommen und im Konstruktor, in dem ich mein Objekt erstelle
diesem dann hinzufügen? Hoffentlich verstehst du mein Problem - bin etwas verwirrt ;-)
(Ich habe im Anhang mal die Datei angehängt)

Das Zeichnen habe ich momentan in der untersten Ebene drin.
Fühl mich einfach gerade ???:L
Wäre klasse, wenn du dir kurz das Projekt mal anschauen könntest :toll:
 

Anhänge

  • CatandMouseEXTENDED_V1_backup.zip
    22,4 KB · Aufrufe: 1

Gucky

Top Contributor
Den JFrame musst du nicht übergeben. Du überschreibst die paintComponent Methode des JFrames und füllst darin die Klassenweite Variable Graphics g. Die übergibst du den Threads und damit auch den Kreisen. Damit zeichnest du dann und rufst in einem separaten Thread immer wieder die repaint Methode. (Dieser Thread ist als lokale Klasse in dem JFrame)
 

Leo123

Mitglied
Ui ui sorry das ging mir jetzt etwas zu schnell :eek:
Ich frag lieber nochmal nach.. bin wieder dabei wild drauflos zu schreiben bzw es irgendwie hinzumurksen.

Den JFrame musst du nicht übergeben. Du überschreibst die paintComponent Methode des JFrames

Code:
@Override
public void paintComponent(Graphics g)
{
g.fillOval (200,200,100,100);   //only to check that nothing is happening :D
}


und füllst darin die Klassenweite Variable Graphics g
Code:
public Graphics g;


Die übergibst du den Threads und damit auch den Kreisen. Damit zeichnest du dann und rufst in einem separaten Thread immer wieder die repaint Methode. (Dieser Thread ist als lokale Klasse in dem JFrame)
Öhm da hörts komplett bei mir auf - wäre für einen neuen Hinweis sehr dankbar :D

Code:
package game.program;

import game.logic.MouseThread;

import java.awt.Graphics;
import java.util.ArrayList;

import javax.swing.JFrame;

public class MainProgram{
 
	private JFrame mainFrame=new JFrame();	
	private ArrayList<MouseThread> mice=new ArrayList<MouseThread>();
	private MouseThread tmpThread;
	
	public Graphics g;
	
	private void addMouse()
	{
		tmpThread=new MouseThread(g);
		mice.add(tmpThread);
		tmpThread.start();	
		//Thread repaintThread=new Thread();
		//repaintThread.start();
	}
		
	MainProgram()
	{
		mainFrame.setSize(700, 700);
		mainFrame.setTitle("Simulation-Test");
		mainFrame.setVisible(true);
	}
	
	public static void main(String[] args)
	{
		MainProgram mainProg = new MainProgram();
		
		for(int i=0;i<=3;i++)
		{
			mainProg.addMouse();
			
		}
	}
	
	//@Override
	public void paintComponent(Graphics g) {
		this.g.fillOval(200, 200, 100, 100);
	}
	
	//@Override
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName());
			//repaint();
		}
	}
}

Code:
package game.logic;

import java.awt.Graphics;

public class MouseThread extends Thread implements Runnable {
	private int posX = RandomPositionStart.createRandom(200);
	private int posY = RandomPositionStart.createRandom(200);
	
	public MouseThread(Graphics g)
	{
		new Mouse(g);
	}
	

	public void run()
	{
		while (true) 
		{
			try {
				Thread.sleep(700);
			} catch (InterruptedException ex) {
			}
			this.moveMouse();
			System.out.println("ThreadID: " + this.getId() + " | PosX: " + posX  +  "PosY: " + posY);
		}
	}
	
	public void moveMouse()
	{
		this.posX=this.posX+20;
		this.posY=this.posY+20;
	}


	public int getPosX() {
		return posX;
	}


	public int getPosY() {
		return posY;
	}
}


Code:
package game.logic;

import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JComponent;

public class Mouse extends JComponent {
	private Image mouseImg;
	private Graphics g;

	public Mouse(Graphics g) {
		this.g=g;
		try {
			mouseImg = ImageIO.read(new File("src/images/mouse.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	public void paintComponent(Graphics g) {
		this.g.drawImage(mouseImg, this.getX(), this.getY(), this);
		this.g.drawLine(0, 0, 10, 20);
	}
	
	public void renderMouseGui() {
		//this.g.drawImage(mouseImg, this.getX(), this.getY(), this);
		//this.g.drawLine(0, 0, 10, 20);
	}
}

Ich hab mal meine drei Files reingestellt.

Vielen Dank schonmal für die Hilfe ;-)
 
Zuletzt bearbeitet:

Gucky

Top Contributor
Zum Malen in Swing guck dir bitte eines der zahlreichen Tutorials an. (Es gibt eines, in dem eine separate Klasse benötigt wird. Das nicht. Das ist nämlich nicht nötig :D )

Weißt du, wie man Parameter im Konstruktor übergibt? Dort übergibst du dem Thread den Graphics g und der übergibt diesen dann der Klasse Kreis, die damit malt.

In der GUI Klasse ist ein Thread in einer lokalen Klasse, der immer die repaint Methode aufruft.
 

Leo123

Mitglied
Zum Malen in Swing guck dir bitte eines der zahlreichen Tutorials an. (Es gibt eines, in dem eine separate Klasse benötigt wird. Das nicht. Das ist nämlich nicht nötig )

Ich gehe mal davon aus, dass JComponent damit gemeint ist :D

Weißt du, wie man Parameter im Konstruktor übergibt?
Also normalerweise sollte man das im 3. Semester schon hinbekommen..
Allerdings ist mir in Java das ganze Prinzip noch ned so wirklich klar und
in Unity hab ich meine Spiele immer ohne Threads hinbekommen :D

In der GUI Klasse ist ein Thread in einer lokalen Klasse, der immer die repaint Methode aufruft.
Das hab ich inzwischen hingebogen.. denke ich mal^^

Mal schauen ob ich das noch eben hinbekomme. Heut gibts mal wieder nen schönen Test..
Aber bis Donnerstag 0 Uhr werd ich es hoffentlich irgendwie hinbekommen :lol:

EDIT: ich glaub ich hab schon wieder Bullshit geschrieben :toll:
EDIT++: dem MainFrame kann ich mit add(new Mouse()) etwas hinzufügen.. das ist mir klar..
Nur die MouseThread.java ist kein JComponent. Sorry bin ziemlich verwirrt gerade ???:L
EDIT++: Jetzt hab ich die Schleife, in der ich die Objekte erstelle entfernt und nur
eins erzeugt.. jetzt wird eins angezeigt :D Ich brauch ne Pause...^^
 
Zuletzt bearbeitet:

Leo123

Mitglied
Schönen guten Abend,
Mir ist es noch nicht wirklich klar mit den Threads in Verbindung mit paintComponent.
Wenn ich das alles in eine Java Datei reinwerde, würd ich es warscheinlich sogar hinbekommen.

Momentan sieht es so aus:
___________________________
MainProgram extendes Thread

Dort ist der JFrame drin.
___________________________
___________________________
MouseThread extends Thread implements Runnable

Neues Mausobjekt wird erzeugt... + Bewegen des Bildes
___________________________
___________________________
Mouse extends JComponent
Laden des Bildes..
___________________________

In den JFrame könnte ich mit add direkt eine new Mouse() einfügen,
weil dies ein Jcomponent ist...
MouseThread.java kann ich allerdings nicht hinzufügen, weil man logischer
weise nicht hinzufügen.. aber ich versteh auch ned wie ich das lösen kann.

Hab heute auch irgendwie kein Kopf mehr um drüber nachzudenken..
Bzw ich glaub ich hab wieder einiges zerstört :/

So kann ich es hinzufügen... allerdings läufts dann halt nicht mit Threads.


Hier nochmal mein aktuell (fehlerhafter) Code..
Muss schauen, ob ich morgen nochmal was hinbiegen kann,
oder obs wieder in wildem Versuchen und copy und paste endet..
Vielen Dank auf jedenfall schonmal für deine Hilfe :)

mainFrame.add(new Mouse());


Code:
package game.program;

import game.logic.Mouse;
import game.logic.MouseThread;

import java.awt.Graphics;
import java.util.ArrayList;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MainProgram extends Thread{
 
	private JFrame mainFrame=new JFrame();	
	private ArrayList<MouseThread> mice=new ArrayList<MouseThread>();
	private MouseThread tmpThread;
	
	public static Graphics g;

	private void addMouse()
	{
		tmpThread=new MouseThread();
		mice.add(tmpThread);
		
		tmpThread.start();	
		


		//Thread repaintThread=new Thread();
		//repaintThread.start();
	}
		
	MainProgram()
	{
		
		mainFrame.setSize(700, 700);
		mainFrame.setTitle("Simulation-Test");
		
		//mainFrame.add(new Mouse());
		
		mainFrame.setVisible(true);
	}
	
	public static void main(String[] args)
	{
		MainProgram mainProg = new MainProgram();
		mainProg.start();
		
		//for(int i=0;i<=3;i++)
		//{
			mainProg.addMouse();
			
		//}
	}
	
	//@Override
	public void paintComponent(Graphics g) {
		g.fillOval(200, 200, 100, 100);
		//paintComponent(g);
	}
	
	//@Override
	public void run()
	{
		while(true)
		{
			System.out.println(Thread.currentThread().getName());
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			mainFrame.getContentPane().revalidate();
			mainFrame.getContentPane().repaint();
		}
	}
	
}

Code:
package game.logic;

import java.awt.Graphics;

public class MouseThread extends Thread implements Runnable {
	private int posX = RandomPositionStart.createRandom(200);
	private int posY = RandomPositionStart.createRandom(200);
	
	public MouseThread()
	{
		new Mouse();
	}
	

	public void run()
	{
		while (true) 
		{
			try {
				Thread.sleep(700);
			} catch (InterruptedException ex) {
			}
			this.moveMouse();
			System.out.println("ThreadID: " + this.getId() + " | PosX: " + posX  +  "PosY: " + posY);
		}
	}
	
	public void moveMouse()
	{
		this.posX=this.posX+20;
		this.posY=this.posY+20;
	}


	public int getPosX() {
		return posX;
	}


	public int getPosY() {
		return posY;
	}
}

Code:
package game.logic;

import game.program.MainProgram;

import java.awt.Graphics;
import java.awt.Image;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.swing.JComponent;

public class Mouse extends JComponent {
	private Image mouseImg;

	public Mouse() {
		try {
			mouseImg = ImageIO.read(new File("src/images/mouse.png"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	
	public void paintComponent(Graphics g) {
		MainProgram.g=g;
		super.paintComponent(g);
		g.drawImage(mouseImg, this.getX(), this.getY(), this);
		g.drawLine(0, 0, 10, 20);
	}
	
	public void renderMouseGui() {
		//this.g.drawImage(mouseImg, this.getX(), this.getY(), this);
		//this.g.drawLine(0, 0, 10, 20);
	}
}
 

Gucky

Top Contributor
Warum erweitert deine Maus eine JComponent?

Ich würde das eher mit
Code:
g.drawSonstwas()
machen. Da schießt du mit Kanonen auf Kolibris.

Du versuchst auf deine Mouse etwas zu zeichnen. Dann versuchst du die
Code:
paintComponent()
-Methode eines Threads zu überschreiben. So läuft das aber nicht. :D

Du hast eine Visuelle Klasse mit der Variable
Code:
Graphics g
(von mir aus final).
Dort überschreibst du die
Code:
paintComponent(Graphics g)
-Methode deines JFrames und darin steht dann:
Code:
this.g=g;
. Damit füllst du die noch nicht definierte Variable g aus dem JFrame mit der definierten Variable aus der Methode
Code:
paintComponent(Graphics g)
.
In dieser Visuellen Klasse ist eine lokale Klasse extends Thread, die nichts besseres zu tun hat, als unablässig
Code:
repaint()
aufzurufen.
Das g aus der visuellen Klasse übergibst du deiner Logikklasse. Die Logikklasse verwaltet in einer Liste sämtliche MousThreads extends Thread implements Runnable. Dort ist auch die Schleife, die deine Liste mit MouseThreads füllt und diese startet oder stoppen kann.
Die Logikklasse übergibt das g aus der visuellen Klasse an die MouseThreads. Diese übergeben das g aus der visuellen Klasse weiter an eine Klasse Mouse, die damit deine Maus auf deinen JFrame zeichnet.


Das sieht jetzt sehr kompliziert aus aber wenn du dir das noch mal als UML Diagramm aufmalst, wirst du sehen, dass das Ganze logisch und sinnvoll ist und auch gar nicht so kompliziert (vorausgesetzt, ich bin nirgends durcheinander gekommen :D )
 

Neue Themen


Oben