java - 为什么我的 Swing 程序仍在推进?

标签 java swing actionlistener ioexception dice

所以我的程序使用附加了 actionListeners 的 JButtons,但是当程序到达某个点时它应该等待一个 Action 被执行,它直接跳过等待,然后继续。我想知道是否是因为没有抛出 IOException,但如果我抛出它,它只会返回一堆错误,这会造成巨大的困惑。

是的,我知道我正在混合使用命令行和 swing。那是因为它最初是命令行,现在我正在让它 Swing 不定。

谁能指出更简单的方法来解决这个问题?

这是我的代码:

public static void choiceRerollDice() {
            if (!canRerollDiceOne && !canRerollDiceTwo && !canRerollDiceThree && !canRerollDiceFour && !canRerollDiceFive) {
            System.out.println("Sorry, but you may not reroll any more dice...");
            displayDiceValues();
            System.exit(0);
        }
        else {
    System.out.println("Would you like to reroll any (more) dice? (yes/no)");
            area = "choiceReroll";
            }
}

public static void rerollChoice(String choiceReroll) {
    switch (choiceReroll) {
                case "yes":
                    rerollDice();
                    break;
                case "no":
                    //endTurn();
                    displayDiceValues();
                    f.validate();
                    f.repaint();
                    //calculatePlayer1Score();
                    //System.out.println("Thank you for playing!");
                    //System.out.println("Goodbye!");
                    System.exit(0);
                    break;
                default:
                    invalidInput();
    }
}

public static void rerollDice() {
    Scanner is = new Scanner(System.in);
    System.out.println("Which dice would you like to reroll? (Click the box under the dice!)");        
    rollSel = is.next();
    switch (rollSel) {
        case "roll":
        if (willRerollDiceOne) {
            if (canRerollDiceOne) {
                diceOne = 0;
                rollDiceOne();
                canRerollDiceOne = false;
                box1.setEnabled(false);
            }
            else {
                System.out.println("error");
            }
        }

        else {
        }
        if (willRerollDiceTwo) {
            if (canRerollDiceTwo) {
            diceTwo = 0;
            rollDiceTwo();
            canRerollDiceTwo = false;
            box2.setEnabled(false);
            }
            else {
                System.out.println("error");
            }
        }
        else {
        }
        if (willRerollDiceThree) {
            if (canRerollDiceThree) {
            diceThree = 0;
            rollDiceThree();
            canRerollDiceThree = false;
            box3.setEnabled(false);
            }
        }
        else {
        }
        if (willRerollDiceFour) {
            if (canRerollDiceFour) {
            diceFour = 0;
            rollDiceFour();
            canRerollDiceFour = false;
            box4.setEnabled(false);
            }
        }
        else {
        }
        if (willRerollDiceFive) {
            if (canRerollDiceFive) {
            diceFive = 0;
            rollDiceFive();
            canRerollDiceFive = false;
            box5.setEnabled(false);
            }
        }
        else {
        }
        box1.setSelected(false);
        box2.setSelected(false);
        box3.setSelected(false);
        box4.setSelected(false);
        box5.setSelected(false);
        f.validate();
        f.repaint();
            break;
        default:
            System.out.println("Error...");
            break;
    }
    choiceRerollDice();
}

这是 JButton:

public static JButton textYes = new JButton("Yes");
public static JButton textNo = new JButton("No");

对于 actionListeners:

      textYes.addActionListener(this);
      textNo.addActionListener(this);

和 actionPerformed():

        if ("choiceReroll".equals(area)) {
            if(e.getSource() == textYes){
                rerollChoice("yes");
            }
            if(e.getSource() == textNo){
                rerollChoice("no");
            }
        }

但不是停下来等待输入:

        else {
    System.out.println("Would you like to reroll any (more) dice? (yes/no)");
            area = "choiceReroll";
            }

它只是继续到 rerollDice()

有什么想法吗?

最佳答案

一般建议:

  • 由于您已经摆脱了扫描器的大部分使用(对您有好处!)和阻塞的 while (true) 循环,目前您不需要使用后台线程。我会摆脱它,只在需要时使用它。
  • 您的类(class)庞大而笨拙,让我们(很可能对您也一样)很难遵循其中包含的逻辑。这是重构代码的原因之一,将其拆分为组成类,每个类都有自己的职责。
  • 通过这样做,您将被迫使用非静态字段和方法,并消除大部分对静态的使用——这是一件非常的好事。
  • 同样使用数组和列表(例如 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 散布您的代码,看看我的意思。可能会出现更具体的建议。或者更好——学习使用然后使用调试器。


编辑

例如,这里有一个稍微过长的示例程序,它显示了我的一些意思。请注意,它由几个类和枚举组成,后者用于保存对象的“状态”值。

好的,但说真的,到目前为止,这是我写过的最好的骰子游戏程序。哈!

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;
   }

}

这显示为:

第一卷: First Roll

第二卷: Second Roll

重置: Reset

关于java - 为什么我的 Swing 程序仍在推进?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17264671/

相关文章:

java - 如何将 actionlistener 放在 JOptionpane.showInputDialog 的 OK 按钮上?

java - 打印 JFrame 及其组件

java - 调整元素的大小和位置

java - JFrame方法问题

java - 如何删除文本文件java中的一行?

java - 在屏幕上拖动一个 jlabel

java - 带有计时器的按键监听器/ Action 监听器无法正常工作

Java while循环不循环

java - Hibernate:使用子查询时出错

java - 在 Java 中修剪二维数组的有效方法