Sleep a java thread but update jFrame first - java

I want to display a text before executing the function mediaPlayer(). During the execution of the mediaplayer, I sleep the thread. That's ok because nothing needs to happen then (then just need to listen).
However, the last text: "Listen to...", is not being displayed (except with a few seconds delay). It there a way to flush the jFrame first before the thread goes to sleep?
expText.setText("Listen to the song and give a rating when it finishes.");
startButton.setEnabled(false);
//play sound
try {
mediaPlayer();
//wait for the duration of the stimuli
Thread.sleep(stimDuration);
...

The setText won't display until the EDT renders another frame, which it can't do because it's busy sleeping for stimDuration amount of time.
Try to play the sound on a separate thread, play the sound on some other thread, detect when the sound stops, and then do another action on the EDT where you change expText back to the original text that you had.

The following combined use of Threads and Swing Timer solved the problem.
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
startButton.setEnabled(false);
startButton.setVisible(false);
buttonsPanel.setEnabled(false);
buttonsPanel.setVisible(false);
expText.setText("Listen to the song and give a rating when it finishes.");
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
t2.start();
Thread t1 = new Thread(new Runnable() {
public void run() {
// code goes here.
try {
mediaPlayer();
// Thread.sleep(5000);
} catch (Exception e1) {
e1.printStackTrace();
}
}
});
t1.start();
ActionListener taskPerformer = new ActionListener() {
public void actionPerformed(ActionEvent evt) {
//...Perform a task...
resultButtonGroup.clearSelection();
startButton.setEnabled(true);
startButton.setVisible(true);
buttonsPanel.setVisible(true);
}
};
Timer timer = new Timer(stimDuration ,taskPerformer);
timer.setRepeats(false);
timer.start();

Related

Is there a quick way to close a thread before the main code continues?

I have a students working on a Simon Game for a final project at school and I have tried all day to solve her problem.
She is trying to create the game Simon. The program randomly selects a sequence of colours and highlights those colours by changing the colours of the 4 coloured buttons from the regular colour to white for a few seconds and then back.
Instead of highlighting one colour at a time white, the programming is making all colours appear white at the same time. So users don't know the sequence.
I have been looking up issues with running multiple threads and have tried using the .join() function. However, when that is used no colours turn white.
//highlights the colours that are currently in the array
public void play() {
//loop through the array and look at all the colours so far
for(int i=0; i<round;i++){
//red is the position in the array
if(colours[i]==1){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
//change the colour of the red button to white
redButton.setBackground(Color.WHITE);
redButton.setOpaque(true);
//wait
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
//change the colour back
redButton.setBackground(Color.RED);
redButton.setOpaque(false);
}
});
sleep.start();
}
//yellow
else if(colours[i]==2){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
yellowButton.setBackground(Color.WHITE);
yellowButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
yellowButton.setBackground(Color.YELLOW);
yellowButton.setOpaque(false);
}
});
sleep.start();
}
//green
else if(colours[i]==3){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
greenButton.setBackground(Color.WHITE);
greenButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
greenButton.setBackground(Color.GREEN);
greenButton.setOpaque(false);
}
});
sleep.start();
}
//blue
else if(colours[i]==4){
Thread sleep=new Thread(new Runnable(){
#Override
public void run(){
blueButton.setBackground(Color.WHITE);
blueButton.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
blueButton.setBackground(Color.CYAN);
blueButton.setOpaque(false);
}
});
sleep.start();
}
}
}
the code there basically says.
for all the steps in the sequence start a thread each.
then each of those threads (all started very soon after each other and not before the previous completes.) set the background to white for 1 second then back.
Usually you want to update the ui in the background so that you can continue to interact, but in this case you are playing a sequence and don't want any input. if updating in the background is required put the whole loop in a thread and you will want to sleep between iterations of that loop. otherwise just do it in the main thread. once the sequence is done playing for the user it will pass control back to the event loop to wait for presses.
also the delay should be .3s < t < .5s 1 second is too long
While you want to change the color of each button for 1 second, your main thread is too fast and finish within that second. Thats why it seems all lights change at same time.
Simple solution is to also to make the outer thread sleep for some time but that will not gurantee sequence of the threads. I would suggest to use java.util.concurrent.CountDownLatch to make the outer thread wait for inner thread to finish.
for (int i = 0; i < round; i++) {
CountDownLatch countDownLatch = new CountDownLatch(1);
// red is the position in the array
if (colours[i] == 1) {
Thread sleep = new Thread(new Worker(redButton, Color.RED, countDownLatch))
sleep.start();
}
// yellow
else if (colours[i] == 2) {
Thread sleep = new Thread(new Worker(yellowButton, Color.YELLOW, countDownLatch))
sleep.start();
}
// green
else if (colours[i] == 3) {
Thread sleep = new Thread(new Worker(greenButton, Color.GREEN, countDownLatch))
sleep.start();
}
// blue
else if (colours[i] == 4) {
Thread sleep = new Thread(new Worker(blueButton, Color.CYAN, countDownLatch))
sleep.start();
}
countDownLatch.await();
}
}
class Worker implements Runnable {
Button button;
Color color;
CountDownLatch countDownLatch;
public Worker(Button button, Color color, CountDownLatch countDownLatch) {
this.button = button;
this.color = color;
this.countDownLatch = countDownLatch;
}
#Override
public void run() {
button.setBackground(Color.WHITE);
button.setOpaque(true);
try {
Thread.currentThread().sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
button.setBackground(color);
button.setOpaque(false);
countDownLatch.countDown();
}
}
As soon as the light changes color for 1 second you count down the latch using countDownLatch.countDown() you wait for count down to hit zero with countDownLatch.await() in outer thread.

How to set JLabel text to display before a system sleep

I'm trying to display the text of Successful Login before a system sleep for 3,000 miliseconds. Its not working when I place it right after the set text. How do I get it to display then pause so there is a bit of delay so the user knows that they loging in?
After the user correctly logs-in it will continue to a different class where the JFrame will close
l_Message.setForeground(Color.green);
l_Message.setText("Succesful Login");
try{
Thread.sleep(3000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
PLOGIN post_login = new PLOGIN();
post_login.postlogin_UI(login_JFrame);
See Concurrency in Swing for the reason why you're having problems
See How to use Swing Timers for a possible solution
import javax.swing.Timer
//...
l_Message.setForeground(Color.green);
l_Message.setText("Succesful Login");
Timer timer = new Timer(3000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
PLOGIN post_login = new PLOGIN();
post_login.postlogin_UI(login_JFrame);
}
});
timer.start();
Assuming that you are calling this from outside of the GUI thread(which I believe that you should be), you could try the following:
EventQueue.invokeLater(() -> {
l_Message.setForeground(Color.green);
l_Message.setText("Succesful Login");
});
try{
Thread.sleep(3000);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
PLOGIN post_login = new PLOGIN();
post_login.postlogin_UI(login_JFrame);
i.e. schedule GUI operations to the GUI thread

Why is my Thread making my JavaFX Application lag?

I'm trying to make an JavaFX application that tracks the movement of my mouse for this im using this code in the controller class:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}).start();
But it couses my application to lag big time.
How should i fix this lag problem?
Thanks i fixed it:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
}
});
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
What you doing is letting Javafx Application thread Thread.sleep(1000); <-wait
Any long term action you shoud put OUT of JFX-AT. And only update your ui components on it.
new Thread(()->{
while(Main.running){
Platform.runLater(()->{
//updateui component
//this is updating on FXAT
});
Thread.sleep(time)//This way you dont let JFXAT wait
}
}).start();
//Not sure if formatted and curly braces correctly.Bud you hopefully understand.Make sure you know which thread you let wait.Otherwise you wont be able to recieve events from paused jfxat.
You should put your Thread.sleep() call in your while loop and not in your Runnable, otherwise the loop keeps posting a lot of runLater tasks and those tasks stops the event thread for 1000ms after updating your mouse position
You call Thread.sleep(long) inside a Runnable that will be executed on the UI thread. If the thread is sleeping, it can't do anything else but sleep there. If you want your label to update every 1000 milliseconds, you can use the java.util.Timer class to make that happen.

How to deselect an item in a jList after a certain ammount of milliseconds on a mouseExit event

I have a jList called todoList
When the user click on an item in the list, it stays selected. But I would like the currently selected item in the list to deselect "by itself" after 400 milliseconds when the mouse exits the jList.
This must only run if there is something already selected in the list.
I am using Netbeans IDE and this is what is have tried so far:
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread = new Thread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
and
private void todoListMouseExited(java.awt.event.MouseEvent evt) {
if (!todoList.isSelectionEmpty()) {
Thread thread= Thread.currentThread();
try {
thread.wait(400L);
todoList.clearSelection();
} catch (InterruptedException ex) {
System.out.println(ex);
}
}
}
These both just make everything stop working.
My though process was that i need to create a new Thread that will wait for 400 milliseconds and then run the clearSelection() method of the jList. This would happen every time the mouse exits the list and run only if there is something in the list that is already selected.
I hope I am explaining my problem thoroughly enough.
The problem is that you are blocking the AWT-Event-Thread.
The solution is to use a swing timer:
private void todoListMouseExited(java.awt.event.MouseEvent evt)
{
if (!todoList.isSelectionEmpty()) {
new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
}).start();
}
}
The problem is that Object#wait is waiting(rather than sleeping) to be notified but this is not happening. Instead the timeout causing an InterruptedException bypassing the call to clearSelection.
Don't use raw Threads in Swing applications. Instead use a Swing Timer which was designed to interact with Swing components.
if (!todoList.isSelectionEmpty()) {
Timer timer = new Timer(400, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
todoList.clearSelection();
}
});
timer.setRepeats(false);
timer.start();
}

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