Variablenabfrage während Thread läuft

manu8

Grünschnabel
Hallo,

ich schreibe an einem Programm in welchem beim Drücken der Maus ein Thread gestartet werden soll, welcher einfach von 0 an hoch zählt und beim Loslassen der Maus, der Zähler einfach gestoppt werden soll.
Also der Thread sollte abhängig vom Zustand der Variablen (boolean) eine bestimmte Funktion ausführen.
Wenn sich der Zustand der Variablen ändert, während der Thread bereits läuft, führt der Thread aber nicht die andere gewünschte Funktion aus. Es scheint als ob der Thread, wenn er einmal läuft die Variable nicht mehr abfrägt.

Code:
import java.awt.Canvas;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class AuswahlBox extends Canvas implements ItemListener, MouseListener, MouseMotionListener {

	public boolean gepresst = false;
	
	public AuswahlBox() {
		addMouseListener(this);
	}
	
	public Dimension getMinimumSize() {
		return new Dimension(300, 300);
	}
	
	public Dimension getPreferredSize() {
		return getMinimumSize();
	}
	
	public void paint(Graphics g) {
		g.setColor(Color.black);
		g.fillRect(0, 0, 300, 300);		
	}

	@Override
	public void itemStateChanged(ItemEvent e) {
		
		
		if(e.getItem() == "yellow") {					
			System.out.println("yellow wurde gewählt");				
		}
		if(e.getItem() == "red") {
			System.out.println("red wurde gewählt");
		}
		if(e.getItem() == "green") {
			System.out.println("green wurde gewählt");
		}
		if(e.getItem() == "blue") {
			System.out.println("blue wurde gewählt");
		}		
	}		
	
	
	public synchronized boolean pressed() {			
		return gepresst;
	}	

	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {		
		gepresst = true;
		System.out.println(gepresst);
		Thread meinThread = new Runner();		
		meinThread.start();
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {	
		gepresst = false;
		System.out.println(gepresst);
		
	}	
}

Code:
public class Runner extends Thread {
	
	AuswahlBox box = new AuswahlBox();
	
	public boolean pressed() {		
		return box.pressed();
	}
	
	@Override
	public void run() {			
		int i = 0;			
		System.out.println("gespresst: "+pressed());
		while(true) {
			if(pressed()) {
				System.out.println(i);
				i++;
			} 						
			
		}	   
	}
}

Code:
mport java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main extends Frame{	
	
	public Main() {
		super("PaintCanvas");
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				setVisible(false);
				dispose();
				System.exit(0);
			}
		});
	}

	public static void main(String[] args) {
		Main main = new Main();
		
		main.setLayout(new BorderLayout());
		main.setSize(300, 300);				
		
		Panel panel = new Panel();
		AuswahlBox auswahlBox = new AuswahlBox();
		panel.add(auswahlBox);	
		
		main.add(panel, BorderLayout.CENTER);	
		
		Choice choice = new Choice();
		choice.addItemListener(auswahlBox);
		choice.addItem("yellow");
		choice.addItem("red");
		choice.addItem("green");
		choice.addItem("blue");
		Panel panel1 = new Panel();
		panel1.add(choice);
		main.add(panel1, BorderLayout.SOUTH);
		main.setVisible(true);		
	}	
}


Wie könnte ich das Programm abändern, damit der Thread auch während der läuft die Variable abfrägt.
 

sheel

I love Asm
Hi

das kann so nicht gehen, weil du bei jedem Mausklick einen neuen Thread erstellst.
Und noch dazu bekommt jeder Thread seine eigene Auswahlbox.

Starte den Thread nicht im mousePressed, sondern irgendwo am Anfang des Programms (zB Im Konstruktor von der Auswahlbox) und setz die box-Variable vom Thread (zwischen "new Runner" und "...start()") auf die vorhandene Auswahlbox.

Gruß
 

manu8

Grünschnabel
Danke für die schnelle Hilfe.
Hab das Programm jetzt so abgeändert:

Code:
public class AuswahlBox extends Canvas implements ItemListener, MouseListener, MouseMotionListener {

	public boolean gepresst;
	
	public AuswahlBox() {
		addMouseListener(this);		
		Thread meinThread = new Runner();
		gepresst = false;
		meinThread.start();
	}

Leider bekomme ich jetzt die Fehlermeldung:
Exception in thread "main" java.lang.StackOverflowError

at java.security.AccessControlContext.optimize(Unknown Source)
at java.security.AccessController.getContext(Unknown Source)
at java.lang.Thread.init(Unknown Source)
at java.lang.Thread.<init>(Unknown Source)
at Zeichenfeld.Runner.<init>(Runner.java:3)
at Zeichenfeld.AuswahlBox.<init>(AuswahlBox.java:20)
at Zeichenfeld.Runner.<init>(Runner.java:5)
at Zeichenfeld.AuswahlBox.<init>(AuswahlBox.java:20)
at Zeichenfeld.Runner.<init>(Runner.java:5)
at Zeichenfeld.AuswahlBox.<init>(AuswahlBox.java:20)
at Zeichenfeld.Runner.<init>(Runner.java:5)
at Zeichenfeld.AuswahlBox.<init>(AuswahlBox.java:20)
......
 

sheel

I love Asm
Du erstellst noch immer pro Thread eine Auswahlbox. Diese erstellt wieder einen Thread usw...
deshalb die Ex.

Zu tun:
1) Aus mousePressed den Threadstart rausnehmen. Ist ja schon im Konstruktor.
Nur gepresst=true und das System.out
2) Im Thread bei der box-Variable das =new... wegnehmen.
3) Dafür eine setBox-Methode (oder so ähnlich) machen.
4) Im Konstruktor der Auswahlbox vor meinThread.start() diese setBox-Methode mit this aufrufen.
 

manu8

Grünschnabel
Denn Threadstart hatte ich bereits aus mousePressed entfernt (hab vergessen es zu erwähnen).
Das "= new..." habe ich jetzt entfernt.
Das mit der setBox-Methode ist mir noch nicht so klar. Sorry bin doch noch mehr ein Anfänger.
In dieser setBox-Methode sollte doch eine AuswahlBox erzeugt werden, wenn ich aber dann diese Methode in den Konstruktor von AuswahlBox vor meinThread.start() einfüge, erhalte ich wieder einen StackOverflowError. Wahrscheinlich mache ich irgendetwas falsch
 

sheel

I love Asm
Du denkst falsch.
Warum soll der Thread seine eigene Auswahlbox erhalten?

Eine gibt es ja schon, die angezeigt wird.
Und genau die soll der Thread bekommen.
Du machst aber eine zweite im Thread, die zwar nicht sichtbar ist,
aber ihre eigene gepresst-Variable hat.

Die Stackoverflow-Sache kommt dadurch zusammen, dass
die Auswahlbox gleich beim Starten eine Thread erzeugt, dieser
sofort eine neue Auswahlbox, die wieder einen Thread ... und so weiter,
bis der dafür vorgesehene Speicher voll ist.

Zeig bitte noch einmal den ganzen Code, was du bis jetzt geändert hast
 

manu8

Grünschnabel
anbei den kompletten Code, ohne die setBox-Methode.
Bei meinem jetzigen Code bekomme ich die Fehlermeldung:

Exception in thread "Thread-2" java.lang.NullPointerException
at Zeichenfeld.Runner.pressed(Runner.java:9)
at Zeichenfeld.Runner.run(Runner.java:15)

Code:
import java.awt.Canvas;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

public class AuswahlBox extends Canvas implements ItemListener, MouseListener, MouseMotionListener {

	public boolean gepresst;
	
	public AuswahlBox() {
		addMouseListener(this);		
		Thread meinThread = new Runner();
		gepresst = false;
		
		meinThread.start();
	}
	
	
	
	
	public Dimension getMinimumSize() {
		return new Dimension(300, 300);
	}
	
	public Dimension getPreferredSize() {
		return getMinimumSize();
	}
	
	public void paint(Graphics g) {
		g.setColor(Color.black);
		g.fillRect(0, 0, 300, 300);		
	}

	@Override
	public void itemStateChanged(ItemEvent e) {		
		
		if(e.getItem() == "yellow") {					
			System.out.println("yellow wurde gewählt");				
		}
		if(e.getItem() == "red") {
			System.out.println("red wurde gewählt");
		}
		if(e.getItem() == "green") {
			System.out.println("green wurde gewählt");
		}
		if(e.getItem() == "blue") {
			System.out.println("blue wurde gewählt");
		}		
	}		
	
	
	public synchronized boolean pressed() {			
		return gepresst;
	}	

	@Override
	public void mouseDragged(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub		
	}

	@Override
	public void mousePressed(MouseEvent arg0) {		
		gepresst = true;
		System.out.println(gepresst);
		
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {	
		gepresst = false;
		System.out.println(gepresst);
		
	}	
}

Code:
public class Runner extends Thread {
	
	AuswahlBox box;
	
	
	public boolean pressed() {		
		return box.pressed();
	}
	
	@Override
	public void run() {			
		int i = 0;			
		System.out.println("gespresst: "+pressed());
		while(true) {
			if(pressed()) {
				System.out.println(i);
				i++;
			} 			
		}	   
	}
}

Code:
import java.awt.BorderLayout;
import java.awt.Choice;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Main extends Frame{	
	
	public Main() {
		super("PaintCanvas");
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent event) {
				setVisible(false);
				dispose();
				System.exit(0);
			}
		});
	}

	public static void main(String[] args) {
		Main main = new Main();
		
		main.setLayout(new BorderLayout());
		main.setSize(300, 300);				
		
		Panel panel = new Panel();
		AuswahlBox auswahlBox = new AuswahlBox();
		panel.add(auswahlBox);	
		
		main.add(panel, BorderLayout.CENTER);	
		
		Choice choice = new Choice();
		choice.addItemListener(auswahlBox);
		choice.addItem("yellow");
		choice.addItem("red");
		choice.addItem("green");
		choice.addItem("blue");
		Panel panel1 = new Panel();
		panel1.add(choice);
		main.add(panel1, BorderLayout.SOUTH);
		main.setVisible(true);		
	}
	
}
 

sheel

I love Asm
Jetzt machst du im Thread noch einen Setter für box
Java:
public void setBox(AuswahlBox x) {
    box = x;
}
und beim AuswahlBox-Konstruktor kommt eine Zeile dazu:
Java:
public AuswahlBox() {
    addMouseListener(this);
  
    Thread meinThread = new Runner();
    gepresst = false;
    meinThread.setBox(this); //neu
    meinThread.start();
}

Was ist an einem Setter für box so schwer?
Alternativ übergibst du die Box gleich im Konstruktor, oder machst sie public und weist es einfach zu, oder ...
 

manu8

Grünschnabel
Vielen Dank
jetzt läuft es so wie es sollte

Was an dem Setter so schwer ist, kann ich im Moment auch nicht sagen.