Stopping a for loop with a button - java

I am trying to stop a for loop that is initiated by pressing a button. The only problem I have found is that the application is literally non-responsive once the start button is pressed. How would I go about making the stop button? At the moment the only way I can stop the application outside of my IDE is to go into task manager and forcibly delete it.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
String L = "Hello";
int Num = Integer.parseInt(m1.getText());
int Num2 = Integer.parseInt(m2.getText());
nu = Num;
for (int kk = nu; nu > 0; nu--) {
if (O1.isSelected()) {
for (int num3 = nu; nu > 0; nu--) {
try {
try {
Thread.sleep(Num2 * 1000);
} catch (InterruptedException ex) {}
Robot robot = new Robot();
robot.keyPress(KeyEvent.VK_F);
} catch (AWTException e) {
e.printStackTrace();
}
}
}
}
This is the code I have, I have been looking around and I think I need to use the SwingWorker class. I am not sure how to implement it though.

Have you put your loop inside the button action handler?
If so remove it and put it in a thread. Else it will block the EDT and app will become unresponsive. Use buttons only to trigger start and stop.

Without code it is hard to determine, but you are probably performing the loop on AWT thread, hence your UI is blocked and you can not press a button.
You should move your endless loop to another Thread, and then the button will work

You are entering in an infinite loop any how. I would suggest to put your loop in a separate thread and when you want to stop it just interrupt that thread on button click.

Move the code into a dedicated thread and use a variable check to end the loop externally.
The first problem is that you're performing this loop inside the Event Dispatch Thread (EDT). This is a thread which is dedicated to handling the user interface. Since you are looping and sleeping in this thread, it is unavailable to handle any other user interactions. So effectively you are locking yourself out of your own program.
The proper way to shut this down is to create a shutdown() method on the loop which will modify a variable that is checked in each iteration of the loop. Then, when you want to shut it down, you just call this method on the Runnable and the loop shuts down.
public class KeyPressRunnable implements Runnable {
private boolean isRunning = true;
public void shutdown() {
this.isRunning = false;
}
#Override
public void run() {
// put your loop in here, and include this code in the loop:
if (!this.isRunning) break;
}
}

Related

JProgressBar moves instantly and not gradually (java)

I want to make a ProgressBar move gradually using a Jbutton. To achieve this I am using a for loop and the method Thread.sleep. The problem is that insted of moving a tiny bit every second (the progress bar) after pressing the button, the program waits until the loop finishes and then does instantly move the progress up. When I take the loop outside of the button listener it works as I want but I really need it to work when pressing the button. Here is the code:
progressBar.setOrientation(SwingConstants.VERTICAL);
progressBar.setMinimum(0);
progressBar.setMaximum(100);
progressBar.setValue(50);
panel1.setLayout(null);
panel1.add(progressBar);
progressBar.setBounds(40,6,100,100);
button1.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
int counter = 5;
for (int i = 0; i < 5; i++) {
progressBar.setValue(progressBar.getValue() + counter);
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
}
});
If anyone can help me I will be very grateful!
Your code runs on the Event Dispatcher Thread (EDT). That thread is responsible for handling events, but also for repainting. Because it's just one thread, the repainting only occurs after your method ends.
There are some ways to solve this. In your case, a javax.swing.Timer would probably be easiest. Instead of running the loop in a single method, the button click starts a timer that runs every second. When it's done the timer can cancel itself. A slightly more difficult alternative is to use a SwingWorker. You could publish data in the doInBackGround method, and override process to perform the updates to the progress bar.
For more information, please read Concurrency in Swing.

Java(Android) stuck in while loop

when I run my app it will continuously be stuck in a while loop. It should leave the while loop when a button is pressed, however even after pressing a button it continues to loop.
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
temp1 = button[0];
temp3 = button[0].getBackground();
state++;
}
};
while(state == 0) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
button[0].setOnClickListener(listener11);
}
variable:
state is an int temp1 is a button temp3 is a Drawable
the delay is there because I actually have 20 buttons and I have the setOnClickListeners for all the buttons inside that while loop so I think it causes it to crash without the delay. Another question would be is it possible to have the setOnClickListeners outside the while loop but still be able to check for button clicks inside the loop?
The problem is you are pressing the button while the thread is in a sleeping state causing the event to not be triggered and therefor the state to never change.
You should remove the while loop and just set all the listeners in a for loop:
for(int i = 0; i< button.length; i++) {
button[0].setTag(i);
button[0].setOnClickListener(listener11);
}
And then change your listener to be something like:
private boolean firstClick = true;
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
if(firstClick) {
firstClick = false;
temp1 = button[(int)view.getTag()];
} else {
temp2 = button[(int)view.getTag()];
}
}
};
I'm not sure exactly what the code is supposed to be doing because I have no idea of the context, but I think think you could remove the while loop altogether:
// initialize the listener
View.OnClickListener listener11 = new View.OnClickListener() {
#Override
public void onClick(View view) {
// add code that runs when button is clicked here
}
};
// now that we have the listener all set up we add it to the button, at which point it just keeps listening for you, no need to put the thread to sleep
button[0].setOnClickListener(listener11);
UPDATE:
So because you want to see if the second value matches the first value you could use a helper method:
private String firstValue = "";
public boolean isMatch(String mostRecentValue) {
boolean match = false;
if (firstValue.isEmpty()) {
firstValue = mostRecentValue;
} else {
match = firstValue.equals(mostRecentValue);
firstValue = "";
}
return match;
}
This method takes a value and if it is the first click the value is saved, if it is the second click it compares it with the first click and then resets the method. A boolean is returned false for no match, and true for a match. Call this method from within the onClick() method and pass in the buttons value. I've used String as an example value but you could use any object type.
I think you might be misunderstanding what setOnClickListener is doing. It's not handling the click, it is setting up the click handler. The line button[0].setOnClickListener(listener11); would be part of your activity initialisation and then not called again.
The reason you get stuck is because the main thread is busy in the while loop and isn't given an opportunity to process click events. Click events are handled on the main thread but only when it's not already busy doing something. In this case, it's forever busy in the while loop. For example, if the main thread was processing a method that would take 10 seconds to complete and you tap on a button 3 seconds into it, the button press wouldn't be handled for another 7 seconds. At which point, the previously set listener11 would be executed.
What you seem to be trying to achieve is already handled by the Looper. You need to be thinking in terms of event handling. So in other words, all your logic needs to go in listener11 or something similar.

Is it possible to pause a sleeping thread in Java

Edit, found a work around, code is posted at the bottom.
Is it possible to pause a thread that's in the middle of using thread.sleep(sleeptime)? And then when it's resumed, sleep for the remaining time?
I tried implementing the wait/notify set up here to pause a thread
How to pause/resume thread in Android?
However, it looks like it waits until thread.sleep is finished with it's sleeping time.
The reason why I am asking this because I am using a while loop inside a thread to play music from a play list, and I need the thread to sleep for the duration of the music track so that the music track finishes before the while loop plays the next song on the playlist.
For example, the while loop will play a song that has a duration of 50 seconds, so the thread.sleep method will pause the thread that contains the while loop. But, the user wants to the pause the song, and the whole play list 25 seconds into the song. So the user will press the pause button 25 seconds into thread.sleep's 50 second sleep. After the user unpauses, I would like the thread.sleep to continue the rest of 50 second wait (25 seconds left at this point) to complete playing the rest of the song. Then the while loop will play the next track on the playlist.
Runnable whilePlay2 = new Runnable() {
#Override
public void run(){
while (k <= myIntArray2.size()-1 ) {
System.gc();
if( myIntArray2.get(k)>count){
video_column_index = videocursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
videocursor.moveToPosition(myIntArray2.get(k)-count);
filename2 = videocursor.getString(video_column_index);
}
else{
music_column_index = musiccursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
musiccursor.moveToPosition(myIntArray2.get(k));
filename2 = musiccursor.getString(music_column_index);
}
try {
if (m2MediaPlayer.isPlaying()) {
m2MediaPlayer.reset();
}
m2MediaPlayer.setDataSource(filename2);
m2MediaPlayer.prepare();
m2MediaPlayer.start();
Thread.sleep(m2MediaPlayer.getDuration());
synchronized(Lock){
while(onS){
Log.i("should be", "waiting");
Lock.wait();
}
}
Log.i("what is on", "on is"+onS);
Log.i("k Check", "k is" +k);
} catch (Exception e) {
}
m2MediaPlayer.stop();
m2MediaPlayer.reset();
k++;
}
} //closes public void run(){
// TODO Auto-generated method stub
};
Thread whilePlay2T = new Thread(whilePlay2);
whilePlay2T.start();
And here is my pause button
public void onToggleClicked(View view) {
// Is the toggle on?
boolean on = ((ToggleButton) view).isChecked();
if (on) {
mMediaPlayer.pause();
length=mMediaPlayer.getCurrentPosition();
m2MediaPlayer.pause();
length2=m2MediaPlayer.getCurrentPosition();
synchronized (Lock){
onS=true;
}
} else {
mMediaPlayer.seekTo(length);
mMediaPlayer.start();
m2MediaPlayer.seekTo(length2);
m2MediaPlayer.start();
synchronized (Lock){
onS=false;
Lock.notifyAll();
}
}
}
EDIT
Looks like I can't use it. So now I am using a recursive function instead of a while loop to set up my play list. Here's what one of them looks like.
public void hiplaylist2(int t2) {
k=t2;
if(k <= myIntArray2.size()-1 ){
System.gc();
if( myIntArray2.get(k)>count){
video_column_index = videocursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
videocursor.moveToPosition(myIntArray2.get(k)-count);
filename2 = videocursor.getString(video_column_index);
}
else{
music_column_index = musiccursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
musiccursor.moveToPosition(myIntArray2.get(k));
filename2 = musiccursor.getString(music_column_index);
}
try {
if (m2MediaPlayer.isPlaying()) {
m2MediaPlayer.reset();
}
m2MediaPlayer.setDataSource(filename2);
m2MediaPlayer.prepare();
m2MediaPlayer.start();
//Thread.sleep(mMediaPlayer.getDuration());
//SystemClock.sleep(mMediaPlayer.getDuration());
Log.i("k Check", "k is" + k);
} catch (Exception e) {
}
}
m2MediaPlayer.setOnCompletionListener(new OnCompletionListener()
{
public void onCompletion(MediaPlayer m2MediaPlayer){
m2MediaPlayer.stop();
m2MediaPlayer.reset();
if(k < myIntArray2.size()-1 ){
k++;
hiplaylist2(k);
}
}
});
};
And then I ues a thread to have more than one of these run at the same time.
I don't really get it. I'm not sure about what you want to do, but i guess that there are at least two problems into your algorithm.
Firstly, when you work on concurrent tasks take care of your race conditions, your m2MediaPlayer seems to be one of them.
Concerning your Thread.sleep(m2MediaPlayer.getDuration()); I believe that you shouldn't do it this way, if you want to wait until your song is finished you just have to :
Launch your song from Thread 1
Pause your Thread 1 (wait)
The song is playing in Thread 2
When the song is finished wake up (notify) your Thread 1 from Thread 2 (and let T2 die)
Note that you have to keep your code as simple as you can, because concurrency is hell.
Is it possible to pause a thread that's in the middle of using thread.sleep(sleeptime)? And then when it's resumed, sleep for the remaining time?
Assuming that you are asking about the behaviour of the Java runtime libraries, then the answer is No.
There is no safe way to pause and resume a thread. The Thread suspend / resume methods for doing this are unsafe and were deprecated in Java 1.1. (Read this if you want an explanation.)
Even if you use the unsafe methods, they do not magically pause a sleep timer. In fact, it is not clear what would happen to a sleeping thread: it is not specified.
Indeed, I would not totally be surprised if you found that a sleeping thread whose sleep time expired while suspended never woke up ...
I'll leave it to others to deal with the rest of your question.
(I can't figure out from your description what it is you are trying to do here ... and why you even need to pause a sleeping thread. On the face of it, it sounds like you should be using wait / notify or a higher level synchronization class ... rather than sleeping. The fact that you apparently tried and failed does not make that the wrong solution.)

While loop makes applet white screen and unresponsive

Here is my loop code (This is the only code relating to my loop):
while(true)
{
try {
Thread.sleep(20);
System.out.println("1");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I launch the applet, it white screens and I cannot close it unless I press the "Terminate" button in eclipse.
You're blocking the UI Thread with an infinite while loop. You don't say whether you're using an AWT or Swing applet, either way the result will be the same. If you're using a Swing applet, use a Swing Timer. If you're using the old heavyweight AWT, convert it to Swing and follow the previous advice.
As said you made an infinity loop with:
while(true){
//something
}
There is no break; So why or what should stop the loop except of a thrown exception?
To see when a InterruptedException is thrown you should read the JavaDoc:
http://docs.oracle.com/javase/7/docs/api/java/lang/InterruptedException.html
You are hogging the applets EDT. You need to run your loop in another thread. Try adding Thread gameThread; as a variable and use
gameThread = new Thread() {
public void run() {
while (condition) {
//code here
}
}
}
and then gameThread.start() both in your applet start method and gameThread.join() in your applet stop method.

How do you repaint a container immediately as components are added in a separate thread in JAVA?

I am using java.
I have a click event that adds "squares" to a container, in a loop. I want each square to show up RIGHT when it is added. I tried running the 'adding of the squares' in a separate thread, but it is not working.
Here is some code I use for 'public class GuiController implements ActionListener, MouseListener':
#Override
public void mouseClicked(MouseEvent e)
{
//createBoardPane();
new Thread
(
new Runnable()
{
public void run()
{
showAnimation();
}
}
).start();
}
public void showAnimation()
{
for(int i = 0; i < model.getAnimationList().size(); i++)
{
String coord = model.getAnimationList().get(i);
int x = Integer.parseInt(coord.substring(0, coord.indexOf(',')));
int y = Integer.parseInt(coord.substring(coord.indexOf(',') + 1, coord.length() - 2));
boolean shouldPlacePiece = (coord.charAt(coord.length() - 1) == 'p');
if(shouldPlacePiece)
{
model.getView().getBoardPane().getComponent(x + (y * model.getBoardSize())).setBackground(Color.BLACK);
}
else
{
model.getView().getBoardPane().getComponent(x + (y * model.getBoardSize())).setBackground(Color.WHITE);
}
model.getView().getBoardPane().repaint();
long time = System.currentTimeMillis();
while((System.currentTimeMillis() - time) < 250)
{
// wait loop
}
}
}
any help is appreciated!
Creating a separate Thread to run for this longish-running task was an excellent idea - unless you want to lock-up interactions with your GUI while doing your animation.
Now, Swing GUI objects are not Thread safe (with few exceptions), so you cannot work with them from a thread other than Swing's Event Dispatch Loop's thread. So take all the GUI update code in your for-loop, and wrap it with a new Runnable (yes, another one).
Then call SwingUtilities.invokeLater(Runnable doRun) with that Runnable on each iteration of the loop.
Your GUI update code will then be scheduled to run ASAP on the Event Dispatch Loop, which will occur while your worker thread goes to sleep (do you have anything against Thread.sleep?).
Alternative: Use SwingWorker instead of Thread
SwingWorker will create and manage a new the Thread for you, and publish data that it (SwingWorker) will cause to be run on the Event Dispatch Loop's thread. You'll override doInBackground with your code. Call publish with parameters to push across into the Event Dispatch Thread. Override process with code to process those parameters and update your GUI.
On gotcha with SwingWorker is that it accumulates published events over a period of about 33 milliseconds. If you're publishing more frequent than that you may get all your events bunched together every 33 milliseconds or so. In you case, 250 milliseconds between updates shouldn't be a problem.

Categories

Resources