一般建议:
- 由于您已经摆脱了对 Scanner 的大部分使用(对您有好处!)和阻塞
while (true)
循环,目前您不需要使用后台线程。我会摆脱它,只在需要时使用它。
- 您的课程庞大且笨拙,这使我们(而且可能对您而言!)很难遵循所包含的逻辑。这是重构代码的原因之一,将其拆分为组成类,每个类都有自己的责任。
- 通过这样做,您将被迫使用非静态字段和方法,并消除您对静态的大部分使用——这是一件非常好的事情。
- 同样,使用数组和列表(如 ArrayLists)将帮助您消除冗余代码,从而使调试和修改更加容易。
具体建议:
- 你的程序逻辑只是做你告诉它做的事情。在您的代码中添加更多 println 语句以了解我的意思。如果你这样做:
actionPerformed 内部:
if ("choiceReroll".equals(area)) {
System.out.println("choiceReroll equals area");
if (e.getSource() == textYes) {
System.out.println("source is textYes");
rerollChoice("yes");
}
if (e.getSource() == textNo) {
rerollChoice("no");
}
}
您会看到当按下 textYes 按钮时调用了 rerollChoice("yes")。
继续用 println's 洒你的代码,看看我的意思。更具体的记录可能即将发布。或者更好——学习使用然后使用调试器。
编辑
例如,这里有一个稍微过长的示例程序,它显示了我的一些意思。请注意,它由几个类和枚举组成,后者保存对象的“状态”值。
好的,但是说真的,到目前为止,这是我写过的最好的骰子游戏程序。哈!
import java.awt.BasicStroke;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.*;
import javax.swing.border.Border;
/**
* DiceGame.java
* previously called Greed2.java
* http://stackoverflow.com/questions/17264671/why-is-my-swing-program-still-advancing
* @author Pete
* 6/24/2013
*/
public class DiceGame {
private static void createAndShowGui() {
DicePanel mainPanel = new DicePanel();
JFrame frame = new JFrame("Dice Game");
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(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
@SuppressWarnings("serial")
class DicePanel extends JPanel {
private static final String FIRST_ROLL_STATUS_TEXT = "Please select die to re-roll and press Second Roll";
private static final String RESET_STATUS_TEXT = "Please press the First Roll Button";
private static final String SECOND_ROLL_STATUS_TEXT = "Please press the Reset Button";
private Die[] dieArray = new Die[5];
private GameState gameState = GameState.FIRST_ROLL;
private JButton rollButton = new JButton();
private JButton exitButton = new JButton();
private JTextArea messageArea = new JTextArea(20, 60);
private Map<GameState, Action> rollActionMap = new HashMap<>();
private JLabel statusLabel = new JLabel(" ");
public DicePanel() {
rollActionMap.put(GameState.FIRST_ROLL, new RollAction(this, GameState.FIRST_ROLL));
rollActionMap.put(GameState.SECOND_ROLL, new RollAction(this, GameState.SECOND_ROLL));
rollActionMap.put(GameState.RESET, new RollAction(this, GameState.RESET));
exitButton.setAction(new ExitAction());
setLayout(new BorderLayout());
int gap = 3;
setBorder(BorderFactory.createEmptyBorder(gap, gap, gap, gap));
add(statusLabel, BorderLayout.NORTH);
add(new JScrollPane(messageArea), BorderLayout.CENTER);
add(createSouthPanel(), BorderLayout.SOUTH);
setGameState(GameState.RESET);
setGameState(GameState.FIRST_ROLL);
}
private JPanel createSouthPanel() {
int gap = 20;
JPanel diePanel = new JPanel(new GridLayout(1, 0, gap, gap));
for (int i = 0; i < dieArray.length; i++) {
dieArray[i] = new Die();
diePanel.add(dieArray[i].getDieLabel());
}
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, 10, 10));
buttonPanel.add(rollButton);
buttonPanel.add(exitButton);
JPanel southPanel = new JPanel(new BorderLayout());
southPanel.add(diePanel, BorderLayout.CENTER);
southPanel.add(buttonPanel, BorderLayout.SOUTH);
return southPanel;
}
public GameState getGameState() {
return gameState;
}
public void rollAll() {
for (Die die : dieArray) {
die.roll();
die.setSelectable(true);
}
}
public void rollSelected() {
for (Die die : dieArray) {
if (die.isSelected()) {
die.roll();
}
die.setSelected(false);
die.setSelectable(false);
}
}
public void setGameState(GameState gameState) {
GameState currentState = this.gameState;
this.gameState = gameState;
rollButton.setAction(rollActionMap.get(gameState));
if (currentState == GameState.RESET) {
reset();
} else if (currentState == GameState.FIRST_ROLL) {
firstRoll();
} else if (currentState == GameState.SECOND_ROLL) {
secondRoll();
}
}
private void firstRoll() {
rollAll();
statusLabel.setText(FIRST_ROLL_STATUS_TEXT);
}
private void secondRoll() {
rollSelected();
// TODO: calculate score and display
statusLabel.setText(SECOND_ROLL_STATUS_TEXT);
}
public void reset() {
for (Die die : dieArray) {
die.reset();
}
statusLabel.setText(RESET_STATUS_TEXT);
}
}
@SuppressWarnings("serial")
class RollAction extends AbstractAction {
private DicePanel dicePanel;
public RollAction(DicePanel dicePanel, GameState gameState) {
super(gameState.getText());
this.dicePanel = dicePanel;
putValue(MNEMONIC_KEY, gameState.getMnemonic());
}
@Override
public void actionPerformed(ActionEvent e) {
dicePanel.setGameState(dicePanel.getGameState().next());
}
}
@SuppressWarnings("serial")
class ExitAction extends AbstractAction {
private static final String EXIT = "Exit";
public ExitAction() {
super(EXIT);
putValue(MNEMONIC_KEY, KeyEvent.VK_X);
}
@Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor(((Component)e.getSource()));
win.dispose();
}
}
enum GameState {
FIRST_ROLL("First Roll", KeyEvent.VK_F), SECOND_ROLL("Second Roll", KeyEvent.VK_S),
RESET("Reset", KeyEvent.VK_R);
private String text;
private int mnemonic;
private GameState(String text, int mnemonic) {
this.text = text;
this.mnemonic = mnemonic;
}
public int getMnemonic() {
return mnemonic;
}
public String getText() {
return text;
}
public GameState next() {
int ordinal = ordinal();
ordinal++;
ordinal %= values().length;
return values()[ordinal];
}
}
class Die {
private static final int BORDER_GAP = 3;
private static final Border SELECTED_BORDER =
BorderFactory.createLineBorder(Color.red, BORDER_GAP);
private static final Border UNSELECTED_BORDER =
BorderFactory.createEmptyBorder(BORDER_GAP, BORDER_GAP, BORDER_GAP, BORDER_GAP);
private JLabel dieLabel = new JLabel();
private Random random = new Random();
private DieValue dieValue = DieValue.BLANK;
private boolean selectable = false;
private boolean selected = false;
public Die() {
reset();
dieLabel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent evt) {
if (selectable) {
setSelected(!selected);
}
}
});
}
public Component getDieLabel() {
return dieLabel;
}
public void setSelected(boolean selected) {
this.selected = selected;
Border border = selected ? SELECTED_BORDER : UNSELECTED_BORDER;
dieLabel.setBorder(border);
}
public void roll() {
int value = random.nextInt(6) + 1;
dieValue = DieValue.getDieValue(value);
dieLabel.setIcon(dieValue.getIcon());
}
public void reset() {
dieValue = DieValue.BLANK;
setSelected(false);
setSelectable(false);
dieLabel.setIcon(dieValue.getIcon());
}
public DieValue getValue() {
return dieValue;
}
public boolean isSelected() {
return selected;
}
public boolean isSelectable() {
return selectable;
}
public void setSelectable(boolean selectable) {
this.selectable = selectable;
}
}
enum DieValue {
BLANK(0, ""),
ONE(1, "One"), TWO(2, "Two"), THREE(3, "Three"),
FOUR(4, "Four"), FIVE(5, "Five"), SIX(6, "Six");
private static final int OUT_FRAME = 110;
private static final int ARC = 16;
private static final float STROKE_WIDTH = 4f;
private static final int SML_GAP = 2;
private static final int OVAL_RADIUS = 24;
private Icon icon;
private String name;
private int value;
private DieValue(int value, String name) {
this.value = value;
this.name = name;
this.icon = createIcon(value);
}
private Icon createIcon(int value) {
BufferedImage img = new BufferedImage(OUT_FRAME, OUT_FRAME,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
Stroke stroke = new BasicStroke(STROKE_WIDTH);
g2.setColor(Color.white);
g2.fillRoundRect(0, 0, OUT_FRAME, OUT_FRAME, ARC, ARC);
g2.setColor(Color.black);
g2.setStroke(stroke);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.drawRoundRect(SML_GAP, SML_GAP, OUT_FRAME - SML_GAP * 2,
OUT_FRAME - SML_GAP * 2, ARC, ARC);
g2.setColor(Color.black);
switch (value) {
case 1:
fillOval(g2, 1, 1);
break;
case 2:
fillOval(g2, 0, 0);
fillOval(g2, 2, 2);
break;
case 3:
fillOval(g2, 0, 0);
fillOval(g2, 1, 1);
fillOval(g2, 2, 2);
break;
case 4:
fillOval(g2, 0, 0);
fillOval(g2, 0, 2);
fillOval(g2, 2, 0);
fillOval(g2, 2, 2);
break;
case 5:
fillOval(g2, 0, 0);
fillOval(g2, 0, 2);
fillOval(g2, 1, 1);
fillOval(g2, 2, 0);
fillOval(g2, 2, 2);
break;
case 6:
fillOval(g2, 0, 0);
fillOval(g2, 0, 1);
fillOval(g2, 0, 2);
fillOval(g2, 2, 0);
fillOval(g2, 2, 1);
fillOval(g2, 2, 2);
break;
default:
break;
}
g2.dispose();
return new ImageIcon(img);
}
private void fillOval(Graphics2D g2, int row, int col) {
double rectWidth = OUT_FRAME - 4 * STROKE_WIDTH;
int x = (int) (2 * STROKE_WIDTH - OVAL_RADIUS / 2 + (col + 0.5) * rectWidth / 3);
int y = (int) (2 * STROKE_WIDTH - OVAL_RADIUS / 2 + (row + 0.5) * rectWidth / 3);
g2.fillOval(x, y, OVAL_RADIUS, OVAL_RADIUS);
}
public static DieValue getDieValue(int value) {
for (DieValue dieImage : DieValue.values()) {
if (dieImage.getValue() == value) {
return dieImage;
}
}
return null;
}
public Icon getIcon() {
return icon;
}
public String getName() {
return name;
}
public int getValue() {
return value;
}
}
这显示为:
第一卷:
第二卷:
重置: