简体   繁体   English

正确更新摆动组件?

[英]Updating swing components correctly?

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. 在这段代码中,我正在翻牌,如果事实证明他们不匹配,我希望他们再次面朝下。

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). 目前正在发生的事情:1。当点击时,第一张卡翻过来2.当点击第二张卡时,发生两件事情中的任何一件(a)如果他们是相同的他们都熬夜这是我想要的(b)如果他们不一样我从来没有看到第二张卡,因为它立即重新显示卡片的背面(以及前一张卡片的背面也按我的方法定义)。

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. 我认为放入睡眠计时器可能会让第二张卡显示一段时间后再转回,但事实并非如此。

I attempted to use contentPane.revalidate(); 我试图使用contentPane.revalidate(); & contentPane.repaint(); &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");
        }
    }
}

You can't sleep in the event dispatch thread, because your GUI will freeze. 您无法在事件调度线程中休眠,因为您的GUI将冻结。 You have to use Swing Timer . 你必须使用Swing Timer For background tasks you'll probably have to worry about in the future, take a look at SwingWorker . 对于后续任务,您可能需要担心将来担心,请查看SwingWorker

There are a number of important concepts you seem to be missing. 您似乎缺少许多重要概念。

  1. Swing is an event driven environment. Swing是一个事件驱动的环境。 That means that there is no means (or at least only a very few) that you can "wait" for user input, typically, you just need to react to their interaction. 这意味着没有办法(或者至少只有极少数)你可以“等待”用户输入,通常,你只需要对他们的交互做出反应。
  2. Swing is driven by a single thread, known as the Event Dispatching Thread (AKA EDT). Swing由单个线程驱动,称为事件调度线程(AKA EDT)。 It is the responsibility of this thread to dispatch/process events coming into the application to the appropriate parts of the application so that they can take action. 此线程负责将进入应用程序的事件分派/处理到应用程序的相应部分,以便它们可以采取措施。
  3. The repaint manager posts its update requests onto the 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执行此工作的操作都会使您的应用程序看起来像是挂起的。

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. 你必须永远不要在EDT上执行任何耗时的操作(例如I / O,循环或Thread#sleep #sleep),这样做会使你的应用程序“暂停”,这永远不会很好。

Have a read through Concurrency in Swing for more information. 有关更多信息,请阅读Swing中的Concurrency

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 . 您可以使用Thread在后台“等待”并转回卡,或者您可以使用SwingWorkerjavax.swing.Timer

The other problem you have, is that you should NEVER update any UI components from any Thread other than the EDT. 您遇到的另一个问题是,您不应该从EDT以外的任何Thread更新任何UI组件。 This means if you were to use a Thread , you would become responsible for re-syncing that thread with the EDT. 这意味着如果您使用Thread ,您将负责将该线程与EDT重新同步。 While not difficult, it just becomes messy. 虽然不难,但它变得凌乱。

SwingWorker and javax.swing.Timer have functionality that make this much easier. SwingWorkerjavax.swing.Timer具有使这更容易的功能。

Threads and SwingWorker are great for performing background processing and would simply be overkill for this problem. Threads和SwingWorker非常适合执行后台处理,并且对于这个问题只是过度杀伤。 Instead, a javax.swing.Timer would fit perfectly here. 相反, 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();
        }
    }

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 ;) 您可能希望放置一些控件,以防止用户在计时器触发之前单击任何内容,例如;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM