I'm new to swing, any help appreciated.
In this piece of code I'm turning a card over face up, if it turns out that they don't match I want them to turn back face down again.
At the moment what is happening: 1. when clicked the first card turns over 2. when a second card is clicked either of two things happen (a) if they are the same they both stay up which is what I want (b) if they are not the same I never see the 2nd card at all as it immediately re-displays the back of the card (and the back of the previous card also as defined in my method).
I thought putting in the sleep timer might keep the 2nd card displayed for a period of time before turning back over but it does not.
I attempted to use contentPane.revalidate(); & contentPane.repaint(); but it doesn't change anything.
I have put in some console outputs:
Console output:
Card: 0 set
Card: 6 set
Sleeping now
Card: 6 unset
Card: 0 unset
Above is the resulting console output when clicking two card which do not match
@Override
public void actionPerformed(ActionEvent e)
{
String buttonPressed = e.getActionCommand();
int pos = Integer.valueOf(buttonPressed);
action = Control.model.ReceiveCardsTurned(pos);
keypadArray[pos].setIcon(myIcons[pos]);
System.out.println("Card: "+pos+" set");
currentTime.setText("" + Control.model.time);
currentScore.setText("" + Control.model.score);
//contentPane.revalidate();
//contentPane.repaint();
if(Control.model.twoCardsTurned == false)
{
if (action == "unturn")
{
System.out.println("Sleeping now");
try
{
Thread.sleep(1000);
}
catch (InterruptedException e1)
{
e1.printStackTrace();
}
keypadArray[pos].setIcon(back);
keypadArray[Control.model.lastCard].setIcon(back);
System.out.println("Card: "+pos+" unset");
System.out.println("Card: "+Control.model.lastCard+" unset");
}
}
}
There are a number of important concepts you seem to be missing.
ANY action you take that stops the EDT from carrying out this work will make your application look like it's hung.
You must NEVER carry out any time consuming operations (such as I/O, loops or Thread#sleep
for example) on the EDT, doing so will make your application "pause", which is never pretty.
Have a read through Concurrency in Swing for more information.
Now, you have a number of choices. You could use a Thread
to "wait" in the background and turn the cards back or you could use a SwingWorker
or a javax.swing.Timer
.
The other problem you have, is that you should NEVER update any UI components from any Thread
other than the EDT. This means if you were to use a Thread
, you would become responsible for re-syncing that thread with the EDT. While not difficult, it just becomes messy.
SwingWorker
and javax.swing.Timer
have functionality that make this much easier.
Threads and SwingWorker
are great for performing background processing and would simply be overkill for this problem. Instead, a javax.swing.Timer
would fit perfectly here.
if (!Control.model.twoCardsTurned)
{
if ("unturn".equals(action))
{
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent evt) {
keypadArray[pos].setIcon(back);
keypadArray[Control.model.lastCard].setIcon(back);
System.out.println("Card: "+pos+" unset");
System.out.println("Card: "+Control.model.lastCard+" unset");
}
}).start();
}
}
This is a really simple example. You might like to put in some controls that will prevent the user from clicking anything until the timer fires, for example ;)