Executing methods in a running secondary thread. Java - java

I have some methods that need to be run from the same secondary thread (if the thread is different they don't work). I have the secondary thread running. Is it possible to execute these methods from this secondary running thread by invoking them from outside? I got good results extracting the content of the methods and putting it in a "state machine" inside the "run" method, but my question is if I have any other way to do this without extracting the content of the method and easier and cleaner.
Example:
package threadapp;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import static javax.swing.JFrame.EXIT_ON_CLOSE;
public class ThreadApp {
public static void main(String[] args) {
Utils utils = new Utils();
}
}
class Utils {
JFrame frame;
JButton btn1;
public Utils() {
btn1 = new JButton("btn1");
frame = new JFrame();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setBounds(100, 100, 300, 200);
frame.setLayout(new FlowLayout());
frame.add(btn1);
frame.setVisible(true);
t1.setName("Thread that I need to use when press button");
t1.start();
btn1.addActionListener((ActionEvent e) -> {
execute = true;
});
}
public void ExecuteActionInTheSameSecondaryThread(){
// Large method to execute withowt extrac the content
}
///// It works!!! Content of the method//////
boolean execute = false;
////////////////////////
Thread t1 = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
///// It works!!! //////
if (execute) {
execute = false;
System.out.println("Button pressed in: " + Thread.currentThread().getName());
}
////////////////////////
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
} catch (InterruptedException ex) {
Logger.getLogger(Utils.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}

Related

How do I make a loop start and end with a key press and release?

Here is my code... How can I make it work so that it runs the loop while the user is holding a button and stops when the user releases the button?
public void nextPrimeNum()
{
x = false;
int b = 2;
ArrayList<Integer> next = new ArrayList<Integer>();
while(x)
{
next = factors(b);
if(next.size()==2)
{
System.out.println(b);
}
b++;
}
System.out.println("End");
}
public void keyPressed(KeyEvent e)
{
if(e.getKeyCode() == 401)
{
x = true;
}
}
public void keyRealesed(KeyEvent e)
{
if(e.getKeyCode() == 402)
{
x = false;
}
}
GUI and multi-thread programming is inherently difficult.
So, this is as simple as it could be, without violating best practices too much.
You need several things:
A separate Thread for printing primes:
Its run method loops for ever, but pauses when the Space key is not pressed.
(see Defining and Starting a Thread for more info)
A KeyListener which will be called from AWT's event dispatch thread:
The event handling methods are designed to finish fast, so that other events
(like moving, resizing and closing the frame) still are handled fast.
(see How to Write a Key Listener
and The Event Dispatch Thread for more info)
A visible GUI component (JFrame) for adding the KeyListener
Some synchronization between the 2 threads (via synchronized, notify and wait)
so that the prime-printing starts/continues on keyPressed
and suspends on keyReleased
(see Guarded Blocks for more info)
Initialize and start the whole GUI by invoking initGUI.
(see Initial Threads for more info)
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Main implements Runnable, KeyListener {
public static void main(String[] args) {
SwingUtilities.invokeLater(Main::initGUI);
}
private static void initGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new JLabel("Press SPACE key for printing primes"));
frame.pack();
frame.setLocationRelativeTo(null); // center on screen
frame.setVisible(true);
Main main = new Main();
frame.addKeyListener(main);
Thread thread = new Thread(main);
thread.start();
}
private boolean spaceKeyPressed;
private boolean isPrime(int n) {
for (int i = 2; i < n; i++) {
if (n % i == 0)
return false;
}
return true;
}
#Override
public void run() {
for (int n = 2; /**/; n++) {
while (!spaceKeyPressed) {
synchronized (this) {
try {
wait(); // waits until notify()
} catch (InterruptedException e) {
// do nothing
}
}
}
if (isPrime(n)) {
System.out.println(n);
}
}
}
#Override
public void keyTyped(KeyEvent e) {
// do nothing
}
#Override
public synchronized void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
spaceKeyPressed = true;
notifyAll(); // cause wait() to finish
}
}
#Override
public synchronized void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
spaceKeyPressed = false;
notifyAll(); // cause wait() to finish
}
}
}
So, the answer is - it's complicated. It covers broad topics such as concurrency (in general), GUI development, best practices with the specific API (Swing) which are better covered in more detail by reading through the various tutorials (and experimenting)
Concurrency
Creating a GUI With JFC/Swing
Concurrency in Swing
Worker Threads and SwingWorker
How to Use Actions
How to Use Key Bindings
The example presents two ways to execute the "loop" (which is presented in the doInBackground method of the CalculateWorker class).
You can press and hold the JButton or press and hold the [kbd]Space[kbd] bar, both will cause the "main loop" to run, updating the JTextArea with the results...
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
private CalculateWorker worker;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(20, 20);
ta.setEditable(false);
add(new JScrollPane(ta));
worker = new CalculateWorker(ta);
JButton btn = new JButton("Press");
btn.getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
System.out.println("...isRunning = " + worker.isRunning());
if (!worker.isRunning()) {
return;
}
System.out.println("...isPressed = " + btn.getModel().isPressed());
System.out.println("...isPaused = " + worker.isPaused());
if (btn.getModel().isPressed()) {
worker.pause(false);
} else {
worker.pause(true);
}
}
});
add(btn, BorderLayout.SOUTH);
worker.execute();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, false), "Space.released");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0, true), "Space.pressed");
am.put("Space.released", new CalculateAction(false, worker));
am.put("Space.pressed", new CalculateAction(true, worker));
}
public class CalculateWorker extends SwingWorker<List<String>, String> {
private AtomicBoolean run = new AtomicBoolean(true);
private AtomicBoolean paused = new AtomicBoolean(false);
private ReentrantLock pausedLocked = new ReentrantLock();
private Condition pausedCondition = pausedLocked.newCondition();
private JTextArea ta;
public CalculateWorker(JTextArea ta) {
this.ta = ta;
pause(true);
}
public void stop() {
run.set(false);
pausedLocked.lock();
pausedCondition.signalAll();
pausedLocked.unlock();
}
public void pause(boolean pause) {
paused.set(pause);
pausedLocked.lock();
pausedCondition.signalAll();
pausedLocked.unlock();
}
public boolean isPaused() {
return paused.get();
}
public boolean isRunning() {
return run.get();
}
#Override
protected List<String> doInBackground() throws Exception {
List<String> values = new ArrayList<>(256);
long value = 0;
System.out.println("!! Start running");
while (run.get()) {
while (paused.get()) {
System.out.println("!! I'm paused");
pausedLocked.lock();
try {
pausedCondition.await();
} finally {
pausedLocked.unlock();
}
}
System.out.println("!! Start loop");
while (!paused.get() && run.get()) {
value++;
values.add(Long.toString(value));
publish(Long.toString(value));
Thread.sleep(5);
}
System.out.println("!! Main loop over");
}
System.out.println("!! Run is over");
return values;
}
#Override
protected void process(List<String> chunks) {
for (String value : chunks) {
ta.append(value);
ta.append("\n");
}
ta.setCaretPosition(ta.getText().length());
}
}
public class CalculateAction extends AbstractAction {
private boolean start;
private CalculateWorker worker;
public CalculateAction(boolean start, CalculateWorker worker) {
putValue(NAME, "Calculate");
this.start = start;
this.worker = worker;
}
#Override
public void actionPerformed(ActionEvent e) {
worker.pause(start);
}
}
}
}
Is there a simpler solution?
Of course, I always go for the most difficult, hard to understand solutions first (sarcasm)
While it "might" be possible to reduce the complexity, the example presents a number of "best practice" concepts which you would do well to learn and understand.
The solution could also be done differently depending on the API used, so, it's the "simplest" solution for the specific API choice.
I wanted to do it from the console!
Java can't do that - it's console support is rudimentary at best and doesn't support a concept of "key pressed/released" actions (since it's running in a single thread, it would be impossible for it to do otherwise).
There "are" solutions you might try, but they would require a third party library linked to native binaries to implement, which would (possibly) reduce the number of platforms it would run on

How to terminate Java program without closing a window

I have created a Java application that goes through hundreds of documents after user clicks "Run" button. Is there a way to terminate the program and leave the GUI running? All I want to be able to stop is the process of reading the documents.
System.exit(0) is not the solution I am looking for as my whole app closes.
It's difficult to say something without to see your application. But probably this piece of code will help you to understand how to implement what you want:
import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.WindowConstants;
public class SwingWorkerTest implements Runnable {
private JButton cancelButton = new JButton("Cancel");
private JButton runButton = new JButton("Run");
private JLabel label = new JLabel("Press 'Run' to start");
private LongWorker longWorker;
#Override
public void run() {
JFrame frm = new JFrame("Long task test");
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
cancelButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
longWorker.terminate();
}
});
runButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
longWorker = new LongWorker();
runButton.setEnabled(false);
cancelButton.setEnabled(true);
label.setText("Task in progress. Press 'Cancel' to terminate.");
longWorker.execute();
}
});
JPanel bottomPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
bottomPanel.add(runButton);
bottomPanel.add(cancelButton);
frm.add(label);
frm.add(bottomPanel, BorderLayout.SOUTH);
frm.setSize(400, 200);
frm.setLocationRelativeTo(null);
frm.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new SwingWorkerTest());
}
private class LongWorker extends SwingWorker<Void, Void> {
private volatile boolean terminated;
#Override
protected Void doInBackground() throws Exception {
// check special variable tov determine whether this task still active
for (int i = 0; i < 1000 && !terminated; i++) {
readFile();
}
return null;
}
#Override
protected void done() {
if (terminated) {
label.setText("Process terminated. Press 'Run' to restart.");
} else {
label.setText("Process done. Press 'Run' to restart.");
}
cancelButton.setEnabled(false);
runButton.setEnabled(true);
}
// dummy method - make 10 milliseconds sleep
private void readFile() {
try {
Thread.sleep(10);
} catch (InterruptedException ex) {
// Nothing here
}
}
public void terminate() {
terminated = true;
}
}
}

Java Swing GUI -how to have a thread to be sleeping all time and be awaken by a click?

sorry but it's the first time i use Threads.
i want Parlami class thread to sleep and be awaken only by the actionListener.
I tried this way but it isn't working, he still sleeps.
Is it right to use thread this way or should i use wait() ?
package parlami;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* #author giacomofava
*/
public class Parlami
{
public boolean finito = false;
public String s="";
public void ascolta()
{
int i=0;
while (i<=1500)
{
// dormi 50 millisecondi
try
{
Thread.sleep(50);
i+=40;
}
catch (InterruptedException e)
{
}
while (voce.SpeechInterface.getRecognizerQueueSize() > 0)
{
s = s+"\n"+voce.SpeechInterface.popRecognizedString();
}
}
}
public String scrivi()
{
return "Hai detto: "+s;
}
public void leggi()
{
voce.SpeechInterface.synthesize(s);
}
public void dormi(int milli)
{
try
{
System.out.println("i'm sleeping");
Thread.sleep(milli);
}
catch (InterruptedException ex)
{
System.out.println("i'm awake ");
ascolta();
}
}
}
this is the gui:
public class GUI extends JFrame
{
private Parlami p;
private JPanel nord, centro;
private JButton registra, leggi;
private JTextArea display;
public static void main(String[] args)
{
new GUI();
}
public GUI()
{
p=new Parlami();
initComponents();
}
private void initComponents()
{
voce.SpeechInterface.init("./lib", true, true,"./lib/gram", "vocabolario");
// N O R D
nord=new JPanel();
display=new JTextArea("");
display.setForeground(Color.GREEN);
display.setBackground(Color.BLACK);
nord.setBackground(Color.BLACK);
nord.add(display);
// C E N T R O
centro=new JPanel();
registra=new JButton("tieni premuto per registrare");
registra.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e)
{
Thread.currentThread().interrupt();// <-------- HERE I TRY TO AWAKE HIM
display.setText(p.scrivi());
}
});
centro.add(registra);
leggi=new JButton("leggi");
centro.add(leggi);
this.setLayout(new BorderLayout());
this.add(nord, BorderLayout.NORTH);
this.add(centro, BorderLayout.CENTER);
this.setSize(700,300);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
p.dormi(50000); // <-------- HERE I TELL HIM TO SLEEP
}
}
If you call Thread.sleep on the Swing event thread, you will put the entire application to sleep rendering it useless, but more importantly, there's no need to do this. You simply have the ActionListener activate whichever object needs activation as this is how event-driven programming works.
If you need a delay in a Swing application, use a Swing Timer, something that has been discussed over and over again on this site.
This is a basic concept of thread wait/notify associated with the topic of thread locks. Basically, you have some common object which is acting as the "lock", one thread "waits" on this thread and when another thread needs to, it "notifies" the monitors that some action has occurred to which they should/can respond.
It'd start by having a look at Lock Objects for more details.
Below is a very basic example of the concept, a Thread is allowed to run continuously, but which "waits" on the common lock. The ActionListener of the button "notifies" the lock when it is pressed, allowing the Thread to continue working until, once again, blocks at the "wait"
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Thread t = new Thread(new Runner());
t.start();
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static final Object LOCK = new Object();
public class TestPane extends JPanel {
public TestPane() {
setLayout(new GridBagLayout());
JButton btn = new JButton("Press me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
synchronized (LOCK) {
LOCK.notifyAll();
}
}
});
add(btn);
}
}
public class Runner implements Runnable {
#Override
public void run() {
while (true && !Thread.currentThread().isInterrupted()) {
synchronized (LOCK) {
try {
System.out.println("Nothing to see here, just waiting");
LOCK.wait();
} catch (InterruptedException ex) {
}
}
System.out.println("Look at me, I'm busy");
}
}
}
}
Remember, Swing is single threaded, never perform any action which is blocking within the context of the Event Dispatching Thread, equally, never update the UI from outside the EDT.
If you need to update the UI for some reason from the other thread, then I suggest you have a look at SwingWorker, which will make your life much simpler. See Worker Threads and SwingWorker for more details.
You have an ActionListener which is notified when the button is activated, why do you need a monitor lock to perform the associated action? Does it take a noticeable amount of time to start the required action? You could just start a new thread when the button is clicked.
If you're waiting for some kind of timeout, then, to be honest, a Swing Timer is probably more suited to the task

Update label twice in one timer operation

I have a class Dmi,Swing components frame and a label.
I have Swing timer. In timer implementation I have two statements for setting text in the label, with a time interval, but I can only see the last setText operation.
import javax.swing.*;
import java.util.Timer.*;
import java.awt.event.*;
class Dmi implements ActionListener
{
Timer tim;
JFrame frame;
JLabel lbl;
Dmi()
{
frame=new JFrame("abc");
lbl=new JLabel("count");
frame.add(lbl);
frame.setVisible(true);
frame.pack();
tim=new Timer(1000,this);
tim.start();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent ae)
{
Thread th1=new Thread();
lbl.setText("abc");
try
{
th1.sleep(300);
}
catch (Exception e)
{
System.out.println(e);
}
lbl.setText("ddd:");
}
public static void main(String[] args)
{
new Dmi();
}
}
Start by taking a closer look at Concurrency in Swing and How to use Swing Timers
A Swing Timer will generate ActionEvents WITHIN the Event Dispatching Thread, which makes them really good for updating the UI from within.
However, your code...
public void actionPerformed(ActionEvent ae)
{
Thread th1=new Thread();
lbl.setText("abc");
try
{
th1.sleep(300);
}
catch (Exception e)
{
System.out.println(e);
}
lbl.setText("ddd:");
}
is blocking the Event Dispatching Thread (through the use of Thread#sleep), which will prevent the EDT from process new repaint events or any other user based events, making your program look as if it's hung.
You're either going to have to devise a solution which allows you to determine the amount of time the timer has been running and change the state based on that or possibly use a SwingWorker instead
For example...
import java.awt.EventQueue;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingWorker;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Dmi {
JFrame frame;
JLabel lbl;
Dmi() {
frame = new JFrame("abc");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
lbl = new JLabel("count");
frame.add(lbl);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
Worker worker = new Worker();
worker.execute();
}
public class Worker extends SwingWorker<String, String> {
#Override
protected String doInBackground() throws Exception {
while (!isCancelled()) {
Thread.sleep(1000);
publish("abc");
Thread.sleep(300);
publish("def");
}
return null;
}
#Override
protected void process(List<String> chunks) {
lbl.setText(chunks.get(chunks.size() - 1));
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Dmi dmi = new Dmi();
}
});
}
}

run function on JButton press

I'm attempting to make a program in java that uses a robot to press a specific key every few seconds. It has a GUI with a start and stop button and a label which tells which state its in. I've got everything working so far except that when I click "start" it runs the loop for my robot function (which is infinite) it doesn't enable the stop button like I thought it would. I know its something stupid with where the infinite loop is placed but I'm not sure how to make it work correctly.
I don't do a lot of java work, this was just a fun thing I thought to try but got stuck part way through. Any help is appreciated.
import java.awt.AWTException;
import java.awt.FlowLayout;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class Main extends JFrame {
/**
*
*/
private static final long serialVersionUID = 1L;
private static boolean running = false;;
private JButton start_button;
private JButton stop_button;
private JLabel tl;
private static int i = 0;
Robot robot;
void start() {
JFrame frame = new JFrame("Helper");
tl = new JLabel("Running: " + running);
start_button = new JButton("Start");
stop_button = new JButton("Stop");
stop_button.setEnabled(false);
frame.add(tl);
frame.add(start_button);
frame.add(stop_button);
frame.setSize(300, 100);
frame.setVisible(true);
frame.setLayout(new FlowLayout());
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
frame.setLocation(400, 400);
try {
robot = new Robot();
} catch (AWTException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
robot.setAutoDelay(200);
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
while (running) {
robot_loop(robot);
}
}
});
stop_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(true);
stop_button.setEnabled(false);
running = false;
tl.setText("Running: " + running);
}
});
}
public static void main(String[] args) {
new Main().start();
}
private static void robot_loop(Robot robot) {
robot.keyPress(KeyEvent.VK_NUMPAD0);
robot.keyRelease(KeyEvent.VK_NUMPAD0);
System.out.println("numpad 0 pressed! - " + i);
i++;
}
}
I've adapted my comment into an answer.
The actionPerformed method of those event listeners are invoked on Swing's event dispatch thread, and since you're entering into an infinite loop, it'll cause the GUI to freeze. You could create a thread inside of your actionPerformed method and do your work inside of the new thread. Though the next issue you'd run into is finding a nice way to stop the thread whenever the user presses the stop button.
What's cool is that you've already got all the logic to do this in your code. So getting it to work is as simple as changing:
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
while (running) {
robot_loop(robot);
}
}
});
To do your work on its own thread:
start_button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
start_button.setEnabled(false);
stop_button.setEnabled(true);
running = true;
tl.setText("Running: " + running);
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override public void run() {
while (running) {
robot_loop(robot);
}
}
});
}
});
The code above makes use of the executors framework (java.util.concurrent.*) rather than directly creating a thread. Another alternative as nachokk suggested would be to use a timer java.util.Timer or javax.swing.Timer (either should be fine in this case).
You can do something like this using SwingTimer
int delay = 400*1000;// you can inject this property
ActionListener taskPerformer = new ActionListener(){
#Override
public void actionPerformed(ActionEvent evt2) {
robot_loop(robot);
}
};
Timer timer = new Timer(delay, taskPerformer);
timer.start();

Categories