I have a class that is a JPanel and implements ActionListener. On the panel, there are three JRadioButtons, and when the user selects one of them, the user's score is incremented based on which radio button they selected. (This works- I tested it out by adding an instance of this class to a simple JFrame). When running my game, though, I have a JFrame Menu class with four options. When the user selects the "Play" option, I create a new instance of my JPanel and add it to the JFrame. However, this program does not wait for me to select a radio button- it finishes execution before I select any of the radio buttons. I have tried using a while loop that checks if a boolean is true (meaning that I selected a radio button) but this just makes my radio buttons unclickable. Is there any way to make the program wait for you to click a radio button before continuing execution? (Yes, I added actionListeners to the radio buttons!)
Code:
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();
}
});
}
}
Unfortunately your program doesn't compile as it's missing the Ask
class definition, but I'll try to help.
First of all, a few facts:
A Java program starts his life in the main()
function, executed by a
thread called MainThread. There are also other threads running, and
in particular one called Event Dispatch Thread (EDT).
In general AWT and Swing APIs are not thread-safe, and in fact should be invoked only by the EDT
the EDT thread is the one that will execute your event-driven code (like actionPerformed
), as well as render all your GUI. The EDT should never be involved in long processing activities, as the GUI can't be rendered until the EDT can return to its main event loop. So, if you need to perform some long activity as reaction to an event, the EDT must trigger a separate thread for such activity. But, if you need to make GUI modifications from such thread, those should be executed in the context of EDT through the use of the SwingUtilities.invokeLater()
or SwingUtilities.invokeAndWait()
functions.
Back to your code, you should not instantiate the Menu
class directly from main()
. Instead, do this:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Menu();
}
});
}
Or, using lambda in JDK1.8:
public static void main(String[] args) {
SwingUtilities.invokeLater( () -> {
new Menu();
});
}
The effect of invokeLater
is that the EDT will execute the instantiation asynchronously. The main thread, not having anything else to do, will just terminate, but your Java application will still be running. the EDT will render your GUI and then go back to his main loop, waiting to dispatch events happening in the GUI. From that moment, your application is event-driven: anything that happens is triggered by a user action (of course, you could also start separately new threads, use timers, react to network activities, etc).
Ok, now to your question. Your program should not have terminated at all (although the main thread should have). What do you base your observation of the program terminating on?
As far as "how to wait" goes, you don't have to. when the button is pressed, the EDT will enter actionPerformed()
. Note however that if you start doing a long activity as part of that (like calling a function that has an infinite loop), as you're blocking the EDT your GUI will not refresh.
Hope this help. If not, please post executable code.