如何等待一组JRadioButtons的输入? (JAVA)

时间:2015-06-04 23:00:38

标签: java swing jradiobutton

我有一个JPanel类并实现了ActionListener。在面板上,有三个JRadioButtons,当用户选择其中一个时,用户的分数会根据他们选择的单选按钮递增。 (这个工作 - 我通过将这个类的实例添加到一个简单的JFrame来测试它)。但是,在运行我的游戏时,我有一个带有四个选项的JFrame Menu类。当用户选择“播放”选项时,我创建了一个新的JPanel实例并将其添加到JFrame中。但是,这个程序不会等我选择一个单选按钮 - 它在我选择任何单选按钮之前完成执行。我已经尝试使用while循环来检查布尔值是否为真(意味着我选择了一个单选按钮),但这只是使我的单选按钮不可点击。在继续执行之前,有没有办法让程序等你单击一个单选按钮? (是的,我将actionListeners添加到单选按钮!)

代码:

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

2 个答案:

答案 0 :(得分:3)

不幸的是你的程序没有编译,因为它缺少Ask类定义,但我会尽力帮助。

首先,一些事实:

  • Java程序在main()函数中开始,由a执行 线程名为MainThread。还有其他线程正在运行,和 特别是一个叫做事件调度线程(EDT)。

  • 一般来说,AWT和Swing API不是线程安全的,实际上只能由EDT调用

  • EDT线程将执行您的事件驱动代码(如actionPerformed),以及渲染您的所有GUI。 EDT永远不应该涉及长处理活动,因为在EDT可以返回其主事件循环之前不能呈现GUI。因此,如果您需要执行一些长时间的活动作为对事件的反应,那么EDT必须为此类活动触发一个单独的线程。但是,如果您需要从这样的线程进行GUI修改,那么应该通过使用SwingUtilities.invokeLater()SwingUtilities.invokeAndWait()函数在EDT的上下文中执行这些修改。

回到您的代码,您不应直接从Menu实例化main()类。相反,这样做:

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

或者,在JDK1.8中使用lambda:

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

invokeLater的效果是EDT将异步执行实例化。没有任何其他事情可做的主线程将终止,但您的Java应用程序仍将运行。 EDT将呈现您的GUI,然后返回到他的主循环,等待发送GUI中发生的事件。从那时起,您的应用程序是事件驱动的:发生的任何事情都是由用户操作触发的(当然,您也可以单独启动新线程,使用计时器,对网络活动做出反应等)。

好的,现在回答你的问题。你的程序根本不应该终止(虽然主线程应该有)。你根据终止的程序观察了什么?

就“如何等待”而言,你没有必要。按下按钮时,EDT将进入actionPerformed()。但请注意,如果您开始执行长活动(例如调用具有无限循环的函数),则在阻止EDT时,GUI将无法刷新。

希望这有帮助。如果没有,请发布可执行代码。

答案 1 :(得分:0)

好的,多个问题。让我们看一下代码的不同部分及其问题:

    按下后,
  • actionPerformed()由EDT执行 “玩”。在这里,你从0循环到7.在循环中,你是 创建HardLevel实例。这个类的构造函数是 创建各种GUI元素,并睡两秒钟。

    所以,你要阻止EDT线程16秒。在此期间,不会显示任何GUI更新,包括新的GUI元素,因为这些更新需要由同一个EDT线程呈现。

  • 我不确定你对你创建的swing.Timer()实例的意图是什么,但是一个swing计时器会执行你传递的对象的actionPerformed作为参数(在这种情况下,在EDT线程的上下文中使用相同的Menu实例)(参见[本页] [1])。由于EDT线程在循环中被阻塞,因此只有在退出循环后才能执行actionPerformed,并从按下“播放”按钮触发的actionPerformed执行返回。

    现在,当EDT最终执行它时,您会收到异常,因为在actionperformed执行时由于计时器到期而执行的操作有一个null ActionEvent字段。

首先,让我们看看如何修复第一部分。我相信你要做的就是按下Play,让游戏经历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(); 
    }

另外,从HardLevel中删除Thread.sleep。