あなたは次のように述べています:
基本的に、コードを特定の時点でブロックし、ユーザーが JFrame で特定の JLabel をクリックするのを待ちます。ユーザーが JLabel をクリックしたら、クリックされた JLabel の ID を取得した後、コードを再開します。どうやってこれを行うのかわかりません。私が以前持っていた方法は、コードのその時点で、ユーザーは id を入力するだけでした (そして Scanner の next() メソッド ブロック)。
GUI の状態を変更し、ユーザーの入力に対する応答をこの状態に基づいて行うほど、(イベント駆動型プログラムではなく) プログラムをブロックしたくありません。あなたが試みた解決策は直線的な考え方であり、Swing やその他のイベント駆動型 GUI ではうまく機能しません。
たとえば、簡単な例として、プログラムにブール変数を与えることを検討してください。
private boolean labelClicked = false;
JLabel がクリックされた後、JLabel の MouseListener でこれを true に変更します。次に、ブール値が true の場合にのみ、他のユーザー入力に応答します。
または別の可能な解決策: JLabel が押された後に JButton をアクティブにする場合は、JButton を無効にし、JLabel の MouseListener 内から JButton で setEnabled(true) を呼び出します。
重要なのは、イベント駆動型プログラミングを考えることです。
このフォーラムでこのような質問をするときのもう 1 つの鍵は、コード固有の質問ではなく、動作固有の質問をすることです。ここでの本当の問題は、標準入力に書き込む方法ではなく、プログラムを一時停止してユーザー入力を待機させる方法です。これは大きな違いです。
最後に、より具体的でより良い推奨事項が必要な場合は、問題の詳細を記入してください。また、混乱を招くものがある場合は、必ず質問してください。頑張ってください!
編集1
このアプリケーションを管理するGUIおよび非GUIクラスを含むいくつかのクラスを持つ可能性が高く、非GUIクラスには次のものを含めることができます。
- プレーヤー クラス: これは、人間またはコンピューターのいずれかです。
- Board クラス: チェス盤の論理 (非 GUI) 表現
- ピース クラス: すべての具体的なピースが派生する抽象クラス
- ChessAI クラス: これはあなたの AI クラスであり、コンピューターが次の最良の手がどうあるべきかを判断するクラスです。
- ゲーム クラス: ゲーム フローを制御し、誰の順番で移動するかを決定するため、おそらくこの議論で最も重要なクラスです。
Game クラスには、呼び出された Player フィールドを含むフィールドがありturn
、誰のターンかへの参照を保持します。たとえば、Game クラスが humanPlayer と computerPlayer という 2 つの Player 変数を保持しているとします。ターン変数は、これらのオブジェクトのいずれかを保持し、プレイヤーがどのように応答するかは、ターンによってどのオブジェクトが保持されているかによって異なります。
Game クラスには一種のループ (ゲーム ループ) があり、humanPlayer オブジェクトと computerPlayer オブジェクトに移動する順番を交互に伝えます。
つまり、コンピューターの番であり、次の最善の動きを計算するのに時間がかかっているとしましょう。一方、人間のプレイヤーが GUI でチェスの駒をドラッグしようとすると、GUI は Game クラスに人間の移動の試みを通知し、Game クラスは人間の番かどうか ( をチェックして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 が動きます(...) が、実際に人間の番でない限り、Game オブジェクトは応答しません。
makeMove()
プレーヤーに追加された編集 3move(...)
メソッド ゲームのメソッドは、必要なすべてのゲーム ループである可能性があることに注意してください。特に、ComputerPlayer のmakeMove(...)
メソッドが AI エンジンに次善の策を作成するように指示し、ゲームの 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 が保持されていることがわかります。ユーザーはいつでもボタンを押すことができますが、ライトが緑色の場合 (go ブール変数が true の場合) にのみ反応します。これは、ボタンの動作 (押したときに応答するかどうか) がクラスの状態 (go が true かどうか) に依存する 1 つの例です。GUI がセットアップされると (コンストラクターが呼び出され、JFrame に配置されて表示されます)、ブロックするコードなどはありません。go の値を切り替えて JFrame を再描画するだけの Swing Timer がありますが、それだけです。