我有一个应用程序,在这个应用程序中,让鼠标点击事件模拟用户输入某个字符串到标准输入是非常方便的。所以我想知道,有没有一种方法可以将代码写入标准中?我意识到这有点像黑客,但它对我需要做的事情非常有用。
编辑(回应气垫船的EDIT2):感谢。我理解该代码如何防止人类玩家不应该移动。我不明白的是你是如何构想主要游戏循环的。你介意写代码来告诉我你在想什么吗?你只是想象一个忙碌的等待循环,不断产生新的计算机动作并调用你的Move()
方法(大部分时间在等待人类玩家移动时被拒绝)?像这样的东西?
public void gameLoop()
{
while (gameNotOver)
{
Move compMove = generateComputersNextMove();
move(blackPlayer, compMove); // where the blackPlayer is the computerPlayer
}
}
答案 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类可以包括:
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)
你必须重新考虑你的解决方案。考虑已经连接到键盘的标准,所以有一些东西已经写入标准版。抱歉,标准旅馆没有空间。