【问题标题】:How do I invoke an immediate update to a Java GUI? (conflict with Thread.sleep())如何调用 Java GUI 的即时更新? (与 Thread.sleep() 冲突)
【发布时间】:2011-11-26 11:45:34
【问题描述】:

我正在制作游戏记忆,当你选择两张牌时,如果它们匹配,你就可以保留它们,否则你将它们退回。如果你然后记住你已经选择的牌,你可以更好地猜测接下来的两张牌。

我遇到的问题涉及repaint() 方法没有立即重绘。

当我翻转第二张牌时,无论结果如何,我都希望将两张牌都正面朝上翻转,然后再丢弃它们或将它们翻转回来。我通过调用 sleep() 来做到这一点。

当然,如果我 repaint() 将卡片正面朝上翻转,稍等片刻,然后根据它们的值再次 repaint(),有用的小 Java 只会重绘一次(我想念 C!)。

基本上我想在sleep() 之前强制调用更新。我读过一些其他线程,基本上说最好的方法是创建两个线程来保持你的逻辑和图形分开,然后你可以sleep()你的逻辑并保持你的 GUI 更新,但我在第一学期的第一学期高中一年级的 CS 课程,我希望将其保持在课程水平(尽管我在夏季 Web 开发和 C 编码中花费了相当多的时间)。

因为我知道 StackOverflow 上乐于助人的人喜欢阅读代码,所以下面是我所指的程序部分。 HitArea 类是 Card 对象,cards[] 数组包含 HitArea 的数量。(我还没有重命名 HitArea 类)。 activeCard1activeCard2HitArea 实例,我用来跟踪用户的两个选择,空白构造函数是保留的“不可见”HitArea,尽管稍后我会将其更改为 null。最后,cards.flip() 反转 toggle 布尔值,用于确定卡片是否正面朝上。

public void respond(HitArea choice)
{
    if(choice.inGame)
    {
        if(activeCard1.value == 0 && activeCard1.value == 0)
            activeCard1 = choice;
        else if((!(activeCard1.value == 0) && activeCard2.value == 0) && (activeCard1.id != choice.id))
        {
            activeCard2 = choice;
            check();
        }

    }
}
public void check()
{
    update();
    pause(250);
    if(activeCard2.value == activeCard1.value)
    {
        score += 2;
        activeCard1.inGame = false;
        activeCard2.inGame = false;
    }
    activeCard1.flip();
    activeCard2.flip();
    activeCard1 = new HitArea();
    activeCard2 = new HitArea();
}
public void pause(int milliseconds)
{
    try{
      Thread.currentThread().sleep(milliseconds);
    }
    catch(InterruptedException e){
        System.out.println("Exception: " + e);
    }
}

public void mousePressed(MouseEvent e)
{
    int x = e.getX();
    int y = e.getY();

    for (int i = 0; i < cardNum; i++)
        if(cards[i].boundsCheck( x, y ) )
        {
            repaint();
            cards[i].flip();
            respond(cards[i]);
        }
}

我毫不怀疑我的代码中存在一些问题,因此请随时指出它们。我认为我的基本结构还可以,我宁愿不为这个项目创建多个线程(记住,它是基本的!)。

【问题讨论】:

    标签: java user-interface repaint swingx


    【解决方案1】:

    不要在主 Swing 线程(EDT)上调用 Thread.sleep(...)。 曾经。而是使用摇摆计时器。

    考虑使用 JLabels 来显示您的图像,然后您可以通过简单地更换 ImageIcons 来“翻转”您的卡片。当第二张卡片被翻转后,如果没有匹配,则启动一个延迟 xxxx ms 的非重复 Swing Timer,并在 Timer 的 ActionListener 的 actionCommand 方法中将两个 JLabel 恢复为默认的 ImageIcon。

    javax.swing.Timer 教程可以在这里找到:How to use Swing Timers

    编辑:
    关于您对使用 g.drawString 的评论:现在更容易了,因为您所要做的就是换掉 JLabel 的文本。但稍后,如果您决定升级程序以显示图像,则一切就绪。

    编辑 2:
    关于您关于创建新的 ActionListener 类的问题:我会为此使用匿名内部类。例如:

      int delayTime = 2 * 1000;
      javax.swing.Timer myTimer = new Timer(delayTime, new ActionListener() {
    
         @Override
         public void actionPerformed(ActionEvent e) {
            // TODO: put in the code you want called in xxx mSecs.
         }
      });
      myTimer.setRepeats(false);
      myTimer.start();
    

    【讨论】:

    • 我会将“Ever”加粗和斜体。 :)
    • 我只是显示一些 g.drawString(...) 文本,没有图像。同样适用吗?
    • 据我了解,我需要创建一个新的 ActionListener 类?我该怎么做?download.oracle.com/javase/1.4.2/docs/api/javax/swing/…
    • @EricThoma:请参阅上面我的回答的编辑 2
    • @Plain_Dude_Sleeping_Alone:是的,Swing Timer 可能确实会调用 Thread.sleep,但 关闭 EDT。正如我的回答中所述,您永远不想在 EDT 上调用 Thread.sleep,因为这会使 GUI 完全没有响应——您甚至无法通过单击操作系统的关闭按钮来关闭它顶层窗口的右上角。如果您想在一段代码中暂停 GUI 代码流,请考虑使用模态对话框,例如 JOptionPane。
    猜你喜欢
    • 1970-01-01
    • 2017-10-08
    • 2019-07-08
    • 2022-01-18
    • 1970-01-01
    • 2019-05-23
    • 1970-01-01
    • 2011-09-24
    • 2013-03-10
    相关资源
    最近更新 更多