2013-03-27 127 views
0

我正在尝试构建一个简单的tictactoe网络游戏。我需要该节目等待,直到一名球员进行动作,然后继续。在我的代码底部的whileConnected()函数中,我有一个while(true)循环,它应该永远运行,并在按下按钮时显示一条确认消息(这是通过字符串的内容变量'消息'的变化)。暂停并等待按钮被点击,然后继续

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

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

下面是我的代码,在此先感谢。

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

    } 

} 

回答

2

如果你正在使用swing,你已经使用了线程。 Swing本质上有一个用于I/O的线程和一个用于后端的线程。你确实想要在这里使用线程 - 除此之外,让线程等待比为它提供无限循环更便宜。

监听器都是线程的另一种应用,我也不会感到惊讶,如果你能得到的大多数或所有你想要的只是通过构建良好的听众。或者,这些东西叫做信号量。信号量是线程处理时序的一种方式 - 如果一个线程试图锁定一个已经被锁定的信号量,它将等待另一个线程在继续(并再次锁定)之前解锁它。在你的情况下,你可以尝试以下。

  • 有一个按钮侦听器,一个主函数和一个锁定的信号量。
  • 主要功能启动,执行任何初始行为,并尝试获取信号量。因为信号量已经被锁定,它就成立了。
  • 当按钮侦听器触发时,它所做的一件事是解锁信号量。
  • 只要旗语解锁,主要功能抓住它(从而锁定了一次以上),并做什么它应该做的事。最终,它结束并试图再次获取(锁定的)信号量,从而等待下一次按钮侦听器触发。
  • 重复。

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

修复:添加Thread.sleep(1000);在whileConnected功能while循环的内部。

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

+0

“如果你能通过使用结构良好的听众获得大部分或全部想要的东西,我不会感到惊讶。你能详细解释一下吗? (我很欣赏信号量的细节,但现在对我来说太复杂了,这是一个我很快就需要解决的学校项目,所以我现在很乐意去寻求最简单的解决方案) – 2013-03-27 20:12:46

+0

就像你需要的是一些能够对按钮进行适当反应的东西。你有一个按钮监听器,它执行基于按钮按下的代码。而不是在主函数中执行任何事情,你可以在监听器中完成你需要做的所有事情。请注意,听众与用户界面运行的线程相同,因此,如果有很多处理过程,那么您可能会遇到一些令人不快的放缓,但它应该起作用。不幸的是,如果你的问题标题是你的任务的直接引用,信号量可能是他们正在寻找的。 – 2013-03-27 20:16:40

+0

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html在这里可能会有所帮助,如果您确实需要使用信号量。 – 2013-03-27 20:20:54

0

我认为游戏暂停直到按下按钮,因为GUI不会运行主线程,它应该在事件分派线程中运行。

Swing肯定有很多关于线程和侦听器的问题,如果执行不正确,可能会导致一些不可预知的行为。

你有没有通过甲骨文的Java教程Swing?大多数relavent将是http://docs.oracle.com/javase/tutorial/uiswing/events/index.html听众和例子http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html为WorkerThreads

我与Swing中发现的最好的事情就是在这里下载例子并尝试对他们

我虽然本·巴登同意扩大,根据我对你需要的理解,我认为你可以用听众来实现你所需要的东西。

+0

我相信你的意思是你同意我的意见。 Assylias编辑了这篇文章,但没有对此做出回应。另外,欢迎来到Stack Overflow。 :) – 2013-03-27 19:41:22

+0

哎呀!谢谢本:) – Causteau 2013-03-27 19:54:32

1

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

在你的情况下,你只需要注册一个AdtionListener到按钮。当用户点击它(或通过键盘激活)时,将调用actionPerformed方法,并且您可以执行您需要的任何代码。

查看更多信息How to write action listeners

Swing也是单线程framwework。也就是说,所有与UI的交互都必须在事件派发线程的上下文中执行。

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

退房Concurrency in Swing更多细节

在我看来,你的游戏协议将需要追踪的方式,其围绕它。这可以简单地通过使用虚拟令牌来实现。

基本的概念是,除非玩家有令牌,否则他们不能动。一旦玩家移动,该移动和令牌就会发送给其他玩家。

相关问题