正确更新摆动组件? [英] Updating swing components correctly?

查看:17
本文介绍了正确更新摆动组件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是摇摆的新手,感谢任何帮助.

I'm new to swing, any help appreciated.

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

In this piece of code I'm turning a card over face up, if it turns out that they don't match I want them to turn back face down again.

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

At the moment what is happening: 1. when clicked the first card turns over 2. when a second card is clicked either of two things happen (a) if they are the same they both stay up which is what I want (b) if they are not the same I never see the 2nd card at all as it immediately re-displays the back of the card (and the back of the previous card also as defined in my method).

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

I thought putting in the sleep timer might keep the 2nd card displayed for a period of time before turning back over but it does not.

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

I attempted to use contentPane.revalidate(); & contentPane.repaint(); but it doesn't change anything.

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

I have put in some console outputs:

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

以上是点击两张不匹配的卡片时的控制台输出

Above is the resulting console output when clicking two card which do not match

@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");
        }
    }
}

推荐答案

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

There are a number of important concepts you seem to be missing.

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

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

ANY action you take that stops the EDT from carrying out this work will make your application look like it's hung.

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

You must NEVER carry out any time consuming operations (such as I/O, loops or Thread#sleep for example) on the EDT, doing so will make your application "pause", which is never pretty.

阅读Swing 中的并发以了解更多信息信息.

Have a read through Concurrency in Swing for more information.

现在,您有多种选择.您可以使用 Thread 在后台等待"并将卡片转回来,或者您可以使用 SwingWorkerjavax.swing.Timer>.

Now, you have a number of choices. You could use a Thread to "wait" in the background and turn the cards back or you could use a SwingWorker or a javax.swing.Timer.

您遇到的另一个问题是,您永远不应该从除 EDT 之外的任何 Thread 更新任何 UI 组件.这意味着如果您要使用 Thread,您将负责将该线程与 EDT 重新同步.虽然不难,但只会变得凌乱.

The other problem you have, is that you should NEVER update any UI components from any Thread other than the EDT. This means if you were to use a Thread, you would become responsible for re-syncing that thread with the EDT. While not difficult, it just becomes messy.

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

SwingWorker and javax.swing.Timer have functionality that make this much easier.

Threads 和 SwingWorker 非常适合执行后台处理,对于这个问题来说简直是矫枉过正.相反,javax.swing.Timer 将非常适合这里.

Threads and SwingWorker are great for performing background processing and would simply be overkill for this problem. Instead, a javax.swing.Timer would fit perfectly here.

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 ;)

这篇关于正确更新摆动组件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆