正确更新摆动组件?

时间:2012-12-14 00:35:03

标签: java swing concurrency timer event-dispatching

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

在这段代码中,我正在翻牌,如果事实证明他们不匹配,我希望他们再次面朝下。

目前正在发生的事情: 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");
        }
    }
}

2 个答案:

答案 0 :(得分:7)

您无法在事件调度线程中休眠,因为您的GUI将冻结。您必须使用Swing Timer。对于您将来可能需要担心的后台任务,请查看SwingWorker

答案 1 :(得分:6)

您似乎缺少许多重要概念。

  1. Swing是一个事件驱动的环境。这意味着没有办法(或者至少只有极少数)你可以“等待”用户输入,通常,你只需要对他们的互动做出反应。
  2. Swing由单个线程驱动,称为事件调度线程(AKA EDT)。该线程负责将进入应用程序的事件分派/处理到应用程序的适当部分,以便他们采取行动。
  3. 重绘经理将更新请求发布到EDT。
  4. 您采取的任何阻止EDT执行此操作的操作都会使您的应用程序看起来像挂起。

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

    阅读Concurrency in Swing以获取更多信息。

    现在,您有很多选择。您可以在后台使用Thread“等待”并转回卡片,或者使用SwingWorkerjavax.swing.Timer

    您遇到的另一个问题是,您不应该从EDT以外的任何Thread更新任何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();
            }
        }
    

    这是一个非常简单的例子。您可能希望放置一些控件,以防止用户在计时器触发之前单击任何内容,例如;)