I have a method here that creates 52 JButtons in a loop. When a button is clicked, according text is displayed on it. After two buttons' text has changed, the program sleeps for 1 seconds (to give the user time to look at them). However, the program sleeps before the button text change animation finishes and ends up not showing the text on the second button:
for(int i=0; i<52; i=i+1){
//button creation
final int a=i;
JButton button_one=new JButton();
buttons[a]=button_one;
mainpanel.add(button_one);
button_one.addActionListener(new ActionListener(){
// what happens when the button is clicked
@Override
public void actionPerformed(ActionEvent button_picked){
amount_of_cards_picked=amount_of_cards_picked+1;
cardamountcheck();
String selectedcard=null;
if(twocardspicked==true){
userpick2=a;
selectedcard=setoutcards[userpick2];
System.out.println(selectedcard);
// button shows name of card
buttons[a].setText(selectedcard);
pairdetermination();
pairprobability();
}
else if(twocardspicked==false){
userpick1=a;
selectedcard=setoutcards[userpick1];
System.out.println(selectedcard);
System.out.println(cardspritesmap.get(selectedcard));
buttons[a].setText(selectedcard);
// the two changed text buttons are stored in an array
}
if(twocardspicked==true){
pickedcardbuttons[1]=buttons[a];
}
else if(twocardspicked==false){
pickedcardbuttons[0]=buttons[a];
}
// sleep method is called
oncardflipped(selectedcard);
}
});
}
This is the method that starts the Thread.sleep():
public void oncardflipped(String card){
if(twocardspicked==true){
// if there are two cards picked, the sleep is activated
try{
Thread.sleep(1000);
}
catch(InterruptedException ex){
Thread.currentThread().interrupt();
}
// once the sleep finishes, the text from the JButtons is removed.
pickedcardbuttons[0].setText("");
pickedcardbuttons[1].setText("");
}
}
The program works exactly how I want it to, the only problem is that the program doesn't give enough time to actually display the text.
This is what happens: The buttons before they are clicked
After one button is clicked (ok so far)
and then the buttons return to not having any text.
By calling Thread.sleep
on the Swing event thread, you are putting the entire GUI to sleep, meaning it cannot do any key actions of updating the GUI or interacting with the user until the sleep time is over. The solution is to never do this. If you need to have a time delay in a Swing GUI, there is a Swing tool created explicitly for this, a Swing Timer: Swing Timer Tutorial
The underlying mechanism is to give the timer a delay time in microseconds as its first constructor parameter, and give it a call back method as an ActionListener as its second parameter. Set it to non-repeating, and call .start()
on it. The call-back should do the actions that you desire after the delay time has finished.
For example, something like:
public void oncardflipped(String card) {
if (twocardspicked) {
int delay = 1000;
Timer timer = new Timer(delay, e -> {
// the actionPerformed call-back code
pickedcardbuttons[0].setText("");
pickedcardbuttons[1].setText("");
});
timer.setRepeats(false);
timer.start();
}
}
Note that you should not use a java.util.Timer
, the other main Java Timer class, since while this sort-of works, it is not Swing thread-safe.