您要添加内重演代码的ActionListeners,被称为多次,并且这会导致在按钮按下时多次调用这些操作。
public void run() {
a = true;
// **************************************
// this add ActionListener gets called with every creation
// of a new Thread, and then calling .start() on the Thread
attack1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
healthleft = healthleft - 100;
}
});
// **************************************
// this code does not belong in an event-driven program
do {
healthleftbl.setText(healthleft + "/" + health);
if (healthleft <= 0) {
page.show(game, "map");
break;
}
System.out.println(healthleft);
} while (turn.getState() != null);
}
不要这样做。在程序设置期间添加一次ActionListeners,而不是在转身期间。此外,您的while (true)
循环不属于事件驱动的程序,相反,您应该将代码设置为状态模式,其中程序的行为(对用户输入的响应)会根据程序的状态进行更改。
例如:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.*;
import javax.swing.event.SwingPropertyChangeSupport;
public class Temp2 extends JPanel {
private CardLayout cardLayout = new CardLayout();
private GamePanel gamePanel = new GamePanel(this);
private IntroPanel introPanel = new IntroPanel(this);
public Temp2() {
setLayout(cardLayout);
add(introPanel, IntroPanel.class.getName());
add(gamePanel, GamePanel.class.getName());
}
public void showCard(String name) {
cardLayout.show(this, name);
}
private static void createAndShowGui() {
Temp2 mainPanel = new Temp2();
JFrame frame = new JFrame("Temp2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
@SuppressWarnings("serial")
class GamePanel extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 350;
public static final int DAMAGE_AMOUNT = 100;
private Temp2 temp2;
private Player2 player2 = new Player2();
private JLabel statusLabel = new JLabel();
public GamePanel(Temp2 temp2) {
this.temp2 = temp2;
player2.addPropertyChangeListener(Player2.HEALTH, new PlayerListener());
JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.LEADING, 5, 5));
statusPanel.add(new JLabel("Health"));
statusPanel.add(statusLabel);
displayHealth();
JPanel battlePanel = new JPanel(new GridBagLayout());
battlePanel.add(new JButton(new BattleAction("Battle", KeyEvent.VK_B)));
setLayout(new BorderLayout());
add(statusPanel, BorderLayout.PAGE_START);
add(battlePanel, BorderLayout.CENTER);
}
private void displayHealth() {
String healthText = String.format("%03d/%03d", player2.getHealth(), Player2.MAX_HEALTH);
statusLabel.setText(healthText);
}
public void reset() {
player2.setHealth(Player2.MAX_HEALTH);
temp2.showCard(IntroPanel.class.getName());
}
@Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class BattleAction extends AbstractAction {
public BattleAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
int health = player2.getHealth() - DAMAGE_AMOUNT;
player2.setHealth(health);
}
}
private class PlayerListener implements PropertyChangeListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
int health = (int) evt.getNewValue();
displayHealth();
if (health <= 0) {
reset();
}
}
}
}
@SuppressWarnings("serial")
class IntroPanel extends JPanel {
private Temp2 temp2;
public IntroPanel(Temp2 temp2) {
this.temp2 = temp2;
setLayout(new GridBagLayout());
add(new JButton(new GoToBattleAction("Go To Battle", KeyEvent.VK_G)));
}
private class GoToBattleAction extends AbstractAction {
public GoToBattleAction(String name, int mnemonic) {
super(name);
putValue(MNEMONIC_KEY, mnemonic);
}
@Override
public void actionPerformed(ActionEvent e) {
temp2.showCard(GamePanel.class.getName());
}
}
}
class Player2 {
// make health a "bound property" by using property change support and listeners
public static final String HEALTH = "health";
public static final int MAX_HEALTH = 800;
private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(this);
private int health;
public Player2() {
this.health = MAX_HEALTH;
}
public int getHealth() {
return health;
}
// notify all listeners if health changes
public void setHealth(int health) {
int oldValue = this.health;
int newValue = health;
this.health = health;
pcSupport.firePropertyChange(HEALTH, oldValue, newValue);
}
// allow outside code to listen for changes to all bound properties
// should also have the associated remove listener methods too
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String name, PropertyChangeListener listener) {
pcSupport.addPropertyChangeListener(name, listener);
}
}
见[检测/为挂Ç修复失去代码块的支架](http://meta.stackexchange.com/q/251795/155831),因为我不能再纠缠于此问题。 –
请参阅编辑以回答 –
我已经制作了一个新程序,显示了一个事件驱动的状态驱动代码示例。没有什么时候可以找到真正的循环。 –