IllegalThreadStateException occuring again and again .. need to restart thread after stopping - java

need to make a music player as my simple java project. it opens up a file and loads the name in the text field.when play is pressed, the name is encircled in the textfield and when pause is pressed , the encircling suspends . play pause are JTogglebuttons and i have a button names stop. using multithreading, i m able to play and pause the string but after i press Stop once.. if again i open up a new music file and press play, it shows an illegalthreadstateexception.Please help me out here.. Note: i havent yet put in the code for playing music in it.. i will put it in once this problem is solved . thanks a lot for ur
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import sun.audio.*;
public class search extends Thread implements ActionListener
{
JFrame f;
JButton stop,open;
JToggleButton play;
JTextField tf,text;
JTextArea ta;
JLabel lab,lab1;
String str,dest;
JScrollPane scrol;
File fl;
int myfl=0,myfl1=0,myfl2=0;
search()
{
f=new JFrame("Music Player");
f.setLayout(null);
f.setSize(620,300);
play=new JToggleButton("play");
play.setBounds(100,150,270,30);
play.addActionListener(this);
f.add(play);
play.setEnabled(false);
stop=new JButton("stop");
stop.setBounds(400,150,120,30);
stop.addActionListener(this);
f.add(stop);
stop.setEnabled(false);
open=new JButton("open");
open.setBounds(100,200,420,30);
open.addActionListener(this);
f.add(open);
tf=new JTextField();
tf.setBounds(25,50,565,40);
tf.setFont(new Font("DK BabySitter",Font.BOLD,20));
tf.setHorizontalAlignment(JTextField.CENTER);
f.add(tf);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void actionPerformed(ActionEvent ae)
{
if(ae.getActionCommand().equals("open"))
{
FileDialog fd=new FileDialog(f,"Open Box",FileDialog.LOAD);
fd.setSize(300,300);
fd.setVisible(true);
String s1="mp3";
str=fd.getFile();
dest=fd.getDirectory()+fd.getFile();
if(str.toLowerCase().endsWith(s1))
{
tf.setText(str);
//pause.setEnabled(true);
play.setEnabled(true);
stop.setEnabled(true);
}
else
{
JOptionPane.showMessageDialog(f, "Select a valid file format");
}
}
if(ae.getActionCommand().equals("stop"))
{
play.setLabel("play");
myfl1=1;
tf.setText(" ");
stop();
}
if(ae.getActionCommand().equals("play"))
{
try
{
play.setLabel("pause");
if(myfl==1 && myfl1==0)
{
resume();
}
if(myfl==0 || myfl1==1)
{
start();
}
}
catch(IllegalThreadStateException e)
{
tf.setText("error a gya re");
Thread newth= new Thread();
newth.start();
}
}
if(ae.getActionCommand().equals("pause"))
{
play.setLabel("play");
myfl=1;
suspend();
}
}
public void run()
{
try
{
String rot=tf.getText();
char rotn[]=new char[rot.length()];
int flag=rot.length();
int move=0;
rotn=rot.toCharArray();
tf.setText(" ");
for(;;)
{
for(;;)
{
sleep(100);
tf.setText( tf.getText() + rotn[move]);
move++;
if(move==(flag-1))
{
move=0;
break;
}
}
tf.setText(" ");
}
}
catch(Exception e)
{
tf.setText("error occured");
}
}
public static void main(String args[])
{
try {
// Set System L&F
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
}
catch (UnsupportedLookAndFeelException e) {
// handle exception
}
catch (ClassNotFoundException e) {
// handle exception
}
catch (InstantiationException e) {
// handle exception
}
catch (IllegalAccessException e) {
// handle exception
}
new search();
}
}

You should not use Thread.stop(), Thread.suspend() or Thread.resume(). These methods are deprecated and explicitly documented to have severe implications (like potential deadlocks etc). See also Why are Thread.stop, Thread.suspend and Thread.resume Deprecated?.
In this specific case the exception occurs because you cannot start() a Thread more than once. You need to code your thread (or better yet: don't extend Thread, but implement Runnable) so that it handles the pause, start, stop etc of your application correctly without using the deprecated and dangerous methods of Thread.

The reason you're getting this error is that you're attempting to manually manipulate the state of the thread you're running in.
The methods you're using here are all deprecated - stop, resume, suspend - these should all be avoided.
A better way to think about how your program is running is that a thread is either alive or it isnt. It may not do anything within the actual run method while alive, but at no point are you pausing/suspending/stopping the actual thread - you're only pausing/stopping the application logic within.
A very quick fix to what you're seeing is to replace all stop/suspend/resume with the following:
private volatile boolean paused = false;
private void pausePlayer(boolean pause) {
this.paused = pause;
}
then everywhere you need to pause the player use:
pausePlayer(true);
and when you want to resume it use:
pausePlayer(false);
In the run method replace the 2nd for loop with:
for (; ; ) {
while(!paused) {
// do your work
Note though that I believe there are larger structural issues with the program as it stands - mixing normal Threads with Swing can be problematic. I would suggest you investigate using a SwingWorker instead, as this is explicitly designed for the sort of thing you're trying to do.

Related

When nothing to do, no update in java? That's maybe a bug?

I'm developing a game, what stops if the window lost the focus. The problem is when the focus is gained, it doesn't start. I simplyfied that part of my game, here is the code:
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import javax.swing.JFrame;
public class Main extends JFrame
{
static boolean running = true;
public static void main(String[] args)
{
Main main = new Main();
main.frameSetup();
while(true)
{
if(running)
{
System.out.println("running");
}
}
}
void frameSetup()
{
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(900, 600);
addFocusListener(new FocusListener()
{
public void focusGained(FocusEvent e)
{
System.out.println("focus gained");
running = true;
}
public void focusLost(FocusEvent areg0)
{
System.out.println("focus lost");
running = false;
}
});
setVisible(true);
}
}
output:
running
running
...
focus lost
focus gained
After the "focus gained" I expected to write the lot running again.
The game works, if I put something to the while(true) like a System.out.println:
while(true)
{
System.out.println("while true");
if(running)
{
System.out.println("running");
}
}
output:
running
while true
running
while true
...
focus lost
while true
while true
...
focus gained
running
while true
running
while true
...
I don't want to put that System.out.printline or whatever because it uses the processor...
So do you know something to fix this "bug"?
Try adding volatile to the definition of running. I believe the problem is that once running == false is detected, it's caching this value and never checking memory again.
at first look you need syncchronization
if only one thread is writting your boolean, you can use a volatile
(usually you do this to define a stop variable checked in the thread's main loop).
if you have multiple threads modifying the boolean, you should use synchronization
READ - MODIFY- WRITE can't be achieved with volatile
https://jorosjavajams.wordpress.com/volatile-vs-synchronized/

Breaking a Loop With a JButton

I'm creating a program for a game that clicks in random intervals for X seconds with Y time between each click. Here is the code that does this.
try {
Util.autoCode rand = new Util.autoCode();
Robot robot = new Robot();
int NoC;
NoC = Integer.parseInt(this.numberOfClicksTF.getText().trim());
if (NoC == 0) {
while (NoC == 0) {
// robot.mousePress(InputEvent.BUTTON1_MASK);
System.out.println("Infinite Press");
Thread.sleep(rand.clickDelay());
System.out.println("Infinite Release");
// robot.mouseRelease(InputEvent.BUTTON1_MASK);
Thread.sleep(rand.interval());
break;
}
} else {
for (int i = 0; i < NoC; i++) {
//robot.mousePress(InputEvent.BUTTON1_MASK);
System.out.println("Click Press");
Thread.sleep(rand.clickDelay());
System.out.println("Click Release");
// robot.mouseRelease(InputEvent.BUTTON1_MASK);
Thread.sleep(rand.interval());
}
}
} catch (AWTException ex) {
Logger.getLogger(MainFrame.class
.getName()).log(Level.SEVERE, null, ex);
} catch (NumberFormatException ex) {
Logger.getLogger(MainFrame.class
.getName()).log(Level.SEVERE, null, ex);
} catch (InterruptedException ex) {
Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
}
I commented out the mouse press and release just so I could do a check to make sure the timing was right, and that it would perform each click. This code is started by JButton in a JFrame. Whenever I press the start button, it starts the code and nothing but force closing it in Netbeans will stop it. The goal is to have a start button initiate, and a stop button interrupt the code, but not close the JFrame. I have been looking everywhere and haven't been able to find a straight answer.
Any help is welcomed and appreciated!
You need tu use SwingWorker, for example:
in your JFrame you may have a SwingWorker and it "builder" method:
private SwingWorker worker;
private SwingWorker getWorker() {
worker = worker == null ? worker = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
while (true) {
System.out.println("doInBackground!");
Thread.sleep(1000);
}
}
} : worker;
return worker;
}
now, in the swing main thread (used for visual components updates) you need to call the SwingWorker with your background task:
private void jButtonActionPerformed(java.awt.event.ActionEvent evt) {
if (getWorker().getState().equals(SwingWorker.StateValue.STARTED)) {
worker.cancel(true);
worker = null;
} else {
getWorker().execute();
}
}
You can click on the button as many times as you wish, the app will create and run a SwingWorker or kill and set to null the current SwingWorker.
Literally ran into your exact same problem this week trying to make almost the same thing. First, let me suggest reading up on multithreading in Java. It may seem complicated, but trust me it's necessary to understand why your program is not working. (I'll give a run down of what's happening below)
Essentially, your GUI is running on an Event Dispatcher Thread that needs to be separated from your robot. That is because when you call thread.sleep(), you essentially tell the GUI thread to sleep too, resulting in loss of GUI control. Start your robot and GUI in separate threads and have your JButtons invoke methods to get your robot thread to start and stop. For example:
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new GUI();
}
});
}
To create your GUI(I don't know what your GUI is like, so I just wrote new GUI() to substitute for how you created yours), that way it's in the thread it's supposed to be in. Then in your eventListener, spawn a new thread holding the robot object everytime the start button is pressed:
if(actionEvent.getSource().equals(playButton)) { //listening for the play button
if(robotThread == null) {
autoClicker= new AutoClicker();
Thread = new Thread(autoClicker);
Thread.start();
}
}
And initiate your robot object in the autoClicker() class like you did, and have autoClicker implement runnable.
public class AutoClicker implements Runnable{
private Robot robot;
public void run(){
try {
robot = new Robot();
} catch (AWTException e) {e.printStackTrace();}
//you need to learn about synchronization first
while(true){
synchronized(this){
//do clicks and stuff here
}
}
}
}
This way, your GUI and robots are in separate threads. In order to make JButtons start and stop your robot, you're going to need to learn synchronization to know how to properly multithread.
Another thing is that you should probably use the wait() method instead of sleep(), as sleep() would cause a lot more problems that's too much to go through in a single answer. Again, you need to learn concurrency/synchronization first.
If you want comment below and we can work out a way for me to DM you my code I'm working on right now, which is the exact same thing as you're trying to make. I can explain every part of it to you to help you on your way.

Java - Swing GUI doesn't load

I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker.
The clicker itself works, but my problem is that my GUI never shows up.
The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.
Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.
This is the code in the main program trying to run the GUI.
package autoclicker;
import java.awt.AWTException;
/**
* The main program for the autoclicker.
*/
public class AutoClicker {
public static void main(String[] args) throws AWTException {
Click click = new Click(true);
click.clicker();
try {
Swingerinos sw = new Swingerinos();
sw.initialize();
}
catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
}
}
And this is the whole GUI file.
package autoclicker;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Swingerinos extends Click implements WindowListener,ActionListener {
private int numClicks = 0;
TextField text;
private JFrame frame;
/**
* #wbp.nonvisual location=181,19
*/
private final JLabel lblAutoclicker = new JLabel("AutoClicker");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Swingerinos window = new Swingerinos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Swingerinos() throws AWTException {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 109);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.WEST);
JButton btnNewButton = new JButton("Toggle On / Off");
text = new TextField(20);
text.setLocation(100, 100);
btnNewButton.addActionListener( this);
btnNewButton.setToolTipText("Toggles the autoclicker on / off.");
panel.add(btnNewButton);
panel.add(text);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
toggle();
numClicks++;
text.setText(""+numClicks);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.
EDIT: I added the whole main program code, also this is the code for the autoclicker.
package autoclicker;
import java.awt.*;
import java.awt.event.InputEvent;
public class Click {
private boolean active;
private Robot robot;
public Click(boolean active, Robot robot) {
this.active = active;
this.robot = robot;
}
public Click() throws AWTException {
this(false, new Robot());
}
public Click(boolean active) throws AWTException {
this(active, new Robot());
}
//TODO: add click.toggle() to somewhere and control da clicker
public void toggle() {
active = !active;
}
public void clicker() {
while (active) {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.setAutoDelay(10000);
}
}
}
Expanding JB Nizet's comment(s) into an answer.
The immediate cause:
When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:
Click click = new Click(true);
click.clicker();
This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:
public void clicker() {
while (active) {
// <snip>
}
}
This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().
Simple solution
You could just set a fixed number of iterations:
public void clicker() {
int i = 0;
while (i < 100) { // iterate 100 times
// <snip>
++i;
}
}
Or using a for-loop (recommended):
public void clicker() {
for (int i = 0; i < 100; ++i) {
// <snip>
}
}
This eliminates the need for the active variable and hence the need for another thread.
A somewhat more complicated solution
If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.
Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:
Thread worker = new Thread(new Runnable() {
public void run() {
click.clicker();
}
});
This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.
As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com
1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.

Unexpected behavior of Java thread

I came across this interesting situation while answering this question.
Try this piece of poorly designed code -
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
class abc extends JFrame implements ActionListener
{
boolean button_clicked = false;
JButton b1;
abc(){
this.setSize (400, 400);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.createUI();
}
void createUI(){
this.setLayout(null);
b1 = new JButton("Click here");
b1.setSize(110,30);
b1.setLocation(10,210);
this.add(b1);
b1.addActionListener(this);
}
public boolean isButton_clicked()
{
return button_clicked;
}
public void setButton_clicked(boolean button_clicked) {
this.button_clicked = button_clicked;
}
public void actionPerformed(ActionEvent arg0) {
button_clicked = true;
}
}
Here's the main method.
class tempMain extends JFrame
{
public static void main(String[] args) throws Exception
{
abc temp = new abc();
temp.setVisible(true);
while(true)
{
// Thread.sleep(200);
if(temp.isButton_clicked())
{
JOptionPane.showMessageDialog(null, "Hello");
temp.setButton_clicked(false);
}
}
}
}
When I ran this on my Windows 7 machine, nothing happened for at least about a minute (I didn't wait after that) after I clicked the button.
Now, just make one small change -
Thread.sleep(200); // uncomment this from the main.
And surprisingly, it works and a JOptionPane message is displayed. Why is the message not displayed the first time?
And surprisingly, it works and a JOptionPane message is displayed. Why is the message not displayed the first time?
button_clicked is not marked as volatile and is being updated from a different thread than the main thread. Since the call-back is made from the event handler thread, the main thread will not see the update unless button_clicked is defined as a volatile boolean. Putting a sleep may allow a memory barrier to be crossed and button_clicked to be updated in the main thread luckily.
Here's some more reading about volatile and why it is important when we are dealing with multiple threads.
Another issue is that you have an infinite loop which is spewing messages to System.out. This completely blocks after a while because the console can't display lines that fast which stops the checking for the click.

Error when creating JFrame from JFrame

I have an application that is works fine and the JFrame for it is launched in the constructor of a GameInitializer class which takes in some config parameters. I have tried to create a GUI in which allows the user to specify these config parameters and then click submit. When the user clicks submit a new GameInitializer object is created. The error I am getting is:
Exception in thread "AWT-EventQueue-0" java.lang.Error: Cannot call invokeAndWait from the event dispatcher thread
at java.awt.EventQueue.invokeAndWait(Unknown Source)
at javax.swing.SwingUtilities.invokeAndWait(Unknown Source)
at game.player.humanplayer.view.HumanView.update(HumanView.java:43)
once submit is called this code is executed:
values assigned to parames...
new GameInitializer(userName, player, Constants.BLIND_STRUCTURE_FILES.get(blindStructure), handState);
Then code in the GameInitializer constructor is:
public GameInitializer(String playerName, AbstractPlayer opponent, String blindStructureConfig, AbstractHandState handState){
beginGame(playerName, opponent, blindStructureConfig, handState);
}
public static void beginGame(String playerName, AbstractPlayer opponent, String blindStructureConfig, AbstractHandState handState){
AbstractDealer dealer;
BlindStructure.initialize(blindStructureConfig);
AbstractPlayer humanPlayer = new HumanPlayer(playerName, handState);
AbstractPlayer[] players = new AbstractPlayer[2];
players[0] = humanPlayer;
players[1] = opponent;
handState.setTableLayout(players);
for(AbstractPlayer player : players){
player.initialize();
}
dealer = new Dealer(players, handState);
dealer.beginGame();
}
It basically cascades down and eventually calls this piece of code in the HumanView class:
public void update(final Event event, final ReadableHandState handState, final AbstractPlayer player) {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
gamePanel.update(event, handState, player);
validate();
}
});
} catch (InterruptedException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
if(event.equals(Event.HAND_ENDING)){
try {
if(handState.wonByShowdown() || handState.isSplitPot()){
Thread.sleep(3500);
}
else{
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Do you have any idea why?
The point of invokeAndWait() is for another thread to wait for something to be done in the event dispatching thread (EDT). Since this code is already executing on the EDT, it's sufficient to call it directly rather than creating a Runnable.
So this code should not be surrounded by anything:
gamePanel.update(event, handState, player);
validate();
It looks like you're already in the Swing thread, so you're asking the Swing thread to wait while you do code in the Swing thread. This won't work. You need to remove the code surrounding
gamePanel.update(event, handState, player);
validate();

Categories

Resources