I'm trying to make a traffic light program, changing the foreground colour of JLabel from red to yellow to green, everytime I press JButton (i.e once i press JButton, JLabel turns red, then when i again press JButton it turns yellow and so on). But somehow the colour changes only once to red & nothing happens on further pressing JButton. Any kind of help would be appreciated. Thanks.
import java.awt.Color;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JTextField;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class traffic {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
traffic window = new traffic();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public traffic() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 798, 512);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(null);
JLabel lblTrafficLight = new JLabel("Traffic Light");
lblTrafficLight.setFont(new Font("Tahoma", Font.BOLD, 40));
lblTrafficLight.setHorizontalAlignment(SwingConstants.CENTER);
lblTrafficLight.setBounds(190, 11, 403, 61);
frame.getContentPane().add(lblTrafficLight);
JLabel lblRed = new JLabel("RED");
lblRed.setHorizontalAlignment(SwingConstants.CENTER);
lblRed.setFont(new Font("Tahoma", Font.PLAIN, 40));
lblRed.setBounds(273, 125, 249, 61);
frame.getContentPane().add(lblRed);
JButton btnButton = new JButton("Button");
btnButton.setActionCommand("B");
btnButton.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
if(btnButton.getActionCommand().equals("B"))
{
lblRed.setForeground(Color.RED);
}
if(btnButton.getActionCommand().equals("B"))
{
lblRed.setForeground(Color.YELLOW);
}
if(btnButton.getActionCommand().equals("B"))
{
lblRed.setForeground(Color.GREEN);
}
if(btnButton.getActionCommand().equals("B"))
{
lblRed.setForeground(Color.YELLOW);
}
if(btnButton.getActionCommand().equals("B"))
{
lblRed.setForeground(Color.RED);
}
}
});
btnButton.setBounds(353, 346, 89, 23);
frame.getContentPane().add(btnButton);
}
}
You're using the same actionCommand, B for each if block, and so all of the blocks will always run, and the last block will be the one seen.
e.g.,
int x = 1;
if (x == 1) {
// do something
}
if (x == 1) {
// do something else
}
all blocks will be done!
Either change the actionCommands used, or don't use actionCommand String but rather an incrementing int index. Also, don't use MouseListeners for JButtons but rather ActionListeners.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
public class Traffic2 extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = 300;
private static final String[] STRINGS = {"Red", "Blue", "Orange", "Yellow", "Green", "Cyan"};
private Map<String, Color> stringColorMap = new HashMap<>();
private JLabel label = new JLabel("", SwingConstants.CENTER);
private int index = 0;
public Traffic2() {
stringColorMap.put("Red", Color.red);
stringColorMap.put("Blue", Color.blue);
stringColorMap.put("Orange", Color.orange);
stringColorMap.put("Yellow", Color.YELLOW);
stringColorMap.put("Green", Color.GREEN);
stringColorMap.put("Cyan", Color.CYAN);
label.setFont(label.getFont().deriveFont(Font.BOLD, 40f));
String key = STRINGS[index];
label.setText(key);
label.setForeground(stringColorMap.get(key));
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(label);
JPanel topPanel = new JPanel();
topPanel.add(new JButton(new AbstractAction("Change Color") {
#Override
public void actionPerformed(ActionEvent e) {
index++;
index %= STRINGS.length;
String key = STRINGS[index];
label.setText(key);
label.setForeground(stringColorMap.get(key));
}
}));
setLayout(new BorderLayout());
add(topPanel, BorderLayout.PAGE_START);
add(centerPanel, BorderLayout.CENTER);
}
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private static void createAndShowGui() {
Traffic2 mainPanel = new Traffic2();
JFrame frame = new JFrame("Traffic2");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Related
I started programming Java. This is my first window application. I did a simple tic-tac-toe game and I want the "o" button font color to be a different color. But it doesn't work. I can change the background color, but not the fonts, why?
package moje;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.print.PrinterJob;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JTextField;
public class Kolko_i_krzyzyk extends JFrame implements ActionListener {
static JTextField tekst;
static JLayeredPane ekran = new JLayeredPane();
static JButton button = new JButton();
static int licznik=0;
public Kolko_i_krzyzyk () {
super("Kółko i krzyżyk");
ekran = new JLayeredPane();
setVisible(true);
setSize(800, 800);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
//Siatka podzielona 3 na 3
setLayout(new GridLayout(3,3));
//Tworzenie 9 przycisków
for(int i = 1; i<=9; i++) {
JButton button = new JButton();
add(button);
button.addActionListener(this);
}
}
public static void main(String[] args) {
JFrame okno = new Kolko_i_krzyzyk();
}
#Override
public void actionPerformed(ActionEvent e) {
JButton button = (JButton) e.getSource();
if(licznik%2==0 ) {
button.setText("x");
button.setFont(new Font ("Arial", Font.BOLD, 90));
}
else {
button.setText("O");
button.setForeground(Color.RED);
button.setFont(new Font ("Arial", Font.BOLD, 90));
}
button.setEnabled(false);
licznik++;
}
}
The issue here is the default behavior when disabling the JButton via setEnabled(false).
This will grey out the button and ignore any color formatting you did to the text (foreground).
There are several workarounds to modify this behavior (as seen in this similar question).
Here is a short demonstration (without the final game logic of course) , which changes the UI of the JButton via setUI().
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.plaf.metal.MetalButtonUI;
public class Test {
private int counter = 0;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new Test().buildGui());
}
private void buildGui() {
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.add(panel);
panel.setLayout(new GridLayout(3, 3));
for (int i = 1; i <= 9; i++) {
JButton button = new JButton() {
#Override
public Dimension getPreferredSize() {
return new Dimension(150, 150);
}
};
button.setFont(new Font("Arial", Font.BOLD, 90));
panel.add(button);
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (counter % 2 == 0) {
button.setText("X");
button.setUI(new MetalButtonUI() {
// override the disabled text color for the button UI
protected Color getDisabledTextColor() {
return Color.BLUE;
}
});
} else {
button.setText("O");
button.setUI(new MetalButtonUI() {
protected Color getDisabledTextColor() {
return Color.RED;
}
});
}
button.setEnabled(false);
counter++;
}
});
}
frame.pack();
frame.setVisible(true);
}
}
Result:
Another (simpler) way to do it would be to build some ImageIcons for "X" and "O", then set these on the buttons via setIcon()/setDisabledIcon(). This would save you the trouble from modifying the button UI.
With Swing, I've created a window and want a letter to flash on the screen depending on the BPM (Beats per minute) the user inputs, and I was wondering how I would go about timing the flashing accurately. I tried using a Swing Timer but it is not very accurate and I see a lot of pauses or lag. I've heard something about using System.nanoTime() and System.currentTimeMillis() but have no clue how to implement them to create a timer. Any help would be appreciated!
Note.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.event.*;
import java.awt.*;
public class Note extends JFrame implements ActionListener {
JPanel mainScreen = new JPanel();
JPanel south = new JPanel();
JPanel north = new JPanel();
//emptyNumberMain = how many empty panels you want to use
public int emptyNumberMain = 2;
JPanel[] emptyMain = new JPanel[emptyNumberMain];
JLabel title = new JLabel("Fretboard Trainer!");
JButton start = new JButton("Start!");
public static void main(String[] args) {
new Note();
}
public Note() {
super("Random Note!");
setSize(300,300);
setResizable(false);
setDefaultCloseOperation(EXIT_ON_CLOSE);
//creates emptyNumberMain amount of empty panels
for (int i = 0; i < emptyNumberMain; i++) {
emptyMain[i] = new JPanel();
}
mainScreen.setLayout(new BorderLayout());
south.setLayout(new GridLayout(1,1));
south.add(emptyMain[0]);
south.add(start);
south.add(emptyMain[1]);
north.setLayout(new GridLayout(1,2));
north.add(title);
title.setHorizontalAlignment(JLabel.CENTER);
title.setFont(title.getFont().deriveFont(32f));
start.addActionListener(this);
mainScreen.add(north, BorderLayout.NORTH);
mainScreen.add(south, BorderLayout.SOUTH);
add(mainScreen);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == start) {
dispose();
new RandomNote();
}
}
}
RandomNote.java
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import java.util.Random;
import javax.swing.Timer;
import javax.swing.JSlider;
import java.awt.event.*;
import java.awt.*;
public class RandomNote extends JFrame {
JPanel noteScreen = new JPanel();
JPanel center = new JPanel();
JPanel southSlider = new JPanel();
JLabel bpm = new JLabel();
//emptyNumber = how many empty panels you want to use
int emptyNumber = 2;
JPanel[] empty = new JPanel[emptyNumber];
JLabel rndNote = new JLabel();
JSlider slider = new JSlider(0,200,100);
Timer timer2 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bpm.setText(Integer.toString(slider.getValue()));
timer.setDelay((int) ((60.0/slider.getValue()) * 1000));
}
});
public RandomNote() {
super("Random Notes!");
timer.start();
timer2.start();
setSize(500,500);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
//creates variable emptyNumber amount of empty panels
for (int i = 0; i < emptyNumber; i++) {
empty[i] = new JPanel();
}
noteScreen.setLayout(new BorderLayout());
center.setLayout(new GridLayout(1,1));
center.add(rndNote);
southSlider.setLayout(new GridLayout(3,1));
slider.setLabelTable(slider.createStandardLabels(20));
slider.setPaintTicks(true);
slider.setPaintLabels(true);
slider.setMinorTickSpacing(5);
slider.setMajorTickSpacing(20);
southSlider.add(slider);
southSlider.add(bpm);
rndNote.setHorizontalAlignment(JLabel.CENTER);
rndNote.setFont(rndNote.getFont().deriveFont(32f));
noteScreen.add(center, BorderLayout.CENTER);
noteScreen.add(southSlider, BorderLayout.SOUTH);
add(noteScreen);
setVisible(true);
}
Timer timer = new Timer(1000, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
rndNote.setText(noteOutput());
}
});
public static String noteOutput() {
Random rand = new Random();
String[] note = {"A", "B", "C", "D", "E", "F", "G"};
int randNum = rand.nextInt(7);
return note[randNum];
}
}
The immediate thing that jumps out at me is this...
Timer timer2 = new Timer(100, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
bpm.setText(Integer.toString(slider.getValue()));
timer.setDelay((int) ((60.0/slider.getValue()) * 1000));
}
});
Why do you need to update the text and reset the timer every 100 milliseconds?
So, the simple answer would be to use a ChangeListener on the JSlider to determine when the slider's value changes. I'd recommend having a look at How to Use Sliders for more details
As a runnable concept...
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private AnimatableLabel label;
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridwidth = GridBagConstraints.REMAINDER;
label = new AnimatableLabel("BMP");
label.setHorizontalAlignment(JLabel.CENTER);
add(label, gbc);
label.start();
JSlider slider = new JSlider(10, 200);
slider.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
label.setBPM(slider.getValue());
}
});
slider.setValue(60);
add(slider, gbc);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class AnimatableLabel extends JLabel {
private Timer pulseTimer;
private Timer fadeTimer;
private double bpm = 60;
private double alpha = 0;
private Long pulsedAt;
public AnimatableLabel(String text, Icon icon, int horizontalAlignment) {
super(text, icon, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(String text, int horizontalAlignment) {
super(text, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(String text) {
super(text);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(Icon image, int horizontalAlignment) {
super(image, horizontalAlignment);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel(Icon image) {
super(image);
setBackground(Color.RED);
initTimer();
}
public AnimatableLabel() {
setBackground(Color.RED);
initTimer();
}
public void start() {
updateTimer();
}
public void stop() {
pulseTimer.stop();
fadeTimer.stop();
}
protected void initTimer() {
pulseTimer = new Timer((int)(getDuration()), new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulsedAt = System.currentTimeMillis();
alpha = 1.0;
repaint();
}
});
pulseTimer.setInitialDelay(0);
pulseTimer.setCoalesce(true);
fadeTimer = new Timer(5, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if (pulsedAt == null) {
return;
}
long fadingDuration = System.currentTimeMillis() - pulsedAt;
alpha = 1.0 - (fadingDuration / getDuration());
if (alpha > 1.0) {
alpha = 1.0;
} else if (alpha < 0.0) {
alpha = 0.0;
}
repaint();
}
});
fadeTimer.setCoalesce(true);
}
protected double getDuration() {
return (60.0 / bpm) * 1000.0;
}
protected void updateTimer() {
fadeTimer.stop();
pulseTimer.stop();
pulseTimer.setDelay((int)getDuration());
pulseTimer.start();
fadeTimer.start();
}
public void setBPM(double bpm) {
this.bpm = bpm;
setText(Double.toString(bpm));
updateTimer();
}
public double getBPM() {
return bpm;
}
#Override
protected void paintComponent(Graphics g) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive((float)alpha));
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
super.paintComponent(g);
}
}
}
I created a JFrame, and it contains a JPanel. I created a number of JLabels. I can add the JLabels to the JPanel, and display them correctly. But I want to implement them so as they displayed sequentially; a time delay between each JLabel to be displayed.
After searching the StackOverfLow, I tried some code, but it has no effect!. So How to use a timer to make components(Labels) displayed one after the other by setting a time delay.
I Don't want a fix for my code particularly in the answer. Just show how to display any type of components in a delayed manner, each component displayed after a period of time. That is all. I provided my code to show my effort in trying to solve the problem.
First this is a subclass of JLabel to use: (No problems with it)
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
public class DLabel extends JLabel
{
Dimension size = new Dimension(70, 75);
Font font = new Font(Font.SANS_SERIF, 12, 35);
public DLabel(String t)
{
this.setPreferredSize(size);
this.setBorder(BorderFactory.createBevelBorder(1, Color.white, Color.black));
this.setVerticalAlignment(JLabel.CENTER);
this.setHorizontalAlignment(JLabel.CENTER);
this.setText(t);
this.setFont(font);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
Color color1 = new Color(226, 218, 145);
Color color2 = color1.brighter();
int w = getWidth();
int h = getHeight();
GradientPaint gp = new GradientPaint(
0, 0, color1, 0, h, color2);
g2d.setPaint(gp);
g2d.fillRect(0, 0, w, h);
super.paintComponent(g);
}
}
The other class that use the DLabel class:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
public class DelayedLabels extends JPanel
{
static JFrame frame;
Timer timer; //timer to be used for dealy
DLabel card_1; //Defining the DLabels
DLabel card_2;
DLabel card_3;
JLabel[] labelsArray;
public DelayedLabels()
{
this.setLayout(null);
card_1 = new DLabel("1");
card_2 = new DLabel("2");
card_3 = new DLabel("3");
labelsArray = new DLabel[3]; //create the array
createLabelsArray(); //add the Labels Objects to labelsArray
setLabelsLocations(labelsArray); // set the locations of the Labels to be displayed on the JPanel
addLabelsToPanel(labelsArray); //The adding of the Labels to the JPanel
}
private void createLabelsArray()
{
labelsArray[0] = card_1;
labelsArray[1] = card_2;
labelsArray[2] = card_3;
}
private void setLabelsLocations(JLabel[] labels)
{
int length = labels.length;
int gap = 10;
int counter = 10;
for (int i = 0; i < length; i++)
{
labels[i].setBounds(170, counter, 60, 70);
counter = counter + labels[i].getBounds().height + gap;
}
}
private void addLabelsToPanel(JLabel[] labels)
{
for (int i = 0; i < labels.length; i++)
{
frame.revalidate();
frame.repaint();
this.add(labels[i]);
timer = new Timer(1000, timerAction); //timer to use with 1000 milliseconds
timer.start();
}
}
private ActionListener timerAction = new ActionListener() //action to be invoked after each label added
{
#Override
public void actionPerformed(ActionEvent ae)
{
frame.revalidate();
frame.repaint();
}
};
private static void createAndShowGUI()
{
frame = new JFrame();
frame.setSize(600, 700);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DelayedLabels demo = new DelayedLabels();
demo.setOpaque(true);
frame.add(demo);
frame.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DelayedLabels extends JPanel {
static JFrame frame;
Timer timer; //timer to be used for dealy
JLabel card_1; //Defining the JLabels
JLabel card_2;
JLabel card_3;
JLabel[] labelsArray;
ActionListener listener;
public DelayedLabels() {
listener = new ActionListener() {
int i = 0;
#Override
public void actionPerformed(ActionEvent e) {
Component c = DelayedLabels.this.getTopLevelAncestor();
DelayedLabels.this.add(labelsArray[i++]);
c.validate();
c.repaint();
if (i==labelsArray.length) {
timer.stop();
}
}
};
this.setLayout(new GridLayout(0, 1, 20, 20));
card_1 = new JLabel("Label 1");
card_2 = new JLabel("Label 2");
card_3 = new JLabel("Label 3");
labelsArray = new JLabel[3]; //create the array
createLabelsArray(); //add the Labels Objects to labelsArray
timer = new Timer(1000,listener);
timer.start();
}
private void createLabelsArray() {
labelsArray[0] = card_1;
labelsArray[1] = card_2;
labelsArray[2] = card_3;
}
private static void createAndShowGUI() {
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DelayedLabels demo = new DelayedLabels();
demo.setOpaque(true);
frame.add(demo, BorderLayout.PAGE_START);
frame.pack();
frame.setSize(200, 150);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
UIManager.put("swing.boldMetal", Boolean.FALSE);
createAndShowGUI();
}
});
}
}
So I'm revising a random number generator I made a while back and instead of making it in JOptionPane, I decided to try to create it in JFrame. The 2 problems I'm having is:
I can't figure out how to access the number of attempts in class "Easy" to use for class "PlayAgain".
How could I loop back to the beginning of the program and start at the Menu screen again if they decide to click btnPlayAgain? Creating a new instance of Menu does not work the way I want it to, as the Menu frame doesn't close after you choose a difficulty.
The code is for the 3 classes, Menu, Easy, and PlayAgain. I didn't include the code for buttons Medium or Hard as it is pretty much identical to Easy.
Menu
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class Menu extends JFrame {
private JPanel contentPane;
public static Menu frame;
public static Easy eFrame;
public static Medium mFrame;
public static Hard hFrame;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new Menu();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Menu() {
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 149);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblSelectADifficulty = new JLabel("Select a difficulty");
lblSelectADifficulty.setBounds(10, 49, 424, 19);
lblSelectADifficulty.setFont(new Font("Tahoma", Font.PLAIN, 15));
lblSelectADifficulty.setHorizontalAlignment(SwingConstants.CENTER);
contentPane.add(lblSelectADifficulty);
JLabel lblRandomNumberGuessing = new JLabel("Random Number Guessing Game");
lblRandomNumberGuessing.setHorizontalAlignment(SwingConstants.CENTER);
lblRandomNumberGuessing.setFont(new Font("Tahoma", Font.PLAIN, 22));
lblRandomNumberGuessing.setBounds(10, 11, 424, 27);
contentPane.add(lblRandomNumberGuessing);
JButton btnEasy = new JButton("Easy (0-100)");
btnEasy.setBounds(10, 79, 134, 23);
contentPane.add(btnEasy);
JButton btnMedium = new JButton("Medium (0-1000)");
btnMedium.setBounds(155, 79, 134, 23);
contentPane.add(btnMedium);
JButton btnHard = new JButton("Hard (0-10000)");
btnHard.setBounds(300, 79, 134, 23);
contentPane.add(btnHard);
btnEasy.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
frame.setVisible(false);
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
eFrame = new Easy();
eFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
});
}
}
Easy
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JTextField;
import javax.swing.JButton;
public class Easy extends JFrame {
private JPanel contentPane;
private JTextField textField;
private int rand;
public int attempts;
public Easy() {
attempts = 1;
Random rnd = new Random();
rand = rnd.nextInt(100 + 1);
setResizable(false);
setTitle("Take a guess");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 300, 135);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
final JLabel lblGuessANumber = new JLabel("Guess a number between 0 - 100");
lblGuessANumber.setBounds(10, 11, 274, 19);
lblGuessANumber.setFont(new Font("Tahoma", Font.PLAIN, 15));
lblGuessANumber.setHorizontalAlignment(SwingConstants.CENTER);
contentPane.add(lblGuessANumber);
textField = new JTextField();
textField.setBounds(20, 41, 110, 20);
contentPane.add(textField);
textField.setColumns(10);
final JButton btnGuess = new JButton("Guess");
btnGuess.setBounds(164, 41, 110, 20);
contentPane.add(btnGuess);
final JLabel label = new JLabel("");
label.setFont(new Font("Tahoma", Font.PLAIN, 12));
label.setHorizontalAlignment(SwingConstants.CENTER);
label.setBounds(10, 72, 274, 24);
contentPane.add(label);
btnGuess.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if((Integer.parseInt(textField.getText())) >= 0 && (Integer.parseInt(textField.getText())) <= 100){
if((Integer.parseInt(textField.getText())) < rand){
label.setText("You guessed too low.");
System.out.println(rand);
attempts++;
}
else if((Integer.parseInt(textField.getText())) > rand){
label.setText("You guessed too high.");
attempts++;
}
else if((Integer.parseInt(textField.getText())) == rand){
dispose();
PlayAgain pl = new PlayAgain();
pl.setVisible(true);
}
}
else
label.setText("Please enter a valid input.");
}
});
}
public int returnAttempts(){
return attempts;
}
}
PlayAgain
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
public class PlayAgain extends JFrame {
private JPanel contentPane;
public PlayAgain() {
setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 240, 110);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
setContentPane(contentPane);
contentPane.setLayout(null);
JLabel lblPlayAgain = new JLabel("Play Again?");
lblPlayAgain.setFont(new Font("Tahoma", Font.PLAIN, 15));
lblPlayAgain.setHorizontalAlignment(SwingConstants.CENTER);
lblPlayAgain.setBounds(10, 27, 214, 23);
contentPane.add(lblPlayAgain);
JButton btnYes = new JButton("Yes");
btnYes.setBounds(10, 49, 89, 23);
contentPane.add(btnYes);
JButton btnQuit = new JButton("Quit");
btnQuit.setBounds(135, 49, 89, 23);
contentPane.add(btnQuit);
//Need to return number of attempts from Easy.java in lblYouGuessedCorrectly
JLabel lblYouGuessedCorrectly = new JLabel("You guessed correctly! Attempts: ");
lblYouGuessedCorrectly.setHorizontalAlignment(SwingConstants.CENTER);
lblYouGuessedCorrectly.setBounds(10, 11, 214, 14);
contentPane.add(lblYouGuessedCorrectly);
btnYes.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Need to start the program over again, starting with from the Menu screen
}
});
btnQuit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
}
}
Suggestions:
You're creating an event-driven Swing GUI, and so you won't "loop" back to the beginning of your program as you would in a linear console program, because that's not how event driven programs work. Rather you'd simply display the menu view when needed, usually in response to some event such as within the ActionListener of a JButton and/or JMenuItem.
So add a reset JButton or JMenuItem or both, have them share the same ResetAction AbstractAction, and inside of that Action, re-show the menu view.
Side recommendation 1 (not related to your main problem): Don't use null layouts or setBounds as that will lead to rigid hard to debug and enhance GUI's that look good on one platform only.
Side recommendation 2: Don't code towards creation of JFrames but rather JPanel views as this will increase the flexibility of your program greatly, allowing you to swap JPanel views if need be using a CardLayout, or displaying views within a JFrame or JDialog or anywhere else they're needed.
For example using a CardLayout to swap JPanel views and a JOptionPane to get user input on re-starting:
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Window;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
#SuppressWarnings("serial")
public class Main2 extends JPanel {
private MenuPanel menuPanel = new MenuPanel(this);
private GamePanel gamePanel = new GamePanel(this);
private CardLayout cardLayout = new CardLayout();
public Main2() {
setLayout(cardLayout);
add(menuPanel, MenuPanel.NAME);
add(gamePanel, GamePanel.NAME);
}
public void setDifficulty(Difficulty difficulty) {
gamePanel.setDifficulty(difficulty);
}
public void showCard(String name) {
cardLayout.show(Main2.this, name);
}
private static void createAndShowGui() {
JFrame frame = new JFrame("Main2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new Main2());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MenuPanel extends JPanel {
public static final String NAME = "menu panel";
private static final String MAIN_TITLE = "Random Number Guessing Game";
private static final String SUB_TITLE = "Select a difficulty";
private static final int GAP = 3;
private static final float TITLE_SIZE = 20f;
private static final float SUB_TITLE_SIZE = 16;
private Main2 main2;
public MenuPanel(Main2 main2) {
this.main2 = main2;
JLabel titleLabel = new JLabel(MAIN_TITLE, SwingConstants.CENTER);
titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD, TITLE_SIZE));
JPanel titlePanel = new JPanel();
titlePanel.add(titleLabel);
JLabel subTitleLabel = new JLabel(SUB_TITLE, SwingConstants.CENTER);
subTitleLabel.setFont(subTitleLabel.getFont().deriveFont(Font.PLAIN, SUB_TITLE_SIZE));
JPanel subTitlePanel = new JPanel();
subTitlePanel.add(subTitleLabel);
JPanel buttonPanel = new JPanel(new GridLayout(1, 0, GAP, GAP));
for (Difficulty difficulty : Difficulty.values()) {
buttonPanel.add(new JButton(new DifficultyAction(difficulty)));
}
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
add(titlePanel);
add(subTitlePanel);
add(buttonPanel);
}
private class DifficultyAction extends AbstractAction {
private Difficulty difficulty;
public DifficultyAction(Difficulty difficulty) {
this.difficulty = difficulty;
String name = String.format("%s (0-%d)", difficulty.getText(), difficulty.getMaxValue());
putValue(NAME, name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
main2.setDifficulty(difficulty);
main2.showCard(GamePanel.NAME);
}
}
}
enum Difficulty {
EASY("Easy", 100), MEDIUM("Medium", 1000), HARD("Hard", 10000);
private String text;
private int maxValue;
private Difficulty(String text, int maxValue) {
this.text = text;
this.maxValue = maxValue;
}
public String getText() {
return text;
}
public int getMaxValue() {
return maxValue;
}
}
#SuppressWarnings("serial")
class GamePanel extends JPanel {
public static final String NAME = "game panel";
private String labelText = "Guess a number between 0 - ";
private JLabel label = new JLabel(labelText + Difficulty.HARD.getMaxValue(), SwingConstants.CENTER);
private Main2 main2;
GuessAction guessAction = new GuessAction("Guess");
private JTextField textField = new JTextField(10);
private JButton guessButton = new JButton(guessAction);
private boolean guessCorrect = false;
private Difficulty difficulty;
public GamePanel(Main2 main2) {
this.main2 = main2;
textField.setAction(guessAction);
JPanel guessPanel = new JPanel();
guessPanel.add(textField);
guessPanel.add(Box.createHorizontalStrut(10));
guessPanel.add(guessButton);
JPanel centerPanel = new JPanel(new GridBagLayout());
centerPanel.add(guessPanel);
setLayout(new BorderLayout());
add(label, BorderLayout.PAGE_START);
add(centerPanel, BorderLayout.CENTER);
}
public void setDifficulty(Difficulty difficulty) {
this.difficulty = difficulty;
label.setText(labelText + difficulty.getMaxValue());
}
private class GuessAction extends AbstractAction {
private int attempts = 1;
public GuessAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
// TODO use difficulty and all to check guesses, and reply to user
// we'll just show the go back to main menu dialog
guessCorrect = true; // TODO: Delete this later
if (guessCorrect) {
String message = "Attempts: " + attempts + ". Play Again?";
String title = "You've Guessed Correctly!";
int optionType = JOptionPane.YES_NO_OPTION;
int selection = JOptionPane.showConfirmDialog(GamePanel.this, message, title, optionType);
if (selection == JOptionPane.YES_OPTION) {
textField.setText("");
main2.showCard(MenuPanel.NAME);
} else {
Window window = SwingUtilities.getWindowAncestor(GamePanel.this);
window.dispose();
}
}
}
}
}
I ll explain my code in a bit:
I have a JComboBox with a list of items
And when the JButton "Select" is pressed, it registers the last index of the last selected item from JComboBox.
Now I need to access this index inside the main.
Here is my code :
public static final JComboBox c = new JComboBox();
private static final JButton btnNewButton = new JButton("Select");
And the JButton ActionListener is:
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
ind = c.getSelectedIndex();
frame.setVisible(false);
}
});
So after the button is pressed, the frame closes
But now when I try to access this ind inside main simply by
public static void main(String[] args) {
System.out.println(ind);}
I get a return value of ind = 0
I understand that this is because it has been initialized to 0 as
static ind = 0
But then how do I access this index outside the JButton ActionListener?
I need to use this index further in my code.
EDIT
Here's my MCVE
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.SpringLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.UIManager;
public class MinimalExProgram
{
private static String[] description = { "One", "Two", "Three"};
static int ind;
public static final JComboBox c = new JComboBox(description);
private static final JButton btnNewButton = new JButton("Select");
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.getContentPane().setForeground(UIManager.getColor("ComboBox.disabledBackground"));
frame.getContentPane().setBackground(UIManager.getColor("EditorPane.disabledBackground"));
SpringLayout springLayout = new SpringLayout();
springLayout.putConstraint(SpringLayout.NORTH, btnNewButton, 5, SpringLayout.NORTH, frame.getContentPane());
springLayout.putConstraint(SpringLayout.EAST, c, -6, SpringLayout.WEST, btnNewButton);
springLayout.putConstraint(SpringLayout.EAST, btnNewButton, -10, SpringLayout.EAST, frame.getContentPane());
springLayout.putConstraint(SpringLayout.WEST, c, 6, SpringLayout.WEST, frame.getContentPane());
springLayout.putConstraint(SpringLayout.NORTH, c, 6, SpringLayout.NORTH, frame.getContentPane());
frame.getContentPane().setLayout(springLayout);
frame.setSize(500, 150);
frame.setLocation(400, 200);
frame.setResizable(false);
c.setBackground(UIManager.getColor("ComboBox.disabledBackground"));
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e)
{
System.out.print("What I want:");
ind = c.getSelectedIndex();
System.out.println(ind);
frame.setVisible(false);
}
});
frame.getContentPane().add(c);
btnNewButton.setForeground(UIManager.getColor("ComboBox.buttonDarkShadow"));
btnNewButton.setBackground(UIManager.getColor("EditorPane.disabledBackground "));
frame.getContentPane().add(btnNewButton);
frame.setVisible(true);
System.out.print("What I get: ");
System.out.println(ind);
}
}
I need to access the ind inside the main as mentioned before
Here when I print out the ind I get zero despite whatever choice I make inside the combobox.
OK, I'm going to guess since you've yet to show us enough information to do more than this, but I assume that:
You're showing a 2nd window as a dialog off of a main window
That this 2nd window is a JFrame and holds your JComboBox and the button
That you're making it invisible on button push,
That you try to get the information from the combobox, but it's always 0
And this may be because you're getting the information before the user has had a chance to interact with the 2nd window.
If so, the solution is to make the 2nd window a modal dialog window such as a modal JDialog and not a JFrame. This way, the calling code will know exactly when the 2nd window is no longer visible since the calling code's code flow will be blocked until the 2nd window is no longer visible.
Edit
Proof of concept: Change your code from:
final JFrame frame = new JFrame();
to:
// rename frame variable to dialog for clarity
final JDialog dialog = new JDialog();
dialog.setModalityType(ModalityType.APPLICATION_MODAL);
and it works.
But again, I'd get rid of unnecessary statics and get rid of doing too much code in the main method. For instance,...
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import java.awt.Dialog.ModalityType;
import java.awt.Dimension;
import java.awt.Window;
import java.awt.event.ActionEvent;
#SuppressWarnings("serial")
public class MinimalExProgram3 extends JPanel {
private static void createAndShowGui() {
MainPanel mainPanel = new MainPanel();
JFrame frame = new JFrame("MinimalExProgram3");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
#SuppressWarnings("serial")
class MainPanel extends JPanel {
private static final int PREF_W = 400;
private static final int PREF_H = PREF_W;
private JTextField field = new JTextField(8);
private ComboPanel comboPanel = new ComboPanel();
JDialog dialog = null;
public MainPanel() {
field.setFocusable(false);
add(field);
add(new JButton(new ShowComboAction("Show Combo")));
}
#Override // make it bigger
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
}
return new Dimension(PREF_W, PREF_H);
}
private class ShowComboAction extends AbstractAction {
public ShowComboAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
Window mainWin = SwingUtilities.getWindowAncestor(MainPanel.this);
if (dialog == null) {
dialog = new JDialog(mainWin, "Dialog", ModalityType.APPLICATION_MODAL);
dialog.add(comboPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
}
dialog.setVisible(true);
// code called here after dialog no longer visible
String text = comboPanel.getText();
field.setText(text);
}
}
}
#SuppressWarnings("serial")
class ComboPanel extends JPanel {
private static final String[] DESCRIPTION = { "One", "Two", "Three" };
private int ind;
private JComboBox<String> combo = new JComboBox<>(DESCRIPTION);
private String text;
private SelectionAction selectionAction = new SelectionAction("Select");
private JButton selectionButton = new JButton(selectionAction);
public ComboPanel() {
add(combo);
add(selectionButton);
combo.setAction(selectionAction);
}
public int getInd() {
return ind;
}
public String getText() {
return text;
}
private class SelectionAction extends AbstractAction {
public SelectionAction(String name) {
super(name);
int mnemonic = (int) name.charAt(0);
putValue(MNEMONIC_KEY, mnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
ind = combo.getSelectedIndex();
if (ind >= 0) {
text = combo.getSelectedItem().toString();
}
Window win = SwingUtilities.getWindowAncestor(ComboPanel.this);
win.dispose();
}
}
}