0

シンプルな tictactoe ネットワーク ゲームを構築しようとしています。プレーヤーが移動するまで待ってから続行するプログラムが必要です。コードの最後にある whileConnected() 関数には、永久に実行され、ボタンが押されたときに確認メッセージを表示するはずの while(true) サイクルがあります (これは、文字列の内容によって通知されます)。変数「メッセージ」の変更)。

問題は、ボタンがクリックされたときに String メッセージ変数が変更されたとしても、whileConnected() 関数がこれを認識せず、関数内の if ステートメントが true に評価されないことです。ButtonListener クラス内の同一の if ステートメントは正常に機能し、必要な確認メッセージを表示します。

どうすればこの問題を解決できますか? 私は読んで読んで、スレッドを使用する必要があるという考えを理解しました(スレッドについて読みましたが、これまで使用したことがないため、推測にすぎません)。スレッドは必要ですか? 誰かがこの特定の問題に使用すべき原則を簡単に説明できますか? (ボタンがクリックされるまでプログラムを一時停止し、ボタンがクリックされたときに作成された関連情報を引き続き使用するにはどうすればよいですか)。コード例は、スレッドについての私の読書を本当に軽くします。これは、初心者にとっては非常に抽象的なトピックです。

以下は私のコードです、事前に感謝します。

public class Test extends JFrame
{
    private Container contentPane;
    private JButton btn00;
    private static String message = "";

    private class ButtonListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            String buttonText = e.getActionCommand();

            if (buttonText.equals("My Button"))
            {
                message = "pressed";
                if (message != "")
                    System.out.println(message+"(executed by ButtonListener)");
            }           
        }

    }

    public Test()
    {
        this.contentPane = this.getContentPane();
        btn00 = new JButton("My Button");
        btn00.setSize(btn00.getPreferredSize());
        btn00.setLocation(20,20);
        ButtonListener listener = new ButtonListener();
        btn00.addActionListener(listener);

        // configure frame
        this.setSize(300,300);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        // make panel
        JPanel panel = new JPanel();
        panel.setSize(200,200);
        panel.setLocation(10,10);
        panel.add(btn00);
        this.contentPane.add(panel);        
    }

    public static void main(String[] args)
    {
        Test gui = new Test();
        gui.setVisible(true);
        // connected
        whileConnected();

    }

    private static void whileConnected()
    {
        System.out.println("message is at first empty: "+message);
        while (true)
        {
            // the if below never evaluates to true... why?

            if (message != "") // this is never true
                System.out.println(message+"(executed by whileConnected)");         
        }

    }

}
4

3 に答える 3

2

スイングを使用している場合は、すでにスレッドを使用しています。Swing には、その性質上、I/O 用のスレッドとバックエンド用のスレッドがあります。ここで実際にスレッドを使用したい - とりわけ、スレッドを待機させることは、無限ループを発生させるよりもはるかに安価です。

リスナーはスレッドのもう 1 つのアプリケーションです。適切に構築されたリスナーを使用するだけで、必要なもののほとんどまたはすべてを取得できたとしても、私は驚かないでしょう。あるいは、セマフォと呼ばれるものがあります。セマフォは、スレッドがタイミングを処理する方法です。スレッドが既にロックされているセマフォをロックしようとすると、別のスレッドがロックを解除するまで待機してから続行します (そして再度ロックします)。あなたの場合、次のことを試してみてください。

  • ボタン リスナー、メイン関数、およびロックされたセマフォを用意します。
  • メイン関数が開始され、初期動作が実行され、セマフォの取得が試行されます。セマフォはすでにロックされているため、保持されます。
  • ボタン リスナーが起動すると、セマフォのロックが解除されます。
  • セマフォがロック解除されるとすぐに、メイン関数がセマフォを取得し (したがってもう一度ロックします)、本来の処理を実行します。最終的に、それはそれを終了し、(ロックされた) セマフォを再度取得しようとします。こうして、次にボタン リスナーが起動するのを待ちます。
  • 繰り返す。

編集:実際に受け入れられた解決策を含めて説明する(以下のコメントから)。

修正: Thread.sleep(1000);whileConnected 関数の while ループの内側に追加します。

説明: while ループは、if ステートメントだけを含む無限ループです。この if ステートメントは、非常に長い間 (少なくともコンピューターに関する限り) false と評価されます (したがって、それ以上何もしません)。これは、電気的短絡とほぼ同じように機能します。速度を落とすものは何もないため、メイン関数を実行するスレッドは、何もせずに多くのコンピューティング リソースを消費します。これは悪いです。いくつかのフェイルセーフが開始され、スレッドが強制終了された可能性があります。スレッドが失敗したか、より醜い方法で何かを壊した可能性があります。いずれにせよ、sleep ステートメント (この場合、ミリ秒単位で測定されるため、各ループで 1 秒間スリープする) を含めることで、これを防ぎ、関数を無期限に続行できるようにします。

于 2013-03-27T18:54:39.043 に答える
2

Swing は、ほとんどの GUI フレームワークと同様に、イベント駆動型の環境です。基本的にこれは、アプリケーションが何らかのイベントが発生するのを待ってから、そのイベントの通知を待っている登録済みのリスナーをトリガーすることを意味します。

あなたの場合、AdtionListenerボタンに a を登録するだけです。ユーザーがそれをクリックすると (またはキーボードからアクティブ化すると)、actionPerformedメソッドが呼び出され、必要なコードを実行できます。

詳細については、アクション リスナーの作成方法を参照してください。

Swing もシングル スレッド フレームワークです。つまり、UI とのすべての対話は、イベント ディスパッチ スレッドのコンテキスト内から実行する必要があります。

これは、EDT が受信イベントや再描画要求を処理するのをブロックしないように、長時間実行またはブロックしているタスクを別のスレッドから実行する必要があることも意味します。これにより、アプリケーションがハングしたように見える可能性があります。

詳細については、Swing の同時実行を確認してください。

私の考えでは、あなたのゲーム プロトコルには、誰のラウンドであるかを追跡する何らかの方法が必要になるでしょう。これは、仮想トークンを使用するだけで実現できます。

プレイヤーがトークンを持っていない限り、プレイヤーは行動を起こすことができないというのが基本的なコンセプトです。プレーヤーが移動すると、その移動とトークンが他のプレーヤーに送信されます。

于 2013-03-27T19:22:56.447 に答える
0

定義上、ボタンが押されるまでゲームは一時停止すると思います.GUIはメインスレッドを実行しないため、イベントディスパッチスレッドで実行する必要があります。

Swing には、正しく実装されていない場合に予期しない動作が発生する可能性がある、スレッド化とリスナーに関する多くの落とし穴があります。

Swing の oracle の Java チュートリアルを読みましたか? ほとんどの関連性は、リスナーの http://docs.oracle.com/javase/tutorial/uiswing/events/index.html と http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index例です。 WorkerThreads の.html

私が Swing で見つけた最良の方法は、ここからサンプルをダウンロードして、それらを拡張してみることです。

私は Ben Barden に同意しますが、必要なものを理解しているので、リスナーを使用して必要なものを達成できると思います。

于 2013-03-27T19:12:39.447 に答える