Вопрос по swing, timer, java, concurrency, event-dispatching – Правильно ли обновлять компоненты свинга?
Я новичок на качелях, любая помощь приветствуется.
В этом фрагменте кода я переворачиваю карту лицевой стороной вверх, если выясняется, что они не совпадают, я хочу, чтобы они снова повернули лицевой стороной вниз.
В момент, когда происходит: 1. при нажатии первая карта переворачивается 2. при нажатии второй карты происходит одно из двух: (а) если они одинаковые, они оба остаются, что я хочу (б), если они не совпадают, я никогда не вижу 2-ую карту вообще, так как она немедленно повторно отображает оборотную сторону карты (и оборотную сторону предыдущей карты также, как определено в моем методе).
Я думал, что включение таймера сна может держать 2-ую карту отображенной в течение некоторого времени, прежде чем вернуться, но это не так.
Я попытался использовать contentPane.revalidate (); & contentPane.repaint (); но это ничего не меняет.
Я вставил в некоторые выводы консоли:
Console output:
Card: 0 set
Card: 6 set
Sleeping now
Card: 6 unset
Card: 0 unset
Выше приведен результирующий вывод консоли при нажатии двух карт, которые не совпадают
@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");
}
}
}
потому что ваш графический интерфейс будет зависать. Вы должны использоватьТаймер качания, Что касается фоновых задач, о которых вам, вероятно, придется беспокоиться в будущем, взгляните наSwingWorker.
SwingWorker
покончено с этой простой проблемой
MadProgrammer
ЛЮБОЕ действие, которое вы предпринимаете, чтобы остановить EDT от выполнения этой работы, заставит ваше приложение выглядеть как зависшее.
Вы НИКОГДА не должны выполнять какие-либо трудоемкие операции (такие как ввод / вывод, циклы илиThread#sleep
например) на EDT, это сделает ваше приложение "паузой", которая никогда не бывает красивой.
ПрочитайтеПараллелизм в Swing для дополнительной информации.
Теперь у вас есть несколько вариантов. Вы могли бы использоватьThread
«ждать» в фоновом режиме и повернуть карты обратно, или вы могли бы использоватьSwingWorker
илиjavax.swing.Timer
.
Другая проблема, которую вы имеете, состоит в том, что вы НИКОГДА не должны обновлять какие-либо компоненты пользовательского интерфейса из любогоThread
кроме EDT. Это означает, что если бы вы использовалиThread
, вы станете ответственным за повторную синхронизацию этого потока с EDT. Хотя это и не сложно, это просто становится грязным.
SwingWorker
а такжеjavax.swing.Timer
есть функциональность, которая делает это намного проще.
Темы иSwingWorker
отлично подходят для выполнения фоновой обработки и будут просто излишними для этой проблемы. Вместо этогоjavax.swing.Timer
идеально подошло бы здесь.
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();
}
}
Это действительно простой пример. Возможно, вы захотите добавить некоторые элементы управления, которые не позволят пользователю нажимать что-либо, пока не сработает таймер, например;)