如何等待来自一组 JRadioButtons 的输入? (Java)
How to wait for input from a group of JRadioButtons? (Java)
我有一个 class,它是一个 JPanel 并实现了 ActionListener。在面板上,有三个 JRadioButton,当用户 select 是其中之一时,用户的分数会根据他们 select 编辑的单选按钮递增。 (这有效 - 我通过将此 class 的一个实例添加到一个简单的 JFrame 来测试它)。但是,当 运行 我的游戏时,我有一个带有四个选项的 JFrame 菜单 class。当用户 select 选择 "Play" 选项时,我创建了 JPanel 的新实例并将其添加到 JFrame。但是,该程序不会等待我 select 单选按钮 - 它会在我 select 任何单选按钮之前完成执行。我尝试使用 while 循环来检查布尔值是否为真(这意味着我 selected 了一个单选按钮)但这只会让我的单选按钮不可点击。有没有办法让程序在继续执行之前等待您单击单选按钮? (是的,我向单选按钮添加了 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();
}
});
}
}
很遗憾,您的程序没有编译,因为它缺少 Ask
class 定义,但我会尽力提供帮助。
首先,几个事实:
一个Java程序在main()
函数中开始他的生命,由一个
线程称为 MainThread。还有其他线程运行,和
特别是一个叫做 Event Dispatch Thread (EDT) 的线程。
一般来说,AWT 和 Swing API 不是线程安全的,实际上应该只被 EDT
调用
EDT 线程将执行您的事件驱动代码(如 actionPerformed
),并呈现所有 GUI。 EDT 不应参与长时间的处理活动,因为在 EDT 可以 return 到其主事件循环之前无法呈现 GUI。因此,如果您需要执行一些长 activity 作为对事件的反应,EDT 必须为此类 activity 触发一个单独的线程。但是,如果您需要从此类线程进行 GUI 修改,则应通过使用 SwingUtilities.invokeLater()
或 SwingUtilities.invokeAndWait()
函数在 EDT 上下文中执行这些修改。
回到你的代码,你不应该直接从 main()
实例化 Menu
class。相反,这样做:
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 中发生的事件。从那一刻起,您的应用程序就是事件驱动的:发生的任何事情都是由用户操作触发的(当然,您也可以单独启动新线程、使用计时器、对网络活动做出反应等)。
好的,现在回答你的问题。您的程序根本不应该终止(尽管主线程应该终止)。您对程序终止的观察基于什么?
就 "how to wait" 而言,您不必这样做。当按下按钮时,EDT 将进入actionPerformed()
。但是请注意,如果你开始做一个很长的 activity 作为其中的一部分(比如调用一个有无限循环的函数),因为你阻止了 EDT,你的 GUI 将不会刷新。
希望对您有所帮助。如果没有,请post可执行代码。
好的,多个问题。让我们看看您代码的不同部分及其问题:
actionPerformed()
在您按下后由 EDT 执行
"Play"。在这里,你从 0 循环到 7。在循环中,你
创建一个 HardLevel
实例。这个 class 的构造函数是
创建各种 GUI 元素,并休眠两秒钟。
因此,您阻塞了 EDT 线程 16 秒。在此期间,无法显示任何 GUI 更新,包括您的新 GUI 元素,因为这些更新需要由相同的 EDT 线程呈现。
我不确定您创建的 swing.Timer()
实例的意图是什么,但是 swing Timer 将执行您作为参数传递的对象的 actionPerformed
(在这种情况下,相同的 Menu
实例)在 EDT 线程的上下文中(参见 [this page][1])。因为 EDT 线程在你的循环中被阻塞,所以只有在你退出循环后它才能执行 actionPerformed
并且 return 从按下 [ 触发的 actionPerformed
执行=41=]按钮。
现在,当 EDT 最终执行它时,您会得到一个异常,因为在 actionperformed
执行时传递的操作由于计时器到期而具有 null
ActionEvent
字段.
首先,让我们看看如何修复第一部分。我相信你想要做的是,在按下播放键后,让游戏经历 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。
我有一个 class,它是一个 JPanel 并实现了 ActionListener。在面板上,有三个 JRadioButton,当用户 select 是其中之一时,用户的分数会根据他们 select 编辑的单选按钮递增。 (这有效 - 我通过将此 class 的一个实例添加到一个简单的 JFrame 来测试它)。但是,当 运行 我的游戏时,我有一个带有四个选项的 JFrame 菜单 class。当用户 select 选择 "Play" 选项时,我创建了 JPanel 的新实例并将其添加到 JFrame。但是,该程序不会等待我 select 单选按钮 - 它会在我 select 任何单选按钮之前完成执行。我尝试使用 while 循环来检查布尔值是否为真(这意味着我 selected 了一个单选按钮)但这只会让我的单选按钮不可点击。有没有办法让程序在继续执行之前等待您单击单选按钮? (是的,我向单选按钮添加了 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();
}
});
}
}
很遗憾,您的程序没有编译,因为它缺少 Ask
class 定义,但我会尽力提供帮助。
首先,几个事实:
一个Java程序在
main()
函数中开始他的生命,由一个 线程称为 MainThread。还有其他线程运行,和 特别是一个叫做 Event Dispatch Thread (EDT) 的线程。一般来说,AWT 和 Swing API 不是线程安全的,实际上应该只被 EDT
调用
EDT 线程将执行您的事件驱动代码(如
actionPerformed
),并呈现所有 GUI。 EDT 不应参与长时间的处理活动,因为在 EDT 可以 return 到其主事件循环之前无法呈现 GUI。因此,如果您需要执行一些长 activity 作为对事件的反应,EDT 必须为此类 activity 触发一个单独的线程。但是,如果您需要从此类线程进行 GUI 修改,则应通过使用SwingUtilities.invokeLater()
或SwingUtilities.invokeAndWait()
函数在 EDT 上下文中执行这些修改。
回到你的代码,你不应该直接从 main()
实例化 Menu
class。相反,这样做:
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 中发生的事件。从那一刻起,您的应用程序就是事件驱动的:发生的任何事情都是由用户操作触发的(当然,您也可以单独启动新线程、使用计时器、对网络活动做出反应等)。
好的,现在回答你的问题。您的程序根本不应该终止(尽管主线程应该终止)。您对程序终止的观察基于什么?
就 "how to wait" 而言,您不必这样做。当按下按钮时,EDT 将进入actionPerformed()
。但是请注意,如果你开始做一个很长的 activity 作为其中的一部分(比如调用一个有无限循环的函数),因为你阻止了 EDT,你的 GUI 将不会刷新。
希望对您有所帮助。如果没有,请post可执行代码。
好的,多个问题。让我们看看您代码的不同部分及其问题:
actionPerformed()
在您按下后由 EDT 执行 "Play"。在这里,你从 0 循环到 7。在循环中,你 创建一个HardLevel
实例。这个 class 的构造函数是 创建各种 GUI 元素,并休眠两秒钟。因此,您阻塞了 EDT 线程 16 秒。在此期间,无法显示任何 GUI 更新,包括您的新 GUI 元素,因为这些更新需要由相同的 EDT 线程呈现。
我不确定您创建的
swing.Timer()
实例的意图是什么,但是 swing Timer 将执行您作为参数传递的对象的actionPerformed
(在这种情况下,相同的Menu
实例)在 EDT 线程的上下文中(参见 [this page][1])。因为 EDT 线程在你的循环中被阻塞,所以只有在你退出循环后它才能执行actionPerformed
并且 return 从按下 [ 触发的actionPerformed
执行=41=]按钮。现在,当 EDT 最终执行它时,您会得到一个异常,因为在
actionperformed
执行时传递的操作由于计时器到期而具有null
ActionEvent
字段.
首先,让我们看看如何修复第一部分。我相信你想要做的是,在按下播放键后,让游戏经历 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。