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

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

问题描述

我是新来的摇摆,任何帮助赞赏。



在这段代码中,我把一张卡片翻过来,如果他们



现在发生了什么:
1.当点击第一张卡片时, b $ b 2.当第二张卡被点击时,两个事情发生
(a)如果他们是相同的,他们都留下来,这是我想要的
(b)如果他们不一样我从来没有看到第二张卡,因为它立即重新显示卡的背面(和前一张卡的背面也如我的方法中定义的)。



我认为加入睡眠定时器可能会保持第二张卡显示一段时间,然后再回来,但它不会。



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



我有一些控制台输出:

 code>控制台输出:
卡:0设置
卡:6设置
现在睡觉
卡:6未设置
卡:0未设置

上面是点击两个不匹配的卡片时产生的控制台输出

  @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)$​​ b $ b {
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);
}
}
}


解决方案>


  1. Swing是一个事件驱动的环境。这意味着没有任何方法(或至少只有很少一部分)可以等待用户输入,通常只需要对其交互作出反应。

  2. Swing是由单个线程驱动,称为事件分派线程(AKA EDT)。这个线程的责任是将进入应用程序的事件分派/处理到应用程序的适当部分,以便他们可以采取行动。

  3. 重新绘制管理器将其更新请求发布到EDT。

您采取的任何措施都会阻止EDT执行此项工作,这将使您的应用程序看起来像挂起。



您不能执行任何耗时的操作(例如I / O,循环或 Thread#sleep ) EDT,这样做会让你的应用程序暂停,这是永远不会漂亮。



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



一些选择。您可以使用主题在后台等待并将卡片回来,或者您可以使用 SwingWorker javax.swing.Timer



另一个问题是,你不应该更新任何UI组件从任何线程除了EDT。这意味着如果你使用 Thread ,你将负责重新同步该线程与EDT。虽然不难,但只是变得杂乱。



SwingWorker javax.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);
}
}开始();
}
}

这是一个非常简单的例子。您可能想要放入一些控件,以防止用户点击任何东西,直到定时器触发,例如;)


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

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.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 is an event driven environment. 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). 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.

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

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.

Have a read through Concurrency in Swing for more information.

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.

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.

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

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

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

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