我有一个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();
}
});
}
}
答案 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。