6

我是摇摆新手,任何帮助表示赞赏。

在这段代码中,我将一张卡片正面朝上翻转,如果事实证明它们不匹配,我希望它们再次正面朝下翻转。

目前正在发生的事情: 1. 当点击第一张卡片时 2. 当点击第二张卡片时,会发生两件事中的任何一个(a)如果它们相同,它们都会保持不变,这就是我想要的(b)如果它们不一样我根本看不到第二张卡片,因为它会立即重新显示卡片的背面(以及前一张卡片的背面也是我的方法中定义的)。

我认为放入睡眠计时器可能会使第二张卡片显示一段时间,然后再翻身,但事实并非如此。

我试图使用 contentPane.revalidate(); & contentPane.repaint(); 但它不会改变任何东西。

我已经输入了一些控制台输出:

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

上面是单击两张不匹配的卡时产生的控制台输出

@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 将冻结。你必须使用Swing Timer。对于您将来可能不得不担心的后台任务,请查看SwingWorker

于 2012-12-14T00:44:20.697 回答
6

您似乎遗漏了许多重要的概念。

  1. Swing 是一个事件驱动的环境。这意味着没有任何方法(或至少只有极少数)可以“等待”用户输入,通常,您只需要对他们的交互做出反应。
  2. Swing 由单个线程驱动,称为事件调度线程 (AKA EDT)。该线程负责将进入应用程序的事件分派/处理到应用程序的适当部分,以便它们可以采取行动。
  3. 重绘管理器将其更新请求发布到 EDT。

您采取的任何阻止 EDT 执行此工作的操作都会使您的应用程序看起来像挂起一样。

您绝不能在 EDT 上执行任何耗时的操作(例如 I/O、循环或Thread#sleep例如),这样做会使您的应用程序“暂停”,这永远不会很漂亮。

阅读Swing 中的并发以获取更多信息。

现在,您有多种选择。您可以使用 aThread在后台“等待”并将卡片转回,或者您可以使用 aSwingWorker或 a javax.swing.Timer

您遇到的另一个问题是,您永远不应该从ThreadEDT 以外的任何地方更新任何 UI 组件。这意味着如果您使用 a Thread,您将负责将该线程与 EDT 重新同步。虽然不难,但它只是变得混乱。

SwingWorkerjavax.swing.Timer具有使这更容易的功能。

线程并且SwingWorker非常适合执行后台处理,并且对于这个问题来说只是矫枉过正。相反, ajavax.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();
        }
    }

This is a really simple example. You might like to put in some controls that will prevent the user from clicking anything until the timer fires, for example ;)

于 2012-12-14T00:53:37.847 回答