2013-03-27 3 views
0

Я пытаюсь создать простую сетевую игру tictactoe. Мне нужна программа, чтобы ждать, пока игрок сделает ход, а затем продолжит. В моей функции whileConnected() в нижней части моего кода у меня есть цикл while (true), который должен запускаться вечно и отображать подтверждающее сообщение при нажатии кнопки (что сигнализируется тем фактом, что содержимое строки переменные «сообщения»).Приостановить и дождаться нажатия кнопки, затем продолжить

Проблема в том, что даже если переменная сообщения String изменяется при нажатии кнопки, моя функция whileConnected() никогда не реализует это, а оператор if внутри функции никогда не оценивает значение true. Тождественный оператор if внутри класса ButtonListener отлично работает и отображает желаемое подтверждающее сообщение.

Как я могу решить эту проблему? Я читал и читал, и мне кажется, что я должен использовать 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)");   
     } 

    } 

} 

ответ

2

Если вы используете качели, вы уже используете потоки. Swing по своей природе имеет поток для ввода-вывода и поток для back-end. Вы действительно хотите использовать потоки здесь - среди прочего, поставить поток в ожидании намного дешевле, чем дать ему бесконечный цикл, чтобы отменить.

Слушатели - это еще одно приложение потоков, и я не удивлюсь, если вы сможете получить больше всего или всего того, что хотите, просто используя хорошо построенные слушатели. Кроме того, эти вещи называются семафорами. Семафоры - это способ для потоков обрабатывать синхронизацию - если поток пытается заблокировать семафор, который уже заблокирован, он будет ждать, пока другой поток не разблокирует его, прежде чем продолжить (и снова заблокировать его). В вашем случае вы можете попробовать следующее.

  • У вас есть кнопка прослушивания, основная функция и заблокированный семафор.
  • Основная функция запускается, выполняет любое начальное поведение и пытается захватить семафор. поскольку семафор уже заблокирован, он держится.
  • Когда запускается кнопка прослушивания, одна из вещей, которые она делает, - это разблокировать семафор.
  • Как только семафор разблокируется, основная функция захватывает его (тем самым блокируя его еще раз) и делает все, что он должен делать. В конце концов, он заканчивает это и пытается снова захватить (заблокированный) семафор, таким образом, ожидая, когда в следующий раз прислушивается кнопка прослушивателя.
  • повторить.

Редактировать: Включить и пояснить принятое решение (из комментариев ниже).

Исправление: добавьте Thread.sleep(1000); к внутренней части цикла while в функции «Соединиться».

Объяснение: Цикл while представляет собой бесконечный цикл, который содержит только инструкцию if. Этот оператор if оценивает значение false (и, следовательно, ничего не делает) в течение очень долгого времени (по крайней мере, в отношении компьютера). Это действует точно так же, как это делает электрический штекер - нет ничего, чтобы замедлить его, поэтому поток, который запускает эту главную функцию, сжигает множество вычислительных ресурсов, ничего не делая. Это плохо.Возможно, что некоторые отказоустойчивые пинают и убивают нить. Вполне возможно, что поток потерпел неудачу или сломал что-то более уродливым образом. В любом случае, включая оператор сна (в этом случае спать на секунду каждый цикл, так как он измеряется в мс) предотвращает это, и, таким образом, позволяет продолжать функционировать бесконечно.

+0

«Я не удивлюсь, если вы сможете получить больше всего или всего того, что хотите, просто используя хорошо построенных слушателей». Не могли бы вы немного рассказать об этом? (Я ценю детали семафора, но на данный момент это слишком сложно для меня, и это школьный проект, который мне нужно решить довольно скоро, поэтому я с удовольствием займусь самым простым решением прямо сейчас) –

+0

Ну, это звучит как то, что вам нужно, это то, что будет реагировать соответствующим образом на нажатия кнопок. У вас есть прослушиватель кнопок, который выполняет код на основе нажатия кнопок. Вместо того, чтобы что-то выполнять в основной функции, вы могли бы просто сделать все, что вам нужно сделать изнутри слушателей. Имейте в виду, что слушатели работают в том же потоке, что и пользовательский интерфейс, поэтому, если там много обработки, вы можете столкнуться с некоторым неприятным замедлением, но это должно сработать.К сожалению, если ваше название вопроса является прямой цитатой из вашего задания, семафоры, вероятно, то, что они ищут. –

+0

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/Semaphore.html может быть полезно здесь, если вам нужно использовать семафоры. –

0

Я думаю, что по определению игра приостанавливается до тех пор, пока не будет нажата кнопка, так как gui не будет запускать основной поток, он должен работать в потоке диспетчеризации события.

Качели, конечно, имеют ряд ошибок в потоковом и прослушивании, что может привести к непредсказуемому поведению, если оно не выполнено правильно.

Прошли ли вы через 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

Я полагаю, вы имели в виду, что вы согласились со мной. Ассилиас отредактировал сообщение, но не ответил на него выше этого. Кроме того, добро пожаловать в переполнение стека. :) –

+0

Упс! Спасибо, Бэн :) – Causteau

1

Свинг, как и большинство графических интерфейсов, является средой, управляемой событиями. В основном это означает, что приложение будет ожидать появления какого-либо события, а затем вызовет любые зарегистрированные слушатели, которые ожидают уведомления для этого события.

В вашем случае вам просто нужно зарегистрировать кнопку AdtionListener. Когда пользователь нажимает на нее (или активируется с клавиатуры), вызывается метод actionPerformed, и вы можете выполнить любой код, который вам нужен.

Отъезд How to write action listeners для получения дополнительной информации.

Качели также представляют собой одно резьбовое обрамление. То есть, все взаимодействие с пользовательским интерфейсом должно выполняться из контекста потока Dispatching Event.

Это также означает, что любая длительная или блокирующая задача ДОЛЖНА выполняться из отдельного потока, чтобы не блокировать EDT от обработки входящих событий и повторного запроса, что может заставить приложение выглядеть так, как если бы оно зависло.

Заканчивать Concurrency in Swing для более подробной информации

На мой взгляд, ваш протокол игры будет нуждаться в какой-то способ отслеживания которого вокруг него есть. Это будет достигнуто просто с помощью виртуального токена.

Основной концепцией было бы, если у игрока нет токена, они не могут сделать ход. Когда игрок делает ход, этот ход и токен отправляются другому игроку.

Смежные вопросы