6

私はスイングするのが初めてです。

このコードでは、カードを表向きにしていますが、一致しないことが判明した場合は、もう一度裏向きに戻します。

現時点で何が起こっているか: 1. 1 枚目のカードをクリックすると裏返る 2. 2 枚目のカードをクリックすると 2 つのいずれかが発生する (a) それらが同じである場合、両方ともそのままであることが望ましい (b) もしそれらは同じではありません.2枚目のカードはカードの裏面をすぐに再表示するため、まったく表示されません(前のカードの裏面も私の方法で定義されています)。

スリープタイマーを入れると、裏返す前に2枚目のカードが表示されたままになるのではないかと思ったのですが、そうではありません。

contentPane.revalidate(); を使用しようとしました。& contentPane.repaint(); しかし、それは何も変わりません。

私はいくつかのコンソール出力を入れました:

Console output:
Card: 0 set
Card: 6 set
Sleeping now
Card: 6 unset
Card: 0 unset

上記は、一致しない 2 つのカードをクリックしたときの結果のコンソール出力です。

@Override
public void actionPerformed(ActionEvent e) 
{
    String buttonPressed = e.getActionCommand();
    int pos = Integer.valueOf(buttonPressed);
    action = Control.model.ReceiveCardsTurned(pos);

    keypadArray[pos].setIcon(myIcons[pos]);     
    System.out.println("Card: "+pos+" set");
    currentTime.setText("" + Control.model.time);
    currentScore.setText("" + Control.model.score);

    //contentPane.revalidate();
    //contentPane.repaint();        

    if(Control.model.twoCardsTurned == false)
    {
        if (action == "unturn") 
        {
            System.out.println("Sleeping now");

            try 
            {
                Thread.sleep(1000);
            }

            catch (InterruptedException e1) 
            {
                e1.printStackTrace();
            }

            keypadArray[pos].setIcon(back);
            keypadArray[Control.model.lastCard].setIcon(back);
            System.out.println("Card: "+pos+" unset");
            System.out.println("Card: "+Control.model.lastCard+" unset");
        }
    }
}
4

2 に答える 2

7

GUIがフリーズするため、イベントディスパッチスレッドでスリープすることはできません。スイングタイマーを使用する必要があります。将来心配する必要があると思われるバックグラウンドタスクについては、SwingWorkerをご覧ください。

于 2012-12-14T00:44:20.697 に答える
6

あなたが見逃していると思われる重要な概念がいくつかあります。

  1. Swingは、イベント駆動型の環境です。つまり、ユーザーの入力を「待つ」ことができる手段はありません(または少なくともごくわずかです)。通常は、ユーザーの操作に反応する必要があります。
  2. Swingは、イベントディスパッチスレッド(別名EDT)と呼ばれる単一のスレッドによって駆動されます。アプリケーションに着信するイベントをアプリケーションの適切な部分にディスパッチ/処理して、アクションを実行できるようにするのは、このスレッドの責任です。
  3. 再描画マネージャーは、更新要求をEDTに送信します。

EDTによるこの作業の実行を停止するアクションを実行すると、アプリケーションがハングしているように見えます。

EDTで時間のかかる操作(I / O、ループなどThread#sleep)を実行しないでください。実行すると、アプリケーションが「一時停止」しますが、これは決してきれいではありません。

詳細については、Swingの並行性をお読みください。

今、あなたはいくつかの選択肢があります。Threadバックグラウンドで「待機」してカードを元に戻すためにを使用するSwingWorkerか、またはを使用することができますjavax.swing.Timer

Threadあなたが持っている他の問題は、EDT以外のUIコンポーネントを決して更新してはならないということです。つまり、を使用する場合はThread、そのスレッドをEDTと再同期する必要があります。難しくはありませんが、面倒になります。

SwingWorkerjavax.swing.Timerこれをはるかに簡単にする機能があります。

スレッドとSwingWorkerはバックグラウンド処理を実行するのに最適であり、この問題には単純にやり過ぎです。代わりに、javax.swing.Timerここに完全に適合します。

if (!Control.model.twoCardsTurned)
    {
        if ("unturn".equals(action)) 
        {
            new Timer(1000, new ActionListener() {
                public void actionPerformed(ActionEvent evt) {
                    keypadArray[pos].setIcon(back);
                    keypadArray[Control.model.lastCard].setIcon(back);
                    System.out.println("Card: "+pos+" unset");
                    System.out.println("Card: "+Control.model.lastCard+" unset");
                }
            }).start();
        }
    }

これは本当に簡単な例です。たとえば、タイマーが起動するまでユーザーが何かをクリックできないようにするいくつかのコントロールを配置したい場合があります;)

于 2012-12-14T00:53:37.847 に答える