Thread.sleep and hiding buttons - java

The problem that I have in my code is that when it runs the button.setVisible(true); it won't set the button to visible until all the other if statements are passed through which really confuses me.
I'm trying to make simon says, and what this try-catch does is that it makes the button in the sequence order blink so that the user can know which button it is that follows.
I'm new to programming so any tips and advises are welcome.
Thank you for taking a look!
try {
inputOrder.clear();
// System.out.println("THIS IS INPUT" + inputOrder);
Sequence.add(randomNumber());
int f = 0;
for (; f < Sequence.size(); f++) {
//Thread.sleep(2000);
if (Sequence.get(f) == 1) {
try {`
btnNewButton.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
Thread.sleep(1000);
System.out.println("it ran here");
btnNewButton.setVisible(true);
}
if (Sequence.get(f) == 2) {
try {
btnBlue.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}Thread.sleep(1000);
System.out.println("it ran here");
btnBlue.setVisible(true);
}
if (Sequence.get(f) == 3) {
try {
btnYellow.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}Thread.sleep(1000);
System.out.println("it ran here");
btnYellow.setVisible(true);
}
if (Sequence.get(f) == 4) {
try {
btnGreen.setVisible(false);
Thread.sleep(1000);
} catch (InterruptedException e1) {
}
Thread.sleep(1000);
System.out.println("it ran here");
btnGreen.setVisible(true);
}
System.out.println(Sequence);
// Order.add(getColor(Sequence.get(f)));
System.out.println(Order);
text.setText(String.valueOf(Order.size()));
}
btnNextRound.setVisible(false);
} catch (InterruptedException e1) {
e1.printStackTrace();
}

Looks like this happens because you are doing this operation in the UI thread, and it does not have time to execute EventQueue since you force to sleep the UI thread, due to this thread gets chance to actually do the paint once it finish all the sleep calls.
In order to get desired output, I think you should move the sleep logic into a separate thread or to a SwingWorker. If you moved the logic to a separate thread you need to use the EventQueue.InvokeLater to enable buttons.

The way that the Java Swing GUI works is that everything happens one after another. Only when the entire method you posted is finished will the next GUI events (such as the repainting events that need to occur to show that the button's not visible anymore). Doing a Thread.sleep just makes your method take longer to finish. The result is that your UI is frozen because no other events (such as mouse, keyboard, or repainting events) are able to run until after all of your sleep calls.
To perform animation in Java, you should use the javax.swing.Timer class rather than using Thread.sleep. Below I've posted a quick example of a timer that, when started, will cause a button to flash. This doesn't completely solve your problem (you're also looping, but you really need another timer to actually schedule when the buttons will flash so that they don't all happen at once).
import javax.swing.Timer
/**
* Timer that causes a button to flash (become invisible for 1 second, and then become visible again).
*/
public class ButtonFlashTimer extends Timer {
private final JButton buttonToFlash;
public ButtonFlashTimer(JButton button) {
super(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
// This method is called every 1000 ms (until we tell
// it to stop). This allows us to perform the next "step"
// in the animation.
boolean isVisible = buttonToFlash.isVisible();
if (isVisible) {
buttonToFlash.setVisible(false);
} else {
buttonToFlash.setVisible(true);
// Once we've flashed, stop the timer (don't keep flashing).
stop();
}
}
});
buttonToFlash = button;
// Become invisible immediately; the 1000 ms will be the time between the first
// call to the actionPerformed (which will set it as invisible) and the second
// call (which makes it visible again).
setInitialDelay(0);
setRepeats(true);
}
}

Related

Java Thread.sleep() within a for loop

public void playPanel() throws IOException{
for(int i = 0; i<listData.size(); i++){
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ascii.setText(listData.get(i));
}
}
What I'm trying to do is play through the listData ArrayList type, which was copied from the ascii JTextArea. Its supposed to be an animation, so when they hit play the function displays the first slide, waits a second, then the next slide, etc.
When I run this the only thing that happens is a pause with nothing on the screen changing until it displays only the final slide. I'm not sure what's wrong with it
You should never call Thread.sleep(...) on the Swing event thread unless your goal is to put the entire application to sleep, rendering it useless. Instead, get rid of the for loop, and "loop" using a Swing Timer. Something like this should work, or be close to a functioning solution (caveat: code has not been compiled nor tested):
int delay = 1000;
new Timer(delay, new ActionListener() {
private int i = 0;
#Override
public void actionPerformed(ActionEvent e) {
if (i < listData.size()) {
ascii.setText(listData.get(i));
} else {
((Timer) e.getSource()).stop();
}
i++;
}
}).start();

JLayer Player overwrites refesh of SWT widgets when placed in a loop

I am attempting to make an application that retrieves images and .mp3 files and transitions from one image to the next once the audio has finished. The underlying framework of how I transition between these images is a little convoluted, but I have managed to get an action in SWT that successfully enables me to manually transition from one to the next. However, a problem has arisen when I've tried to automate it; when placed into a loop, my playAudio() method begins before all of the calls I make in my displayShow() method have resolved, which results in a blank window, despite the audio still playing.
Here is the run method for the action that I want to start the show:
Action startAction = new Action("Start") {
public void run() {
//do {
displayShow();
playAudio();
//} while(true);
}
};
Here is playAudio(). I am able to PLAY the audio without incident:
public void playAudio() {
final String audio = "Happy_Birthday.mp3";
audioLatch = new CountDownLatch(1);
audioThread = new Thread() {
public void run() {
try {
Player player = new Player
(new BufferedInputStream
(new FileInputStream(audio)));
player.play();
audioLatch.countDown();
} catch (JavaLayerException e) {
} catch (FileNotFoundException e) {
} catch (Exception e) {
}
}
};
audioThread.start();
try {
audioLatch.await();
} catch (InterruptedException e) {
}
}
And here is displayShow():
private void displayShow() {
new Thread() {
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Control[] children = container.getChildren();
for (int i = 0; i < children.length; i++) {
children[i].dispose();
}
show.showSlide(container);
container.layout();
}
});
}
}.start();
}
show.showSlide returns a composite whose parent is container, which is the immediate child of the highest parent composite. Within the newly created composite, an image is added to a label and the label's parent is assigned to composite. I realize whether displayShow() is in a separate thread or not seems to be immaterial; this was just the last thing I tried.
It is not solely the addition of the loop that causes the refresh to not execute. The only way I can get the manual transition to work is if I remove the CountDownLatch from the playAudio() method. Were I to remove this latch, the only way to encase these two methods in a loop would be embedded while loops, which seem to hog a fair amount of the CPU and still does not solve my problem. Am I missing anything?
The audioLatch.await() is blocking the main program thread, this is the thread that all SWT operations run on so the Display.asyncExec runnables are just being queued until the thread is available.
If you really must wait in the playAudio method you could run the display event loop there until the background thread is finished:
while (! background thread finished)
{
if (!display.readAndDispatch())
display.sleep();
}

Button doesn't disable when function is called

I'm really lost with this:
In this Case the Button should diasable (btnStart.setEnable(false)) when it got clicked.
after this it should call a function, located in an other class.
Everything works, except that the btnStart doesn't disable on click but after the function ist called.
So this:
#Override
public void actionPerformed(ActionEvent buttonKLick) {
if(buttonKLick.getSource() == this.btnStart){
btnStart.setEnabled(false);
try {
Funktionen.fileFinder(Pfad); //The Function
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
Will call the function FileFinder and then disable the button although the button should be disabled before.
You've likely got a threading issue where your other method is taking time and locking up the Swing event thread, preventing Swing from properly painting the button as disabled. What happens if you use a background thread?
i.e.,
if(buttonKLick.getSource() == this.btnStart){
btnStart.setEnabled(false);
new Thread(new Runnable() {
public void run() {
try {
Funktionen.fileFinder(Pfad); //The Function
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}).start();
}
Edit:
Please be sure to read: Lesson: Concurrency in Swing.
No, it will disable the button right when you call setEnabled( false ). Just try calling isEnabled() before you call that function.
What you observe is that the button is only painted in disabled state after the function is executed. That is because your function occupies the one and only thread used to update the UI (the Event Dispatch Thread).
Solution: execute your function on a worker thread, for example using a SwingWorker. Also, read the Swing concurrency guide. This explains in more detail what I mentioned here

Smooth movement of JButton on an action

How can I smoothly move the JButton if action performed (eg the button is pushed). Here's my example but it doesnt work propely:
public void actionPerformed(ActionEvent event) {
for(int i = 0; i<50; i++){
ww.button.setLocation(ww.button.getLocation().x+1, ww.button.getLocation().y);//ww is a JFrame child
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
After action performed I get a delay in 20*50 ms and button location set in previous loc + 50px, without intermediate locations.
Always try to avoid Thread while working with Swing. In your code it will make main EDT thread to sleep and that's why you are not able to view intermediate locations. Try this with using Swing Timer and you will get it working as intended. Take a look here: How to Use Swing Timers and also try using Swing workers.

Changing color before removing button

I'm trying to create a button that changes color of the background and then removes itself from the JFrame after a set amount of time, but instead of changing color it just stays pressed for the duration of wait.
public void actionPerformed(ActionEvent e) {
setBackground(Color.red);
try{
Thread.sleep(10000);
}
catch (InterruptedException iE) {
}
frame.remove(this);
}
Can anyone see what im doing wrong?
Your sleep is occurring in the main UI thread, hence the reason the button just stays pressed. If you want a sleep you should create a new thread, get that to sleep, then from within that thread you can get the frame to remove the button.
new Thread() {
public void run() {
try {
Thread.sleep(10000);
// Now do what is needed to remove the button.
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}.start();

Categories

Resources