Обновление JButton по таймеру в цикле do-while
У меня возникли проблемы с повторным обновлением JButton (используется с таймером) в цикле do-while. Я работаю над простой игрой, в которую играют по 10 * 10 сеткам объектов плиток, которые соответствуют массиву JButton arrayList с 100 кнопками.
Эта часть программы обрабатывает простое нахождение пути (т. Е. Если я нажимаю на символ, то на пустой плитке персонаж будет перемещаться по каждой плитке на пути к месту назначения). Между каждым шагом есть задержка, чтобы пользователь мог видеть прогресс персонажа.
В текущем положении вещей движение является правильным, но JButton обновляется только тогда, когда персонаж достигает цели, а не на промежуточных шагах.
public void move(int terrainTile)
{
int currentPosition = actorList.get(selectedActor).getPosition();
int movementValue = 0;
int destination = terrainTile;
int destinationX = destination / 10;
int destinationY = destination % 10;
do
{
currentPosition = actorList.get(selectedActor).getPosition(); // Gets PC's current position (before move)
System.out.println("Old position is " + currentPosition);
int currentX = currentPosition / 10;
int currentY = currentPosition % 10;
if(actorList.get(selectedActor).getCurrentAP() > 0)
{
movementValue = 0;
if(destinationX > currentX)
{
movementValue += 10;
}
if(destinationX < currentX)
{
movementValue -= 10;
}
if(destinationY > currentY)
{
movementValue += 1;
}
if(destinationY < currentY)
{
movementValue -= 1;
}
int nextStep = currentPosition + movementValue;
myGame.setActorIdInTile(currentPosition, -1); //Changes ActorId in PC current tile back to -1
scrubTiles(currentPosition);
actorList.get(selectedActor).setPosition(nextStep); // Sets new position in actor object
System.out.println("Actor " + selectedActor + " " + actorList.get(selectedActor).getName() + " position has been updated to " + nextStep);
myGame.setActorIdInTile(nextStep, selectedActor); // Sets ActorId in moved to Tile
System.out.println("Tile " + nextStep + " actorId has been updated to " + selectedActor);
buttons.get(nextStep).setIcon(new ImageIcon(actorList.get(selectedActor).getImageName()));
// If orthagonal move AP-4
if(movementValue == 10 || movementValue == -10 || movementValue == 1 || movementValue == -1)
{
actorList.get(selectedActor).reduceAP(4);
}
// If diagonal move AP-6
else
{
actorList.get(selectedActor).reduceAP(6);
}
System.out.println(actorList.get(selectedActor).getName() + " has " + actorList.get(selectedActor).getCurrentAP() + " AP remaining");
try
{
Thread.sleep(500); // one second
}
catch (Exception e){}
buttons.get(nextStep).repaint();
}
else
{
System.out.println(actorList.get(selectedActor).getName() + " has insufficient AP to move");
break;
}
}while(destination != (currentPosition + movementValue));
Что я пробовал:
buttons.get (NeXTSTEP).repaint(); (Попробовал поставить команду перекрасить кнопку после установки imageIcon. Без изменений.
buttons.get (NeXTSTEP).revalidate(); (Нет уверенности на 100%, что это делает - это было потенциальным решением, но оно не работает.
Шаги 1 и 2 в сочетании
Заглянул в класс свинг-таймера - движение не происходит каждый раз, когда срабатывает actionEvent (только если выбран персонаж и целевая плитка пуста), поэтому не уверен, как заставить это работать
Любая помощь будет принята с благодарностью!
2 ответа
Я действительно не знаю точно, что вы хотели знать в своих комментариях, хотя +1 к ответу выше, мне кажется, это реальная причина. Посмотрите на этот пример программы, просто добавьте свой звонок в move(...)
метод внутри timerAction
Кажется, что это может работать для вас. Вот попробуйте этот код:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GridExample
{
private static final int SIZE = 36;
private JButton[] buttons;
private int presentPos;
private int desiredPos;
private Timer timer;
private Icon infoIcon =
UIManager.getIcon("OptionPane.informationIcon");
private ActionListener timerAction = new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
buttons[presentPos].setIcon(null);
if (desiredPos < presentPos)
{
presentPos--;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos > presentPos)
{
presentPos++;
buttons[presentPos].setIcon(infoIcon);
}
else if (desiredPos == presentPos)
{
timer.stop();
buttons[presentPos].setIcon(infoIcon);
}
}
};
public GridExample()
{
buttons = new JButton[SIZE];
presentPos = 0;
desiredPos = 0;
}
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("Grid Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(6, 6, 5, 5));
for (int i = 0; i < SIZE; i++)
{
final int counter = i;
buttons[i] = new JButton();
buttons[i].setActionCommand("" + i);
buttons[i].addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
desiredPos = Integer.parseInt(
(String) buttons[counter].getActionCommand());
timer.start();
}
});
contentPane.add(buttons[i]);
}
buttons[presentPos].setIcon(infoIcon);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(1000, timerAction);
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new GridExample().createAndDisplayGUI();
}
});
}
}
Это потому, что вы делаете do { } в потоке пользовательского интерфейса. Чтобы решить эту проблему, вы должны использовать SwingWorker или javax.swing.Timer