SwingWorker Hilfe!

mogli

Mitglied
Hallo Programmierfreunde!

Ich bin noch ein Frischling und muss selbst sagen, dass ich mich ein wenig uebernommen habe.
Ich habe aber nunmal dieses "kleine" Programm angefangen und das laesst mir keine Ruhe mehr.
Ich sitze schon seit Stunden daran und komme einfach nicht weiter.

Ich braeuchte also Hilfe zum Einsatz des WorkerThreads, vllt anhand eines Beispiels:

Code:
	public Test() {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JButton btnStart = new JButton("Start");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
				{
                                 zaehlen=true;
				//Worker Thread starten!
				}
		});
		contentPane.add(btnStart, BorderLayout.WEST);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) 
				{
                                 zaehlen=false;
				//Worker Thread stoppen!
				}
		});
		contentPane.add(btnStop, BorderLayout.EAST);
	}

}

Das Programm soll nun beispielsweise nach einer gewissen Zeit eine Taste drücken.
Code:
public WorkerThread(String actionCommand) 
		
{
		
        Robot robot = null; //ROBOT
    	try 
    	{
    	robot = new Robot();
    	}
    	catch (AWTException g) 
    	{
    	g.printStackTrace();
    	}

    	while(zaehlen=true)
        {
    	robot.delay(5000); //5sek warten vor Tastendruck
	robot.keyPress(49); //Taste 1
	robot.keyRelease(49);//Taste 1
	}
}
Während dieser Zeit will ich den Vorgang aber jederzeit abbrechen koennen, indem ich den Stop Button druecke.

Ich weiß, dass es schon einige Beitraege zu dem Thema gibt, jedoch konnte ich die Informationen leider nicht in meinem Programm umsetzen.

Ich bin mittlerweile für Hilfe sehr dankbar 😀
 
Hallo,
du lässt einfach deine klasse test von Runnable erben:
Java:
public class Test implements Runnable
dann braucht deine klasse test eine methode
Java:
public void run()
in diese run-methode kommt dein ganzer code der in WorkerThread steht (deinen parameter actionCommand lasse ich jetzt mal außen vor, der wird ja offenbar nicht benötigt)
du machst ein datenfeld in der Klasse Test:
Java:
private Thred th;
in deinem konstruktor muss stehen:
Java:
th = new Thread(this);
und in deine actionperformed-methode von deinem jbutton steht:
Java:
if(!th.isAlive()) {
    th.start();
    btnStart.setText("Stop");
} else {
    th.interrupt();
    btnStart.setText("Start");
}
So müsste es funktionieren, hab jetzt nicht getestet.
javampir
 
Ja dein code hat super geklappt! =)
Das Programm friert nun nicht mehr ein.
Allerdings ist nun ein neues Problem aufgetaucht: naemlich, dass er aus der while-Schleife nicht mehr herauskommt.

Dh er tippt staendig diese 1 ein^^

Code:
		JButton btnStart = new JButton("Start");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=true;
				th.start();
			}
		});
		contentPane.add(btnStart, BorderLayout.WEST);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=false;
				th.interrupt();
			}
		});

while:

Code:
    public void run()
    	{
        Robot robot = null; //ROBOT
    	try 
    	{
    	robot = new Robot();
    	}
    	catch (AWTException g) 
    	{
    	g.printStackTrace();
    	}

    	while(zaehlen==true)
        {
    	robot.delay(5000); //5sek warten vor Tastendruck
    	robot.keyPress(49); //Taste 1
    	robot.keyRelease(49);//Taste 1 loslassen
        if(zaehlen==false)
        {
        	break;
        }
        }
    	}

Und eine Frage habe ich zu deinem Code javampir;
An welcher Stelle sage ich dem Programm, dass es die Anweisungen in public void run() ausfuehren soll. Ich sage ihm per Knopfdruck ja lediglich, dass er den th.Thread Konstruktor ansprechen soll.
Scheinbar besteht zwischen diesen eine direkte Verbindung, aber ich verstehe nicht warum!
 
Hallo mogli,

mit der Anweisung
Code:
th.start();
sagst du deinem programm, dass er den Inhalt deiner
Code:
run()
-Methode ausführen soll.

Du kannst in deiner
Code:
run()
-Methode diese Anweisung auslassen, da die while-Schleife sowieso abbricht, wenn deine variable
Code:
zaehlen
den wert
Code:
false
annimmt.

if(zaehlen==false)
{
break;
}
}
}

du kannst stattdessen mal einfügen:
Java:
th.sleep(1);
so bekommst du zumindest alle 5 sekunden die möglichkeit, selbst aktiv zu werden und das abzubrechen.

besser wäre dann vllt noch:
Java:
public void run()
    	{
int warten=0;
 Robot robot = null; //ROBOT
 try 
 {
 robot = new Robot();
 }
 catch (AWTException g) 
 {
 g.printStackTrace();
 }

 while(zaehlen==true)
 {
 if(warten==5000) 
{ 
 robot.keyPress(49); //Taste 1
 robot.keyRelease(49);//Taste 1 loslassen
warten=0;
}
try{ th.sleep(1); } catch (Exception ex) {}
warten++;
}

So kannst du dann jederzeit selbst aktiv sein und das abbrechen, und dein Roboter drückt trotzdem alle 5 Sekunden auf die Taste 🙂
 
Zuletzt bearbeitet:
Okay ich habe die break; Anweisung rausgekommen. Nun kann ich den Thread auch Stoppen.

Nichts fuer ungut, aber ich wuerde zuerst versuchen zu verstehen, warum da etwas nicht richtig laeuft.
So wie ich das sehe kann ich mit th.start() und th.interrupt() den thread starten und stoppen. In den actionperformed Methoden habe ich zaehlen wie schon gepostet auf true bzw false gesetzt.

Ich programmiere mit Eclipse.
Wenn ich den Thread stoppe gibt er mir folgende Fehlermeldung aus:

java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at java.awt.Robot.delay(Robot.java:542)
at test.Test.run(Test.java:95)
at java.lang.Thread.run(Thread.java:744)

Falls das ueberhaupt ein Fehler ist.
Wenn ich dann wieder auf Start druecke kommt:
Exception in thread "AWT-EventQueue-0" java.lang.IllegalThreadStateException
at java.lang.Thread.start(Thread.java:704)
at test.Test$2.actionPerformed(Test.java:63)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:2018)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2341)
at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:402)
at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:259)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:252)
at java.awt.Component.processMouseEvent(Component.java:6505)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3311)
at java.awt.Component.processEvent(Component.java:6270)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4492)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:735)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:708)
at java.awt.EventQueue$4.run(EventQueue.java:706)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:705)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:242)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:150)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:146)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:138)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:91)
... und er startet nicht wieder von vorn.
Ich poste vllt zusaetzlich noch den gesamten code:

Code:
package test;

import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Robot;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JButton;

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

public class Test extends JFrame implements Runnable {
	
	private static final long serialVersionUID = 1L;

	private Thread th;
    {
    th = new Thread(this);
    }

	public boolean zaehlen;
	private JPanel contentPane;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Test frame = new Test();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
               public Test() 
	       {
		
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JButton btnStart = new JButton("Start");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=true;
				th.start();
			}
		});
		contentPane.add(btnStart, BorderLayout.WEST);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=false;
				th.interrupt();
			}
		});
		contentPane.add(btnStop, BorderLayout.EAST);
		
		
	}

	
    public void run()
    	{
        Robot robot = null; //ROBOT
    	try 
    	{
    	robot = new Robot();
    	}
    	catch (AWTException g) 
    	{
    	g.printStackTrace();
    	}

    	while(zaehlen==true)
        {
    	robot.delay(5000); //5sek warten vor Tastendruck
    	robot.keyPress(49); //Taste 1
    	robot.keyRelease(49);//Taste 1 loslassen
        }
        }
}

Newcomer dein Code funktioniert einen Tick besser, da er ohne Probleme stoppt. Jedoch laesst er sich auch nicht wieder starten.

Muss ich den Thread erst wieder zuruecksetzen o.Ä.?

Vllt ist es möglich den Thread schon von Anfang an laufen zu lassen und per ActionPerformed lediglich zaehlen auf true oder false zu setzen.
Das kommt mir allerdings nicht wie eine saubere Programmierung vor sondern wie Pfuschen 😀
 
Hallo mogli,

ja, richtig, mit
Code:
th.start();
und
Code:
th.interrupt();
kannst du den Thread starten und sogar zerstören, mit
Code:
th.stop();
kannste ihn erstmal stoppen.
Da wäre auch der Fehler: mit
Code:
th.interrupt();
zerstörst du den Thread. Diese Fehlermeldung sagt aus, dass er im schlafenden Modus zerstört wurde. Die zweite Meldung sagt Dir, dass er nicht weiß, welcher Thread gestartet werden soll, es ist ja keiner mehr da.

Warum du es also nicht wieder starten kannst, liegt daran, dass Du nur den einen Thread besitzt, den Du zu Beginn mit
Code:
th = new Thread(this);
erzeugst und der dann mit
Code:
th.interrupt();
zerstört wird. Du müsstest in dem Fall also jedes Mal wenn Du auf Start drückst, einen neuen Thread einläuten. Also vor die
Code:
th.start();
-Anweisung noch
Code:
th = new Thread(this);
setzen.

Ich programmiere auch mit Eclipse 🙂

Es wäre auch kein Pfuschen, den Thread von Anfang an laufen zu lassen 😉 ist sogar eine gute Variante ^^
Java:
while(Frame.isVisible()) {


}
Dann aber eben auch mit
Code:
th.sleep();
in nem Counter bis 5000 in der run()-Methode. Der Counter sollte dann anfangen mit zählen, sobald
Code:
zaehlen
auf true ist, und auf 0 gesetzt wird und bleibt, sobald zaehlen auf false ist.
 
Zuletzt bearbeitet:
Will Dir mal noch die beiden Möglichkeiten gegenüber stellen:

1. Thread läuft von Anfang an:

Java:
public class Test extends JFrame implements Runnable {
	
	private static final long serialVersionUID = 1L;

	private Thread th;
        public boolean zaehlen;
	private JPanel contentPane;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Test frame = new Test();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
               public Test() 
	       {
		th = new Thread(this);
                th.start();
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JButton btnStart = new JButton("Start");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=true;
				// th.start(); in diesem Fall dies auslassen
			}
		});
		contentPane.add(btnStart, BorderLayout.WEST);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=false;
				// th.interrupt(); dieses auch auslassen
			}
		});
		contentPane.add(btnStop, BorderLayout.EAST);
		
		
	}

	
    public void run()
    	{
        int zaehler=0;
        Robot robot = null; //ROBOT
    	try 
    	{
    	robot = new Robot();
    	}
    	catch (AWTException g) 
    	{
    	g.printStackTrace();
    	}

    	while(isVisible()) //Solange dein Programmfenster sichtbar ist, macht er das Folgende,
                              // ansonsten hört der Thread auf zu laufen 
        {
            if (zaehlen==true) 
            { //sobald deine Variable true ist, fängt er an zaehler hochzuzählen
                if (zaehler==5000) 
                { //erreicht zaehler dabei den Wert 5000, drückt er die Taste 1 
                  //und zaehler wird auf 0 gesetzt, zählt aber weiter
    	            robot.keyPress(49); //Taste 1
    	            robot.keyRelease(49);//Taste 1 loslassen
                    zaehler=0;
                } 
            zaehler++;
            try { th.sleep(1); } catch (Exception e) {} // der Thread muss 1ms schlafen gelegt werden
        } // damit deine Eingaben auch erkannt werden können
        }
        }
}

2. Thread läuft erst bei Druck auf "Start":

Java:
public class Test extends JFrame implements Runnable {
	
	private static final long serialVersionUID = 1L;

	private Thread th;
        public boolean zaehlen;
	private JPanel contentPane;

	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					Test frame = new Test();
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
               public Test() 
	       {
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setBounds(100, 100, 450, 300);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		contentPane.setLayout(new BorderLayout(0, 0));
		setContentPane(contentPane);
		
		JButton btnStart = new JButton("Start");
		btnStart.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=true;
                                th = new Thread(this); //bei betätigen des "Start"-Buttons entsteht d. Thread
				th.start(); // und wird sofort gestartet
			}
		});
		contentPane.add(btnStart, BorderLayout.WEST);
		
		JButton btnStop = new JButton("Stop");
		btnStop.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				zaehlen=false;
                                th.stop();  //erstmal den Thread stoppen
				th.interrupt(); //dann kann er zerstört werden
			}
		});
		contentPane.add(btnStop, BorderLayout.EAST);		
	}

	
    public void run()
    	{
        int zaehler=0;
        Robot robot = null; //ROBOT
    	try 
    	{
    	robot = new Robot();
    	}
    	catch (AWTException g) 
    	{
    	g.printStackTrace();
    	}

    	while(th.isAlive()) 
        {   //solange dein Thread läuft, d.h. zaehlen = true macht er folgendes: 
                if (zaehler==5000) //ist die Variable zaehler auf 5000
                { 
    	            robot.keyPress(49); //Taste 1 drücken
    	            robot.keyRelease(49);//Taste 1 loslassen
                    zaehler=0; //zaehler wieder auf 0 setzen
                } 
            zaehler++; //die Variable zaehler wird dauerhaft hochgezählt
            try { th.sleep(1); } catch (Exception e) {} // der Thread muss 1ms schlafen gelegt werden
        } // damit deine Eingaben auch erkannt werden können
        }
        }
}

Ich hoffe, hier hast du jetzt mal 2 funktionierende Varianten und kannst sie nachvollziehen 🙂
 
Zuletzt bearbeitet:
Erstmal vielen Dank für deine ausfuehrlichen Erlaeuterungen! =)

Allerdings funktionieren deine beiden codes bei mir leider nicht ^^
Ich haette wirklich nie gedacht, dass java SO kompliziert ist :S
Ich habe ein paar C++ Vorkenntnisse und hatte das Programmieren wirklich nicht so verwirrend in Erinnerung 😱

Ich habe noch ein bisschen rumprobiert.
Er kann per Tastendruck in der actionPerformed Methode keinen neuen Thread erstellen.
Er bietet mir dann
Code:
th = new Thread();
an. Das this gefaellt ihm irgendwie nicht - so funktioniert es aber natuerlich auch nicht. D.h. er startet den Thread nicht.

Dann habe ich die erste Methode(thread laeuft direkt) versucht ganz einfach zu loesen:

Code:
    public void run()
        {
        Robot robot = null; //ROBOT
        try
        {
        robot = new Robot();
        }
        catch (AWTException g)
        {
        g.printStackTrace();
        }
 
        while(zaehlen==true)
        {
        	    robot.delay(3000);
                    robot.keyPress(49); //Taste 1
                    robot.keyRelease(49);//Taste 1 loslassen
        }
        }
}

--> Er faengt auch nicht an.

Warum sollte es so nicht funktionieren? Ich setze die Variable einfach nur auf true (was ja an sich funktioniert) und dann sollten die Anweisungen in der while Schleife in dem Thread(der ja laufen sollte) ausgefuehrt, weil die Bedingung true erfuellt wurde.

Viel mehr wuerde mich allerdings interessieren, warum er ein Problem damit hat den Thread aus der actionPerformed Methode zu starten.
 
Hallo,
habs mal bei mir probiert. Die Varianten, die ich da gepostet haben, gehn bei mir auch nicht ^^
Aber hab noch bissl gebastelt, und JETZT gehts 🙂 Zumindest bei mir ^^
So funktioniert das bei dauernd laufendem Thread 🙂 Jedoch is das Fenster selbst nicht mehr sehr groß, das kommt aber durch das
Code:
pack();
. Die Anweisung komprimiert das Fenster auf den nötigsten Platzbedarf.

Java:
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;

    public class Test extends JFrame implements Runnable {
       
        private static final long serialVersionUID = 1L;
     
        private Thread th;
            public boolean zaehlen;
        private JPanel contentPane;
     
        public static void main(String[] args) {
                        Test frame = new Test(); //Hier ist ne ganze Menge weg, wie Du siehst ^^
        }
       
                   public Test()
               {

            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setVisible(true);
            contentPane = new JPanel();
            contentPane.setSize(450,300);
            contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
            contentPane.setLayout(new BorderLayout(0, 0));
            add(contentPane); //Hier wurde setContentPane durch add ersetzt
            th = new Thread(this);
            th.start();
            JButton btnStart = new JButton("Start");
            btnStart.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    zaehlen=true;
                    System.out.println();
                    // in diesem Fall dies auslassen
                }
            });
            contentPane.add(btnStart, BorderLayout.WEST);
           
            JButton btnStop = new JButton("Stop");
            btnStop.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    zaehlen=false;
//                     th.interrupt(); //dieses auch auslassen
                }
            });
            contentPane.add(btnStop, BorderLayout.EAST);           
               pack();}
     
       
        public void run()
            {
            int zaehler=0;
            Robot robot = null; //ROBOT
            try
            {
            robot = new Robot();
            }
            catch (AWTException g)
            {
            g.printStackTrace();
            }
     
            while(isVisible()) //Solange dein Programmfenster sichtbar ist, macht er das Folgende,
                                  // ansonsten hört der Thread auf zu laufen
            {
                if (zaehlen==true)
                { //sobald deine Variable true ist, fängt er an zaehler hochzuzählen
                    if (zaehler==5000)
                    { //erreicht zaehler dabei den Wert 5000, drückt er die Taste 1
                      //und zaehler wird auf 0 gesetzt, zählt aber weiter
                        robot.keyPress(49); //Taste 1
                        robot.keyRelease(49);//Taste 1 loslassen
                        zaehler=0;
                    }
                zaehler++;
                try { th.sleep(1); } catch (Exception e) {} // der Thread muss 1ms schlafen gelegt werden
            } // damit deine Eingaben auch erkannt werden können
            }
            }
    }

Ansonsten is der Rest geblieben. Und die 1 setzt der dann im entsprechenden Intervall dort, wo Du den Cursor hinsetzt. Sei es im Quellcode, in der Commandozeile, im Suchfenster des Browsers ^^

Viel Spaß damit 😉
 
Jap, jetzt laeuft es bei mir auch! 😉
Also nochmal vielen Dank und ich werde jetzt versuchen alles zu verstehen und in mein eigentliches Programm zu integrieren 😀

Bis bald! 😉
 

Neue Themen


Zurück
Oben