2015-06-04 3 views
-1

У меня есть класс, который является JPanel и реализует ActionListener. На панели есть три JRadioButtons, и когда пользователь выбирает один из них, счет пользователя увеличивается на основе выбранного переключателя. (Это работает - я проверил его, добавив экземпляр этого класса в простой JFrame). Однако, когда я запускаю свою игру, у меня есть класс меню JFrame с четырьмя вариантами. Когда пользователь выбирает параметр «Воспроизвести», я создаю новый экземпляр своего JPanel и добавляю его в JFrame. Однако эта программа не дожидалась, когда я выберу радиокнопку - она ​​завершит выполнение, прежде чем я выберу любую из переключателей. Я попытался использовать цикл while, который проверяет, является ли логическое значение true (это означает, что я выбрал переключатель), но это просто делает мои переключатели незаметными. Есть ли способ заставить программу ждать, пока вы нажмете переключатель, прежде чем продолжить выполнение? (Да, я добавил actionListeners к кнопкам радио!)Как ждать ввода из группы JRadioButtons? (Java)

Код:

import javax.swing.*; 
    import java.awt.*; 
    import java.awt.event.*; 

    public class Ask{ 
     public Ask(){ 
     } 

     public String askName(){ 
     return JOptionPane.showInputDialog("Please enter your name: "); 
     } 

     public int askLevel(){ 
     Object[] options = {"Easy", 
      "Medium", "Hard"}; 
     int n = JOptionPane.showOptionDialog(null,"Which level?","Choices!",JOptionPane.YES_NO_OPTION, 
              JOptionPane.QUESTION_MESSAGE,null,options,options[0]); 
     return n+1; 
     } 

     public boolean askGender(){ 
     Object[] options = {"Girl", 
      "Boy"}; 
     int n = JOptionPane.showOptionDialog(null,"What gender do you want to be?","Choices!",JOptionPane.YES_NO_OPTION, 
              JOptionPane.QUESTION_MESSAGE,null,options,options[0]); 
     if (n == 0) 
      return true; 
     return false; 
     } 
    } 


    import java.awt.*; 
    import java.util.*; 
    import javax.swing.*; 
    import java.awt.event.KeyEvent; 
    import java.awt.event.*; 

    public class HardLevel extends JPanel implements ActionListener{ 
     public int score = 0; 
     public boolean gender; 
     public String playerName; 
     private int num = 0; 
     public boolean check = false; 

     public HardLevel(int n){ 
     super(); 
     num = n; 
     animate(); 
     setVisible(true); 
     setSize(677,500); 
     } 

     public void setGender(boolean g){ 
     gender = g; 
     } 

     public void setPlayerName(String s){ 
     playerName = s; 
     } 

     public boolean getGender(){ 
     return gender; 
     } 

     public String getRealGender(){ 
     if (gender) 
      return "Girl"; 
     return "Boy"; 
     } 

     public String getPlayerName(){ 
     return playerName; 
     } 

     public int getScore(){ 
     return score; 
     } 

     public void animate(){ 
     Insets insets = getInsets(); 
     Dimension size; 
     Surface s = new Surface (num, true); 
     System.out.println (num); 
     s.setLayout (null); 
     removeAll(); 
     add(s); 
     String html1 = "<html><body style='width: "; 
     String html2 = "px'>"; 
     JLabel desc = new JLabel("Description"); 
     desc.setFont(desc.getFont().deriveFont(Font.BOLD, 20)); 
     desc.setForeground(Color.RED); 

     JRadioButton option1 = new JRadioButton("Option 1"); 
     option1.setSelected(true); 
     option1.setActionCommand("Option 1"); 

     JRadioButton option2 = new JRadioButton("Option 2"); 
     option2.setActionCommand("Option 2"); 

     JRadioButton option3 = new JRadioButton("Option 3"); 
     option3.setActionCommand("Option 3"); 

     //Group the radio buttons. 
     ButtonGroup group = new ButtonGroup(); 
     group.add(option1); 
     group.add(option2); 
     group.add(option3); 
     size = option1.getPreferredSize(); 
     option1.setBounds (15+insets.left, 355+insets.top, size.width, size.height); 
     size = option2.getPreferredSize(); 
     option2.setBounds (15+insets.left, 375+insets.top, size.width, size.height); 
     size = option3.getPreferredSize(); 
     option3.setBounds (15+insets.left, 395+insets.top, size.width, size.height); 
     s.add(option1); 
     s.add(option2); 
     s.add(option3); 
     size = desc.getPreferredSize(); 
     desc.setBounds (20+insets.left, 10+insets.top, size.width, size.height); 
     s.add(desc); 
     option1.addActionListener(this); 
     option2.addActionListener(this); 
     option3.addActionListener(this); 
     this.revalidate(); 
     this.repaint(); 
     try{Thread.sleep(2000);}catch(InterruptedException e){} 

     } 

     public void actionPerformed (ActionEvent e){ 
     int n = -1; 
     if (e.getActionCommand().equals("Option 1")) 
      n = 0; 
     if (e.getActionCommand().equals("Option 2")) 
      n = 1; 
     if (e.getActionCommand().equals("Option 3")) 
      n = 2; 
     score += 1; 
     check = true; 
     } 
    } 

    import java.awt.Dimension; 
    import java.awt.EventQueue; 
    import java.awt.Graphics; 
    import java.awt.Graphics2D; 
    import java.awt.Image; 
    import javax.swing.ImageIcon; 
    import javax.swing.JFrame; 
    import javax.swing.JPanel; 

    public class Surface extends JPanel { 

     private Image mshi; 
     private Image mshi2; 
     private int indicator; 

     public Surface(int newIndicator, boolean gender) { 
      indicator = newIndicator; 
      loadImage(); 
      setSurfaceSize(); 
     } 

     private void loadImage() { 
      mshi = new ImageIcon("background_"+indicator+".png").getImage(); 
      mshi2 = new ImageIcon("charactergirl1.png").getImage(); 
     } 

     private void setSurfaceSize() { 
      Dimension d = new Dimension(); 
      d.width = mshi.getWidth(null); 
      d.height = mshi.getHeight(null); 
      setPreferredSize(d);  

     } 

     private void setCharacterSize(){ 
      Dimension d1 = new Dimension(); 
      d1.width = mshi2.getWidth(null); 
      d1.height = mshi2.getHeight(null); 
      setPreferredSize (d1); 
     } 

     private void doDrawing(Graphics g) { 

      Graphics2D g2d = (Graphics2D) g; 
      g2d.drawImage(mshi, 0, 0, null); 
      g2d.drawImage(mshi2, 560, 0, null); 
     } 

     public void paintComponent(Graphics g) { 

      super.paintComponent(g); 
      doDrawing(g); 
     } 
    } 


    import java.awt.*; 
    import java.awt.event.*; 
    import javax.swing.*; 
    import java.awt.print.*; 
    import java.io.*; 

    public class PrintScores implements Printable 
    { 
     private String[] printData = new String [10]; 
     //public String printData = ""; 
     private int counter = 0; 
     private ImageIcon img = new ImageIcon ("logo.png"); 

     public PrintScores (int indicator) 
     { 
     try 
     { 
      BufferedReader in = new BufferedReader (new FileReader ("level_1_high_scores.txt")); 
      while (in.readLine() != null) 
      { 
      printData [counter] = in.readLine(); 
      //System.out.println (printData [counter]); 
      counter++; 
      } 
     } 
     catch (IOException e) 
     { 
      System.out.println ("error"); 
     } 
     } 

     public int print (Graphics g, PageFormat pf, int page) throws PrinterException 
     { 
     if (page > 0) 
     { 
      return NO_SUCH_PAGE; 
     } 
     Graphics2D g2d = (Graphics2D) g; 
     Font font = new Font ("Serif", Font.PLAIN, 10); 
     FontMetrics metrics = g.getFontMetrics (font); 
     g.drawImage (img.getImage(), 400, 100, null); 
     g2d.setFont(new Font("Lucida Console", Font.PLAIN, 11)); 
     for (int x = 0 ; x < counter ; x++) 
      g2d.drawString (printData [x], 100, 100 + (20 * x)); 
     return PAGE_EXISTS; 
     } 


     public void printToPrinter() 
     { 
     PrinterJob job = PrinterJob.getPrinterJob(); 
     job.setPrintable (new PrintScores (1)); 
     boolean doPrint = job.printDialog(); 
     if (doPrint) 
     { 
      try 
      { 
      job.print(); 
      } 
      catch (PrinterException e) 
      { 
      } 
     } 
     } 

    public static void main (String[] args) 
    { 
    PrintScores p = new PrintScores (1); 
    p.printToPrinter(); 
    } 
} 


    import java.awt.*; 
    import java.util.ArrayList; 
    import java.awt.BorderLayout; 
    import java.awt.FlowLayout; 
    import java.awt.event.ActionEvent; 
    import java.awt.event.ActionListener; 
    import javax.swing.*; 

    public class Menu extends JFrame implements ActionListener{ 
     private Image mshi; 
     Timer timer; 
     public int choice; 
     ArrayList <Integer> used = new ArrayList <Integer>(); 
     int counter = 0; 

     public Menu() 
     { 
     super ("Meal Or No Meal?"); 
     setVisible(true); 
     setSize(677, 500); 
     loadImage(); 
     setSurfaceSize(); 
     setLayout (null); 
     Insets insets = getInsets(); 
     JButton highScores = new JButton ("High Scores"); 
     JButton print = new JButton ("Print High Scores"); 
     JButton play = new JButton ("Play"); 
     JButton instructions = new JButton ("Instructions"); 
     highScores.addActionListener(this); 
     print.addActionListener(this); 
     play.addActionListener(this); 
     instructions.addActionListener(this); 
     add(highScores); 
     add(print); 
     add (play); 
     add (instructions); 
     Dimension size = highScores.getPreferredSize(); 
     highScores.setBounds (105+insets.left,255+insets.top, size.width, size.height); 
     size = print.getPreferredSize(); 
     print.setBounds (405+insets.left, 255+insets.top, size.width, size.height); 
     size = play.getPreferredSize(); 
     play.setBounds (115+insets.left, 105+insets.top, size.width, size.height); 
     size = instructions.getPreferredSize(); 
     instructions.setBounds (410+insets.left, 105+insets.top, size.width, size.height); 
     revalidate(); 
     repaint(); 
     } 

     private void loadImage() { 
     mshi = new ImageIcon("menuBackground.png").getImage(); 
     } 

     private void setSurfaceSize() { 
     Dimension d = new Dimension(); 
     d.width = mshi.getWidth(null); 
     d.height = mshi.getHeight(null); 
     setPreferredSize(d);  
     } 

     private void doDrawing(Graphics g) { 
     Graphics2D g2d = (Graphics2D) g; 
     g2d.drawImage(mshi, 0, 0, null); 
     } 

     public void paintComponent(Graphics g) { 
     paintComponent(g); 
     doDrawing(g); 
     } 

     public void actionPerformed (ActionEvent ae) 
     {  
     if (ae.getActionCommand().equals ("High Scores")) 
     { 
      System.out.println ("high scores"); 
      choice = 1; 
     } 
     else if (ae.getActionCommand().equals ("Print High Scores")) 
     { 
      System.out.println ("print high scores"); 
      Ask s = new Ask(); 
      PrintScores p = new PrintScores(s.askLevel()); 
      p.printToPrinter(); 
      choice = 2; 
     } 
     else if (ae.getActionCommand().equals ("Play")) 
     { 
      System.out.println ("play"); 
      int score = 0; 
      for (int x = 0; x < 8; x ++){ 
      getContentPane().removeAll(); 
      int num = 0; 
      while(true){ 
       num = (int)(Math.random() * 13 - 1 + 1) + 1; 
       if (used.contains(num)) 
       continue; 
       used.add(num); 
       break; 
      } 
      HardLevel h = new HardLevel(num); 
      add(h); 
      revalidate(); 
      repaint(); 
      if (counter == 0){ 
       Ask s = new Ask(); 
       h.setPlayerName(s.askName()); 
       h.setGender(s.askGender()); 
       System.out.println (h.getPlayerName()+ " " + h.getRealGender());} 
      timer = new Timer(100, this); 
      timer.setInitialDelay(500); 
      timer.start(); 
      score +=h.getScore(); 
      System.out.println ("Score: "+score); 
      counter++; 
     } 
     } 
     else if (ae.getActionCommand().equals ("Instructions")) 
     { 
      System.out.println ("instructions"); 
      choice = 4; 
     } 
     } 
     public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       new Menu(); 
      } 
     }); 
    } 
    } 
+0

Опубликовать код, не писать эссе об этом. – Yoda

+0

Используйте CardLayout для управления представлениями, используйте контроллер для управления перемещением между видами – MadProgrammer

ответ

3

К сожалению, программа не компилируется, как он отсутствует определение Ask класса, но я постараюсь помочь.

Прежде всего, несколько фактов:

  • программа Java, начинает свою жизнь в функции main(), выполняемую нити под названием MainThread. Существуют также другие потоки, и , в частности, один из них называется Event Dispatch Thread (EDT).

  • В общем AWT и Swing, API-интерфейсы не поточно-, а на самом деле должны быть вызваны только EDT

  • нитью EDT является один, который будет выполнять ваш управляемые события кода (например, actionPerformed) , а также отобразить весь ваш графический интерфейс. EDT никогда не должен участвовать в длительных процессах обработки, поскольку GUI не может быть отображен до тех пор, пока EDT не сможет вернуться в свой основной цикл событий. Итак, если вам нужно выполнить некоторую длительную деятельность как реакцию на событие, EDT должен инициировать отдельный поток для такой активности. Но, если вам нужно внести изменения в GUI из такого потока, они должны выполняться в контексте EDT с использованием функцийили SwingUtilities.invokeAndWait().

Назад к коду, вы не должны создать экземпляр класса Menu непосредственно из main(). Вместо этого:

public static void main(String[] args) { 
    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      new Menu(); 
     } 
    }); 
} 

Или, используя лямбда в JDK1.8:

public static void main(String[] args) { 
    SwingUtilities.invokeLater(() -> { 
     new Menu(); 
    }); 
} 

Эффект invokeLater является то, что EDT будет выполнять инстанцирование асинхронно. Основной поток, не имеющий ничего другого, просто прекратит работу, но ваше приложение Java все равно будет работать. EDT отобразит ваш графический интерфейс, а затем вернется в свой основной цикл, ожидая отправки событий, происходящих в графическом интерфейсе. С этого момента ваше приложение управляется событиями: все, что происходит, инициируется действием пользователя (конечно, вы также можете запускать отдельно новые потоки, использовать таймеры, реагировать на сетевые действия и т. Д.).

Хорошо, теперь на ваш вопрос. Ваша программа не должна заканчиваться вообще (хотя основной поток должен иметь). На чем вы основываете свое наблюдение за завершением программы?

Что касается «как подождать», вам не обязательно. когда кнопка нажата, EDT войдет в actionPerformed(). Обратите внимание, что если вы начнете выполнять длинную деятельность как часть этого (например, вызывать функцию с бесконечным циклом), поскольку вы блокируете EDT, ваш графический интерфейс не будет обновляться.

Надеюсь, что эта помощь. Если нет, отправьте исполняемый код.

+0

большое вам спасибо! Это было действительно хорошее объяснение, и теперь я понимаю edt намного больше. однако, когда я запускаю его, он дает мне исключение nullpointer. Я добавлю весь свой код так, чтобы он исполнялся – null

+0

Я отправил код, пожалуйста, скажите мне, что-то не хватает – null

+0

Хорошо, несколько вопросов: –

0

Хорошо, несколько вопросов. Давайте посмотрим на различные части вашего кода, и их проблемы:

  • actionPerformed() в настоящее время исполняется EDT после нажатия «Play». Здесь вы выполняете цикл от 0 до 7. В цикле вы находитесь , создавая экземпляр HardLevel. Конструктор этого класса: , создающий различные элементы GUI, и спящий в течение двух секунд.

    Итак, вы блокируете поток EDT в течение 16 секунд. В течение этого времени никакие обновления GUI не могут отображаться, включая новые элементы GUI, поскольку эти обновления должны отображаться одним и тем же потоком EDT.

  • Я не уверен, что ваши намерения с swing.Timer(), например, вы создаете, но свинг таймер будет выполнять actionPerformed объекта вы передаете в качестве аргумента (в данном случае тот же Menu экземпляра) в контексте EDT (см. [Настоящая страница] [1]). Поскольку поток EDT заблокирован в вашем цикле, он сможет выполнить actionPerformed только после выхода из цикла и возврата из выполнения actionPerformed, который был вызван нажатием кнопки «Воспроизвести».

    Теперь, когда EDT наконец выполняет его, вы получите исключение, потому что действие, которое передается при actionperformed выполняется из-за tử Уходящий таймера имеет nullActionEvent поле.

Прежде всего, давайте посмотрим, как исправить первую часть. Я считаю, что вы пытаетесь сделать это, нажав «Играть», имея в игре 8 уровней, каждый из которых имеет определенную продолжительность времени. Это верно? если это так, способ сделать это:

private void nextLevel() { 
    while(true){ 
     num = (int)(Math.random() * 13 - 1 + 1) + 1; 
     System.out.println ("num: "+num); 
     if (used.contains(num)) 
      continue; 
     used.add(num); 
     break; 
    } 
    HardLevel h = new HardLevel(num); 
    add(h); 
    revalidate(); 
    repaint(); 
} 

public void actionPerformed(ActionEvent ev) { 
... 
    else if (ae.getActionCommand().equals ("Play")) 
    { 
     System.out.println ("play"); 
     int score = 0; 
     getContentPane().removeAll(); 
     int num = 0; 
     nextLevel(); 
     if (counter == 0){ 
      Ask s = new Ask(); 
      h.setPlayerName(s.askName()); 
      h.setGender(s.askGender()); 
     } 
     counter++; 
     // here I setup a timer that will expire when the level 
     // is over. I pass an anonymous ActionListener instead of 
     // using the Menu object again. This will be executed when 
     // the timer exipires, in the EDT context. 
     timer = new Timer(100, new ActionListener() { 
      public void actionPerformed(ActionEvent ev) { 
       score +=h.getScore(); 
       System.out.println ("Score: "+score); 
       nextLevel(); 
      } 
     }; 
     timer.setInitialDelay(LEVEL_DURATION_MS); 
     timer.start(); 
    } 

Также удалите Thread.sleep из HardLevel.

+0

Спасибо за помощь, она оценена. Я внедрил предложенный вами код, но теперь, когда я перехожу к опции «Воспроизведение» из меню, и он переходит в первую сцену, программа переходит в бесконечный цикл и сохраняет печать в области взаимодействия. Чтобы ответить на ваш вопрос о таймере, я просто попробовал его для тестирования - я извиняюсь за путаницу, это не имело реальной цели. Я хочу, чтобы в этой игре отображалась одна сцена за раз, получая вход от пользователя через один из JRadioButtons, и когда пользователь нажимает кнопку, я хочу, чтобы она переходила к следующей сцене. – null

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