暂停并等待单击按钮,然后继续

时间:2013-03-27 18:44:07

标签: java multithreading swing

我正在尝试构建一个简单的tictactoe网络游戏。我需要程序等到玩家移动然后继续。在我的代码底部的whileConnected()函数中,我有一个while(true)循环,它应该永远运行并在按下按钮时显示一条确认消息(这是由String的内容表示的事实变量'消息'更改)。

问题是,即使单击按钮时String消息变量发生了变化,我的whileConnected()函数也从未意识到这一点,函数内部的if语句永远不会计算为true。 ButtonListener类中的相同if语句正常工作并显示所需的确认消息。

我该如何解决这个问题?我已经阅读并阅读了,我认为我应该使用Threads(我读过它们但我之前从未使用过它们,这就是为什么它只是猜测)。我需要线程吗?有人可以简单解释应该用于这个特定问题的原则吗? (如何在单击按钮之前暂停程序,然后继续使用单击按钮时创建的相关信息)。一个代码示例真的会减轻我对线程的阅读 - 当一个人是初学者时,这是一个非常抽象的主题。

以下是我的代码,提前谢谢。

public class Test extends JFrame
{
    private Container contentPane;
    private JButton btn00;
    private static String message = "";

    private class ButtonListener implements ActionListener
    {

        @Override
        public void actionPerformed(ActionEvent e)
        {
            String buttonText = e.getActionCommand();

            if (buttonText.equals("My Button"))
            {
                message = "pressed";
                if (message != "")
                    System.out.println(message+"(executed by ButtonListener)");
            }           
        }

    }

    public Test()
    {
        this.contentPane = this.getContentPane();
        btn00 = new JButton("My Button");
        btn00.setSize(btn00.getPreferredSize());
        btn00.setLocation(20,20);
        ButtonListener listener = new ButtonListener();
        btn00.addActionListener(listener);

        // configure frame
        this.setSize(300,300);
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);

        // make panel
        JPanel panel = new JPanel();
        panel.setSize(200,200);
        panel.setLocation(10,10);
        panel.add(btn00);
        this.contentPane.add(panel);        
    }

    public static void main(String[] args)
    {
        Test gui = new Test();
        gui.setVisible(true);
        // connected
        whileConnected();

    }

    private static void whileConnected()
    {
        System.out.println("message is at first empty: "+message);
        while (true)
        {
            // the if below never evaluates to true... why?

            if (message != "") // this is never true
                System.out.println(message+"(executed by whileConnected)");         
        }

    }

}

3 个答案:

答案 0 :(得分:2)

如果您正在使用swing,那么您已经在使用线程了。 Swing本质上有一个用于I / O的线程和一个用于后端的线程。你确实想在这里使用线程 - 除其他外,将一个线程置于等待比给它一个无限循环来流失要便宜得多。

监听器是线程的另一个应用程序,如果你能通过使用构造良好的监听器获得你想要的大部分或全部内容,我不会感到惊讶。或者,有些东西叫做信号量。信号量是线程处理时间的一种方式 - 如果线程试图锁定已经锁定的信号量,它将等到另一个线程解锁它然后再继续(并再次锁定它)。在您的情况下,您可以尝试以下操作。

  • 有一个按钮监听器,一个主函数和一个锁定的信号量。
  • 主要功能启动,执行任何初始行为,并尝试获取信号量。由于信号量已被锁定,因此它保持不变。
  • 当按钮侦听器触发时,它所做的一件事就是解锁信号量。
  • 一旦信号量解锁,主函数就会抓住它(因此再次锁定它)并做它应该做的任何事情。最终,它完成了,并尝试再次获取(锁定)信号量,从而等待下一次按钮侦听器触发。
  • 重复。

编辑:包括并解释实际接受的解决方案(来自下面的评论)。

修复:将Thread.sleep(1000);添加到whileConnected函数中while循环的内部。

说明:while循环是一个无限循环,只包含if语句。这个if语句在很长一段时间内(至少就计算机而言)的评估结果为false(因此不再做任何事情)。这与电气短路的作用大致相同 - 没有什么可以减慢它的速度,因此运行该主要功能的线程会消耗大量的计算资源。这是不好的。有些故障安全可能会被踢进并杀死线程。线程可能以更丑陋的方式失败或破坏某些东西。在任何情况下,包括睡眠语句(在这种情况下,每秒循环睡眠,因为它以毫秒为单位测量)会阻止这种情况,从而允许函数无限期地继续。

答案 1 :(得分:2)

与大多数GUI框架一样,Swing是一个事件驱动的环境。基本上这意味着,应用程序将等待某种事件发生,然后将触发任何已注册的侦听器等待该事件的通知。

在您的情况下,您只需要在按钮上注册AdtionListener即可。当用户单击它(或通过键盘激活)时,将调用actionPerformed方法,您可以执行所需的代码。

查看How to write action listeners了解详情。

Swing也是一个单线程的framwework。也就是说,必须在Event Dispatching Thread的上下文中执行与UI的所有交互。

这也意味着,任何长时间运行或阻塞任务必须从单独的线程执行,以免阻止EDT处理传入事件和重新绘制请求,这可能会使应用程序看起来好像已挂起。

查看Concurrency in Swing了解详情

在我看来,你的游戏协议需要某种方式跟踪它的轮次。这可以通过使用虚拟令牌来实现。

基本概念是,除非玩家拥有令牌,否则他们无法采取行动。一旦玩家移动,该移动和令牌将被发送给另一个玩家。

答案 2 :(得分:0)

我认为根据定义,游戏暂停直到按下按钮,因为gui不会运行主线程,它应该在事件调度线程中运行。

Swing肯定有许多围绕线程和侦听器的问题,如果没有正确实现,可能会导致一些不可预测的行为。

你是否经历过针对Swing的oracle Java教程?大多数相关都是http://docs.oracle.com/javase/tutorial/uiswing/events/index.html中监听器和http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html for WorkerThreads

的示例

我发现使用Swing最好的方法是在这里下载示例并尝试扩展它们

我同意Ben Barden的观点,根据我对你所需要的理解,我认为你可以通过听众实现你所需要的。