Java - 写入标准?

时间:2012-05-19 02:31:46

标签: java swing stdin

我有一个应用程序,在这个应用程序中,让鼠标点击事件模拟用户输入某个字符串到标准输入是非常方便的。所以我想知道,有没有一种方法可以将代码写入标准中?我意识到这有点像黑客,但它对我需要做的事情非常有用。

编辑(回应气垫船的EDIT2):

感谢。我理解该代码如何防止人类玩家不应该移动。我不明白的是你是如何构想主要游戏循环的。你介意写代码来告诉我你在想什么吗?你只是想象一个忙碌的等待循环,不断产生新的计算机动作并调用你的Move()方法(大部分时间在等待人类玩家移动时被拒绝)?像这样的东西?

public void gameLoop()
{
   while (gameNotOver)
   {
      Move compMove = generateComputersNextMove();
      move(blackPlayer, compMove); // where the blackPlayer is the computerPlayer 
   }
}

3 个答案:

答案 0 :(得分:4)

你说:

  

基本上,我希望我的代码在某一点阻止并等待用户单击我的JFrame中的特定JLabel。一旦用户单击JLabel,我希望在获取单击的JLabel的id后恢复代码。我不知道怎么会这样做。之前的方式是,在代码中的那个时刻,用户只需键入一个id(以及Scanner&#39的next()方法块)。

您不希望阻止您的程序(不是在事件驱动的程序中),而是更改GUI的状态,并根据用户对此状态的输入作出响应。您尝试的解决方案是一种线性思维方式,并且不适用于Swing或其他事件驱动的GUI。

例如,作为一个简单的例子,考虑给你的程序一个布尔变量,

private boolean labelClicked = false;

在单击JLabel后,在JLabel的MouseListener中将此更改为true。然后,如果布尔值为真,则仅响应其他用户输入。

或另一种可能的解决方案:如果你想在按下JLabel之后激活JButton,那么禁用JButton,并在JLabel的MouseListener中调用JButton上的setEnabled(true)。

关键是要考虑事件驱动编程 在本论坛中提出这样的问题时,另一个关键不是向我们询问特定于代码的问题,而是针对特定行为的问题。这里真正的问题不是如何写入标准,而是如何让程序暂停并等待用户输入 - 这是一个很大的区别。

最后,如果您需要更具体和更好的建议,请填写我们问题的详细信息,如果有任何疑问,请务必提出问题。祝你好运!

编辑1
您可能会有几个类,包括管理此应用程序的GUI和非GUI类,非GUI类可以包括:

  • 玩家类:这可以是人或计算机
  • 棋盘类:国际象棋棋盘的逻辑(非gui)表示
  • Piece class:所有具体Pieces派生自
  • 的抽象类
  • ChessAI课程:这是你的AI课程,是为计算机确定下一个最佳动作应该是什么。
  • 游戏课:也许是本次讨论中最重要的课程,因为这将控制游戏流程并决定轮到你移动。

Game类将包含一个名为turn的玩家字段的字段,该字段将保留对任何人的引用。所以说你的Game类拥有两个Player变量,humanPlayer和computerPlayer。 turn变量将保存这些对象中的一个或另一个,并且Player如何响应将取决于轮流保持的对象。

Game类将有一个循环,一个游戏循环,在告诉humanPlayer对象和它们轮到它们移动的computerPlayer对象之间交替。

所以说它是计算机的转向,并且需要一段时间来计算下一个最佳动作。如果同时人类玩家试图在GUI上拖动棋子,GUI将通知游戏类人类移动的尝试,游戏类将检查它是否是人类的#'s;转(通过检查if (turn == humanPlayer))并且如果它不是人类的回合,游戏将通知GUI,并且GUI将把棋子设置回原来的位置并且可能弹出一个警告信息。

在计算机请求Game移动它之后,Game将告诉GUI移动计算机的部分,然后Game将设置turn = humanPlayer,现在允许人类玩家移动。在HumanPlayer尝试移动之后,GUI将告诉Game人类的移动尝试。游戏将检查它是否有效,如果是,将告诉computerPlayer它现在应该移动。

请注意,当我说"告诉"时,我的意思是它将在该对象上调用公共方法。

编辑2
我的意思是这样的:

public class Game {
   private Player whitePlayer;
   private Player blackPlayer;
   private Player turn;
   private Board board = new Board(); // non-GUI logical board
   private Gui gui; // the Swing GUI that displays all

   public Game(String humanPlayerName, boolean humanWhite) {
      if (humanWhite) {
         whitePlayer = new HumanPlayer(humanPlayerName, this);
         blackPlayer = new ComputerPlayer("Computer", this);
      } else {
         whitePlayer = new ComputerPlayer("Computer", this);
         blackPlayer = new HumanPlayer(humanPlayerName, this);
      }
   }

   public void start() {
      whitePlayer.setMyTurn(true); // tell white player to move
   }

   public void move(Player playerMakingMove, Move move) {

      // only respond if the right player is making the move
      if (turn == playerMakingMove) {
         // check if its a valid move
         // if so, tell GUI to make move
         // check if game over

         turn.setMyTurn(false); // current player's turn is over
         turn = (turn == blackPlayer) ? whitePlayer : blackPlayer; // swap players
         turn.setMyTurn(true); // tell other player, it's his turn

         turn.makeMove(); // *** added
      } else {
         // send message that it's not their turn to move
      }
   }
}

因此,如果人类玩家试图移动GUI将为人类玩家移动(...),但游戏对象不会响应,除非它实际上是人类的转向。

编辑3
添加到播放器的makeMove()方法 请注意,Game的move(...)方法可能是所需的所有游戏循环,特别是如果ComputerPlayer的makeMove(...)方法告诉AI引擎创建下一个最佳移动然后再次调用Game的move(...)方法:

abstract class Player {
   private String name;
   private boolean myTurn = false;
   protected Game game;

   public Player(String name, Game game) {
      this.name = name;
      this.game = game;
   }

   public abstract void makeMove();

   public boolean isMyTurn() {
      return myTurn;
   }

   public void setMyTurn(boolean myTurn) {
      this.myTurn = myTurn;
   }

   public String getName() {
      return name;
   }

}

class HumanPlayer extends Player {

   public HumanPlayer(String name, Game game) {
      super(name, game);
   }

   @Override
   public void makeMove() {
      // TODO: ask GUI to inform player that it's his turn to move and accept the move

   }


}

class ComputerPlayer extends Player {
   private ChessAi chessAi = new ChessAi();

   public ComputerPlayer(String name, Game game) {
      super(name, game);
   }

   @Override
   public void makeMove() {
      game.move(this, chessAi.calcBestMove());
   }

}

当他们发现移动时,两个玩家都会调用game.move(...),这会让游戏提示下一个玩家移动....直到游戏结束。

请注意,这不是一个正在运行的程序,并不是故意的,而是更多用于说明可能的游戏逻辑的模型。我没有做过这样的事情,并且可能有更好更清晰的方法来实现这一点,但我只是想在事件驱动的GUI程序中实现基于回合的逻辑的各种方法。

编辑4
编译并运行以下简单事件驱动的GUI:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class EventDrivenGui extends JPanel {
   private static final Color GO_COLOR = Color.green;
   private static final Color STOP_COLOR = Color.red;
   private static final int SIDE = 300;
   private static final int TIMER_DELAY = 4 * 1000; // change light every 4 seconds
   private boolean go = false;
   private JButton button = new JButton("Button");


   public EventDrivenGui() {
      add(button);
      button.addActionListener(new ButtonListener());
      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   protected void paintComponent(Graphics g) {
      super.paintComponent(g);
      Graphics2D g2 = (Graphics2D) g;
      g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

      Color color = go ? GO_COLOR : STOP_COLOR;
      g2.setColor(color);
      g2.fillOval(0, SIDE / 3, SIDE, SIDE);
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(SIDE, (4 * SIDE) / 3);
   }

   private class ButtonListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent arg0) {
         if (go) {
            JOptionPane.showMessageDialog(EventDrivenGui.this, "Button is Active");
         }
      }
   }

   private class TimerListener implements ActionListener {
      @Override
      public void actionPerformed(ActionEvent e) {
         // toggle go. if true, now false, and visa versa
         go = !go;
         repaint(); // redraw oval
      }
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            EventDrivenGui mainPanel = new EventDrivenGui();

            JFrame frame = new JFrame("EventDrivenGui");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.getContentPane().add(mainPanel);
            frame.pack();
            frame.setLocationByPlatform(true);
            frame.setVisible(true);
         }
      });
   }

}

您会看到JPanel中存在JButton。您可以随时按下按钮,但只有当灯光为绿色时才会响应(当布尔变量为真时)。这是一个例子,按钮的行为,无论它是否响应按下,取决于类的状态,是否真实。一旦GUI被设置 - 构造函数已经被调用,它被放置在JFrame中,并且被显示,没有代码阻塞或类似的东西。有一个Swing Timer,其唯一的工作就是切换go的值并重新绘制JFrame,但那就是它。

答案 1 :(得分:1)

看看JDialog http://docs.oracle.com/javase/6/docs/api/javax/swing/JDialog.html。它可以在Swing应用程序中阻塞而不会产生不必要的复杂情况。

答案 2 :(得分:0)

你必须重新考虑你的解决方案。考虑已经连接到键盘的标准,所以有一些东西已经写入标准版。抱歉,标准旅馆没有空间。