I get a stack overflow error - java

I'm trying to create a program where you press start and a new JFrame comes up with 3 buttons , you have to switch the button after you click on it using a random , I'm fairly new to java so I don't know what to do. Thank you
package code;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.Timer;
public class StartListener implements java.awt.event.ActionListener {
private int counter;
private Game Ga;
private JFrame z;
private int x;
public StartListener(Game a, int co){
Ga=a;
counter = co;
}
public void actionPerformed(ActionEvent e) {
Timer time = new Timer(10000,new Time(Ga));
time.start();
z = new JFrame("Sequence game");
FlowLayout fl = new FlowLayout(0, 50, 40);
z.getContentPane().setLayout(fl);
z.setVisible(true);
JButton a = new JButton("A");
Font f = a.getFont();
Font myFont = f.deriveFont(Font.BOLD, f.getSize()*4);
a.setSize(200,100);
a.setVisible(true);
JButton b = new JButton("B");
b.setVisible(true);
b.setSize(200,100);
JButton c = new JButton("C");
c.setVisible(true);
c.setSize(200,100);
z.getContentPane().add(a);
z.getContentPane().add(b);
z.getContentPane().add(c);
z.pack();
Random r = new Random();
x=r.nextInt(3);
figure(a,b,c,x,myFont,f);}
public void figure(JButton a,JButton b, JButton c, int x, Font myFont,Font f){
if(x==0){
a.setEnabled(true);
b.setEnabled(false);
c.setEnabled(false);
a.setFont(myFont);
b.setFont(f);
c.setFont(f);
x =buttonA(a);
figure(a,b,c,x,myFont,f);
;}
else if(x==1){
a.setEnabled(false);
b.setEnabled(true);
c.setEnabled(false);
a.setFont(f);
c.setFont(f);
b.setFont(myFont);
x = buttonB(b);
figure(a,b,c,x,myFont,f);
}
else if(x==2){
a.setEnabled(false);
b.setEnabled(false);
c.setEnabled(true);
a.setFont(f);
b.setFont(f);
c.setFont(myFont);
x = buttonC(c);
figure(a,b,c,x,myFont,f);
}
}
public int buttonA(JButton a){
Random r = new Random();
int rand = 0;
a.addActionListener(new Something(Ga));
rand = r.nextInt(3);
return rand;
}
public int buttonB(JButton b){
Random r = new Random();
int rand = 0;
b.addActionListener(new Something(Ga));
rand=r.nextInt(3);
return rand;
}
public int buttonC(JButton c){
Random r = new Random();
int rand=0;
c.addActionListener(new Something(Ga));
rand = r.nextInt(3);
return rand;
}
}
And here's the code for Something
package code;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Something implements ActionListener {
private Game G;
public Something(Game a){
G = a;
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
G.increment();
}
}
Here's the error :
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.awt.Component.enable(Unknown Source)
at java.awt.Component.setEnabled(Unknown Source)
at javax.swing.JComponent.setEnabled(Unknown Source)
at javax.swing.AbstractButton.setEnabled(Unknown Source)

Your figure method continuously calls itself recursively forever, or until stack space runs out. Solution: get rid of those recursive calls. Also you really don't want to keep adding multiple ActionListeners on to JButtons, all this suggesting that you will want to refactor and perhaps redesign the entire program.
You will want to change the state of a field in the class, and use that field's state to decide what to do within the ActionListener.
For example:
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
#SuppressWarnings("serial")
public class SwapButtons extends JPanel {
private static final Font ACTIVE_FONT = new Font(Font.DIALOG, Font.BOLD, 15);
private static final String[] BTN_TEXT = { "Monday", "Tuesday", "Wednesday" };
private static final int EXTRA_WIDTH = 50;
private List<AbstractButton> buttonList = new ArrayList<>();
private int buttonIndex = 0;
public SwapButtons() {
setLayout(new GridLayout(1, 0, 5, 0));
BtnListener btnListener = new BtnListener();
for (int i = 0; i < BTN_TEXT.length; i++) {
JButton button = new JButton(BTN_TEXT[i]);
button.addActionListener(btnListener);
buttonList.add(button); // add to ArrayList
add(button); // add to GUI
}
setActiveButton();
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
}
#Override
public Dimension getPreferredSize() {
Dimension superSz = super.getPreferredSize();
if (isPreferredSizeSet()) {
return superSz;
}
// give preferred size extra width so gui can handle larger fonts
int prefW = superSz.width + EXTRA_WIDTH;
int prefH = superSz.height;
return new Dimension(prefW, prefH);
}
private void setActiveButton() {
// iterate through buttonList, turning on the "active" button
// as determined by the buttonIndex variable
for (int i = 0; i < buttonList.size(); i++) {
if (i == buttonIndex) {
buttonList.get(i).setFont(ACTIVE_FONT);
buttonList.get(i).setEnabled(true);
} else {
buttonList.get(i).setFont(null);
buttonList.get(i).setEnabled(false);
}
}
}
private class BtnListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
// show which button pressed
System.out.println("Button Pressed: " + e.getActionCommand());
// advance button index so that next button can be activated
buttonIndex++;
// but change index to 0 if buttonList size is reached
buttonIndex %= buttonList.size();
// activate the next button:
setActiveButton();
}
}
private static void createAndShowGui() {
SwapButtons mainPanel = new SwapButtons();
JFrame frame = new JFrame("Swap Buttons");
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

Click Event - Accessing a boolean variable from another class [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
Stuck on a problem that requires grabbing a boolean variable from another class.
I have the following for-loop, boolean and if-else statements
import java.awt.*;
import javax.swing.*;
import java.awt.Color.*;
import java.awt.event.MouseListener;
import java.awt.event.MouseEvent;
import java.util.Random;
public class Checkers extends JFrame
{
Random random = new Random();
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private int i;
private int score;
private JPanel pane = new JPanel(new GridLayout(ROWS,COLS, GAP,GAP));
private JPanel pane2 = new JPanel();
private JPanel pane3 = new JPanel();
private JButton btn1 = new JButton("Play A Game");
private JButton btn2 = new JButton("Exit");
private JButton btn3 = new JButton("Easy");
private JButton btn4 = new JButton("Intermediate");
private JButton btn5 = new JButton("Difficult");
private JLabel lbl1 = new JLabel ("score: " + score);
private JLabel gameLost = new JLabel("You lose! You got: " + score + " points");
private JButton btnRestart = new JButton("Restart");
private MyPanel [] panel = new MyPanel[NUM];
private Color col1 = Color.RED;
private Color col2 = Color.WHITE;
private Color col3 = Color.GREEN;
private Color tempColor;
private boolean isPanelDisabled;
//Starts the checkers GUI, calling the constructor below this.
public static void main(String[] args){
new Checkers();
}
//Sets the dimensions of the GUI, visibility, background color and
//contents via the setBoard();
public Checkers()
{
super("Checkers");
setSize(600,600);
setVisible(true);
setBackground(Color.BLACK);
setBoard();
}
//Makes the grid, contains a conditional boolean, adds the panels to grid based on i value.
//sets Colours accordingly
public void setBoard()
{
boolean isPanelDisabled = false;
for (int i = 0; i < panel.length; i++) {
panel[i] = new MyPanel(this);
pane.add(panel[i]);
if (i % COLS == 0) {
tempColor = col1;
}
if (i == 9 || i <8) {
panel[i].setBackground(col1);
}
if(i == 8){
isPanelDisabled = true;
panel[i].setBackground(col3);
}
}
//pane background colour and the size of this pane.
pane.setBackground(Color.BLACK);
pane.setPreferredSize(new Dimension(300,300));
//pane background colour and size of this pane.
pane2.setBackground(Color.white);
pane2.setPreferredSize(new Dimension(300,300));
//directions on the board where these panes appear.
add(pane, BorderLayout.WEST);
add(pane2, BorderLayout.EAST);
pane2.add(lbl1);
pane2.add(btnRestart);
btnRestart.addActionListener( e -> restartBoard());
pane2.setLayout(new BoxLayout(pane2, BoxLayout.PAGE_AXIS));
}
//increments the score for the user based on current points.
public void incrementScore(){
if (score != 5){
score++;
lbl1.setText("Score: " + Integer.toString(score));
}
else if(score == 5){
lbl1.setText("Congratulations!, you've won!, your score is:" + score);
}
}
}
and this mouseClicked Event
import java.awt.Color;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.*;
import java.awt.event.*;
import javax.swing.JPanel;
public class MyPanel extends JPanel implements MouseListener, ActionListener {
private final Checkers checkers;
private boolean isPanelDisabled;
//MyPanel Constructor that initiates a instance of checkers.
public MyPanel(Checkers checkers) {
this.checkers = checkers;
addMouseListener(this);
}
#Override
public void actionPerformed(ActionEvent e){
}
// Sets the panel colours according to their int number and the boolean condiiton.
#Override
public void mouseClicked(MouseEvent e) {
if (isPanelDisabled == true){
setBackground(Color.CYAN);
}
else{
setBackground(Color.BLACK);
checkers.incrementScore();
}
}
My Expected result of this should be that if the user clicks the 8th panel in that grid, then the color of that panel will be cyan when pressed and not black, but it cant access the boolean variable? where am i going wrong here?
Your question involves communication between objects of different classes, and there are several ways to do this, but most basic is to call a method of an object in one class to the other.
First lets set up the problem,... I've created classes called MyPanel2 and Checkers2, to distinguish them from yours.
Say in MyPanel2 we have a Checkers2 field and a boolean field called selected that is set to false:
private Checkers2 checkers;
private boolean selected = false;
along with appropriate boolean getter and setter:
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
And say within the Checkers2 class you have a 10 instances of MyPanel2 held within an array, and you want the user to be able to "select" instances of the class, but only allow 7 of them to be selected, and assume that you want to user the set up that you're currently using, you could give the main class, a method, public boolean isPanelDisabled(), and have the MyPanel2 class call this method to determine if selection is allowed. So within MyPanel2 you could have a MouseListener with something like:
#Override
public void mousePressed(MouseEvent e) {
if (selected) {
return;
}
// call the Checkers2 boolean method to check
if (checkers.isPanelDisabled()) {
setBackground(DISABLED_COLOR);
} else {
setBackground(SELECTED_COLOR);
setSelected(true);
}
}
Within Checkers2 .isPanelDisabled() method you'd iterate through the array of MyPanel2 instances to see how many have been selected, something like this could work:
public boolean isPanelDisabled() {
int count = 0;
for (MyPanel2 panel2 : myPanels) {
if (panel2.isSelected()) {
count++;
}
}
return count >= MAX_COUNT;
}
The whole MCVE testable code could look like:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Checkers2 extends JFrame {
private static final int MAX_COUNT = 7;
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private MyPanel2[] myPanels = new MyPanel2[NUM];
public Checkers2() {
super("Checkers");
setDefaultCloseOperation(EXIT_ON_CLOSE);
JPanel gridPanel = new JPanel(new GridLayout(ROWS, COLS, 1, 1));
gridPanel.setBackground(Color.BLACK);
gridPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
for (int i = 0; i < myPanels.length; i++) {
MyPanel2 myPanel = new MyPanel2(this);
gridPanel.add(myPanel);
myPanels[i] = myPanel;
}
JButton resetButton = new JButton("Reset");
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(evt -> {
for (MyPanel2 myPanel2 : myPanels) {
myPanel2.reset();
}
});
JButton exitButton = new JButton("Exit");
exitButton.setMnemonic(KeyEvent.VK_X);
exitButton.addActionListener(evt -> System.exit(0));
JPanel buttonPanel = new JPanel();
buttonPanel.add(resetButton);
add(gridPanel);
add(buttonPanel, BorderLayout.PAGE_END);
pack();
setLocationRelativeTo(null);
}
public boolean isPanelDisabled() {
int count = 0;
for (MyPanel2 panel2 : myPanels) {
if (panel2.isSelected()) {
count++;
}
}
return count >= MAX_COUNT;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new Checkers2().setVisible(true);
});
}
}
class MyPanel2 extends JPanel {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GR = 240;
public static final Color BASE_COLOR = new Color(GR, GR, GR);
public static final Color DISABLED_COLOR = Color.CYAN;
public static final Color SELECTED_COLOR = Color.BLACK;
private Checkers2 checkers;
private boolean selected = false;
public MyPanel2(Checkers2 checkers) {
setBackground(BASE_COLOR);
this.checkers = checkers;
setPreferredSize(new Dimension(PREF_W, PREF_H));
addMouseListener(new MyMouse());
}
public void setSelected(boolean selected) {
this.selected = selected;
}
public boolean isSelected() {
return selected;
}
public void reset() {
setBackground(BASE_COLOR);
setSelected(false);
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
if (selected) {
return;
}
if (checkers.isPanelDisabled()) {
setBackground(DISABLED_COLOR);
} else {
setBackground(SELECTED_COLOR);
setSelected(true);
}
}
}
}
Another Option is to take all the logic out of MyPanel and put it into the main program, something like:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class Checkers3 extends JPanel {
private static final int MAX_COUNT = 7;
private final int ROWS = 2;
private final int COLS = 5;
private final int GAP = 2;
private final int NUM = ROWS * COLS;
private MyPanel3[] myPanels = new MyPanel3[NUM];
public Checkers3() {
JPanel gridPanel = new JPanel(new GridLayout(ROWS, COLS, 1, 1));
gridPanel.setBackground(Color.BLACK);
gridPanel.setBorder(BorderFactory.createLineBorder(Color.BLACK));
MyMouse myMouse = new MyMouse();
for (int i = 0; i < myPanels.length; i++) {
MyPanel3 myPanel = new MyPanel3();
myPanel.addMouseListener(myMouse);
gridPanel.add(myPanel);
myPanels[i] = myPanel;
}
JButton resetButton = new JButton("Reset");
resetButton.setMnemonic(KeyEvent.VK_R);
resetButton.addActionListener(evt -> {
for (MyPanel3 myPanel : myPanels) {
myPanel.reset();
}
});
JButton exitButton = new JButton("Exit");
exitButton.setMnemonic(KeyEvent.VK_X);
exitButton.addActionListener(evt -> System.exit(0));
JPanel buttonPanel = new JPanel();
buttonPanel.add(resetButton);
setLayout(new BorderLayout());
add(gridPanel);
add(buttonPanel, BorderLayout.PAGE_END);
}
public boolean isPanelDisabled() {
int count = 0;
for (MyPanel3 panel : myPanels) {
if (panel.isSelected()) {
count++;
}
}
return count >= MAX_COUNT;
}
private class MyMouse extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
MyPanel3 myPanel = (MyPanel3) e.getSource();
if (myPanel.isSelected()) {
return; // it's already selected
} else if (isPanelDisabled()) {
myPanel.setSelected(false);
} else {
myPanel.setSelected(true);
}
}
}
private static void createAndShowGui() {
Checkers3 mainPanel = new Checkers3();
JFrame frame = new JFrame("Checkers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
}
#SuppressWarnings("serial")
class MyPanel3 extends JPanel {
private static final int PREF_W = 200;
private static final int PREF_H = PREF_W;
private static final int GR = 240;
public static final Color BASE_COLOR = new Color(GR, GR, GR);
public static final Color DISABLED_COLOR = Color.CYAN;
public static final Color SELECTED_COLOR = Color.BLACK;
private boolean selected = false;
public MyPanel3() {
setBackground(BASE_COLOR);
setPreferredSize(new Dimension(PREF_W, PREF_H));
}
public void setSelected(boolean selected) {
this.selected = selected;
Color background = selected ? SELECTED_COLOR : DISABLED_COLOR;
setBackground(background);
}
public boolean isSelected() {
return selected;
}
public void reset() {
setSelected(false);
setBackground(BASE_COLOR);
}
}
But the BEST option is to put all logic within a separate model class (or classes) and make the GUI's as dumb as possible.

JButton size & location

Hello fellow programmers! I'm starting to learn java, and as a project, i put in my mind to make a visual calculator. My problem is that i can't set an exact location or size for my button, and i would like some help please!
import javax.swing.*;
import java.awt.*;
public class Calculator{
public static void main(String[] args) {
//Frame & sizes
JFrame f = new JFrame("Calculator");
f.setSize(400, 500);
f.setLocation(300,200);
//Text area
final JTextArea textArea = new JTextArea(10, 40);
f.getContentPane().add(BorderLayout.NORTH, textArea);
//Buttons
final JButton button1 = new JButton("1");
button1.setBounds(160, 100, 410, 100);
}
}
There is a lot of additional set-up you need to do, for a tutorial please refer to this article. They do a great job walking you through the steps, I simply pasted the final solution if you want to try it out on your end. To replicate simply create a new Java class called JavaCalculator and run the main method, hopefully this helps!
JavaCalculator:
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.JButton;
import java.awt.Container;
public class JavaCalculator implements ActionListener{
JFrame guiFrame;
JPanel buttonPanel;
JTextField numberCalc;
int calcOperation = 0;
int currentCalc;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable()
{
public void run()
{
new JavaCalculator();
}
});
}
public JavaCalculator()
{
guiFrame = new JFrame();
guiFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
guiFrame.setTitle("Simple Calculator");
guiFrame.setSize(300,300);
guiFrame.setLocationRelativeTo(null);
numberCalc = new JTextField();
numberCalc.setHorizontalAlignment(JTextField.RIGHT);
numberCalc.setEditable(false);
guiFrame.add(numberCalc, BorderLayout.NORTH);
buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(4,4));
guiFrame.add(buttonPanel, BorderLayout.CENTER);
for (int i=0;i<10;i++)
{
addNumberButton(buttonPanel, String.valueOf(i));
}
addActionButton(buttonPanel, 1, "+");
addActionButton(buttonPanel, 2, "-");
addActionButton(buttonPanel, 3, "*");
addActionButton(buttonPanel, 4, "/");
addActionButton(buttonPanel, 5, "^2");
JButton equalsButton = new JButton("=");
equalsButton.setActionCommand("=");
equalsButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent event)
{
if (!numberCalc.getText().isEmpty())
{
int number = Integer.parseInt(numberCalc.getText());
if (calcOperation == 1)
{
int calculate = currentCalc + number;
numberCalc.setText(Integer.toString(calculate));
}
else if (calcOperation == 2)
{
int calculate = currentCalc - number;
numberCalc.setText(Integer.toString(calculate));
}
else if (calcOperation == 3)
{
int calculate = currentCalc * number;
numberCalc.setText(Integer.toString(calculate));
}
else if (calcOperation == 4)
{
int calculate = currentCalc / number;
numberCalc.setText(Integer.toString(calculate));
}
else if (calcOperation == 5)
{
int calculate = currentCalc * currentCalc;
numberCalc.setText(Integer.toString(calculate));
}
}
}
});
buttonPanel.add(equalsButton);
guiFrame.setVisible(true);
}
private void addNumberButton(Container parent, String name)
{
JButton but = new JButton(name);
but.setActionCommand(name);
but.addActionListener(this);
parent.add(but);
}
private void addActionButton(Container parent, int action, String text)
{
JButton but = new JButton(text);
but.setActionCommand(text);
OperatorAction addAction = new OperatorAction(1);
but.addActionListener(addAction);
parent.add(but);
}
public void actionPerformed(ActionEvent event)
{
String action = event.getActionCommand();
numberCalc.setText(action);
}
private class OperatorAction implements ActionListener
{
private int operator;
public OperatorAction(int operation)
{
operator = operation;
}
public void actionPerformed(ActionEvent event)
{
currentCalc = Integer.parseInt(numberCalc.getText());
calcOperation = operator;
}
}
}

Image did not fresh in Frame on Mouse Click In Java

First Time three random images shown on Jframe from three diffrent arrays.
even MouseClicked Method triggered but images does not refresh in Frame.
I want to refresh three random images each time i click on Frame.
Please help
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.*;
public class Cards extends JFrame implements MouseListener {
public static void main(String[] args) {
JFrame frame = new Cards();
frame.setTitle("Cards");
frame.setSize(500, 500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
new Cards();
}
public Cards() {
this.getContentPane().addMouseListener(this);
cards1();
cards2();
cards3();
}
public void cards1() {
ImageIcon[] images = new ImageIcon[10];
for (int i = 1; i < images.length; i++) {
images[i] = new ImageIcon("Drawables//Images//" + i + ".png");
}
int[] threeRandoms = new int[1];
Random ran = new Random();
for (int i = 0; i < threeRandoms.length; i++) {
threeRandoms[i] = ran.nextInt(10);
}
setLayout(new GridLayout(1, 4, 5, 5));
add(new JLabel(images[threeRandoms[0]]));
}
public void cards2() {
ImageIcon[] images = new ImageIcon[10];
for (int i = 1; i < images.length; i++) {
images[i] = new ImageIcon("Drawables//Images1//" + i + ".png");
}
int[] threeRandoms = new int[1];
Random ran = new Random();
for (int i = 0; i < threeRandoms.length; i++) {
threeRandoms[i] = ran.nextInt(10);
}
setLayout(new GridLayout(1, 4, 5, 5));
add(new JLabel(images[threeRandoms[0]]));
}
public void cards3() {
// this.getContentPane().addMouseListener(this);
ImageIcon[] images = new ImageIcon[10];
for (int i = 1; i < images.length; i++) {
images[i] = new ImageIcon("Drawables//Images2//" + i + ".png");
}
int[] threeRandoms = new int[1];
Random ran = new Random();
for (int i = 0; i < threeRandoms.length; i++) {
threeRandoms[i] = ran.nextInt(10);
}
// Labels with gridLayout
setLayout(new GridLayout(1, 4, 5, 5));
add(new JLabel(images[threeRandoms[0]]));
}
public void mouseClicked(MouseEvent e) {
System.out.println("The frame was clicked.");
new Cards();
}
public void mouseEntered(MouseEvent e) {
System.out.println("The mouse entered the frame.");
}
public void mouseExited(MouseEvent e) {
System.out.println("The mouse exited the frame.");
}
public void mousePressed(MouseEvent e) {
System.out.println("The left mouse button was pressed.");
}
public void mouseReleased(MouseEvent e) {
System.out.println("The left mouse button was released.");
}
}
I'm sorry, but I'm confused by your code. For one thing your cards1(), cards2() and cards3() methods look to be all the very same, and if so, why 3 different methods? Why not just one method? In those methods you appear to be trying to add JLabels repeatedly. Are you trying to add many many JLabels to the GUI? Or are you simply trying to display 3 images that change randomly on mouse action?
I would recommend structuring things a bit differently:
If possible, read all necessary images in once in your class's constructor, put the images into ImageIcons and then add them to an ArrayList or several ArrayLists if need be.
Don't add new JLabels each time a mouseClick occurs.
Create a JPanel give it a GridLayout and in your class constructor add to it three JLabels that are either instance fields or in an array or ArrayList.
Add this JPanel to your JFrame.
Add a MouseListener to each JLabel
in that MouseListener's mousePressed(MouseEvent e) method (not mouseClicked) randomize your number and use that number to call setIcon(...) on the JLabel source, obtained by calling getSource() on your MouseEvent parameter.
For example:
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.*;
#SuppressWarnings("serial")
public class RandomImages extends JPanel {
private static final int LABEL_COUNT = 3;
private Random random = new Random();
public RandomImages() {
setLayout(new GridLayout(1, 3));
for (int i = 0; i < LABEL_COUNT; i++) {
final List<Icon> iconList = new ArrayList<>();
// TODO: get images for the ith list
// and fill iconList with ImageIcons from the first grouping
// create JLabel and give it the first Icon from the List above
final JLabel label = new JLabel(iconList.get(0));
label.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
// get random number from random object using iconList.size()
// get random Icon from list
// set label's icon via setIcon(...)
}
});
// add to GUI
add(label);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("RandomImages");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new RandomImages());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
Concrete example 2:
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class RandomChessMen extends JPanel {
// for this example I get a sprite sheet that holds several sprite images in it
// the images can be found here: http://stackoverflow.com/questions/19209650
private static final String IMAGE_PATH = "http://i.stack.imgur.com/memI0.png";
private static final int LABEL_COUNT = 2;
private static final int ICON_COLUMNS = 6;
private Random random = new Random();
public RandomChessMen() throws IOException {
URL url = new URL(IMAGE_PATH);
BufferedImage largeImg = ImageIO.read(url);
setLayout(new GridLayout(1, 0));
// break down large image into its constituent sprites and place into ArrayList<Icon>
int w = largeImg.getWidth() / ICON_COLUMNS;
int h = largeImg.getHeight() / LABEL_COUNT;
for (int i = 0; i < LABEL_COUNT; i++) {
final List<Icon> iconList = new ArrayList<>();
int y = (i * largeImg.getHeight()) / LABEL_COUNT;
// get 6 icons out of large image
for (int j = 0; j < ICON_COLUMNS; j++) {
int x = (j * largeImg.getWidth()) / ICON_COLUMNS;
// get subImage
BufferedImage subImg = largeImg.getSubimage(x, y, w, h);
// create ImageIcon and add to list
iconList.add(new ImageIcon(subImg));
}
// create JLabel
final JLabel label = new JLabel("", SwingConstants.CENTER);
int eb = 40;
label.setBorder(BorderFactory.createEmptyBorder(eb, eb, eb, eb));
// get random index for iconList
int randomIndex = random.nextInt(iconList.size());
Icon icon = iconList.get(randomIndex); // use index to get random Icon
label.setIcon(icon); // set label's icon
label.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
Icon secondIcon = label.getIcon();
// so we don't repeat icons
while (label.getIcon() == secondIcon) {
int randomIndex = random.nextInt(iconList.size());
secondIcon = iconList.get(randomIndex);
}
label.setIcon(secondIcon);
}
});
// add to GUI
add(label);
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("RandomImages");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
frame.getContentPane().add(new RandomChessMen());
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
I have made these changes to your code:
Instead of having three methods cards1() cards2() cards3(), i have just made one cards() method.
Everytime you click on the frame, three random images get loaded.
I have set every image inside a JLabel in order to make it easy to update it.
The code below works perfectly according to your needs.
package example;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class Cards extends JFrame implements MouseListener {
JPanel subPanel1;
JLabel label1, label2, label3;
static ImageIcon[] images ;
static Random ran ;
static int[] threeRandoms;
public Cards() {
super("Cards");
subPanel1 = new JPanel();
// Set up first subpanel
subPanel1.setPreferredSize (new Dimension(400, 400));
//subPanel1.setBackground (Color.cyan);
label1 = new JLabel ("image 1",SwingConstants.CENTER);
label2 = new JLabel ("image 2", SwingConstants.LEFT);
label3 = new JLabel ("image 3", SwingConstants.CENTER);
subPanel1.add (label1);
subPanel1.add (label2);
subPanel1.add (label3);
add(subPanel1);
addMouseListener(this);
setSize(500, 500);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
setLocationRelativeTo(null);
setVisible(true);
System.out.println("Success.....");
}
public void cards() {
for (int i = 0; i < threeRandoms.length; i++)
threeRandoms[i] = ran.nextInt(3);
label1.setIcon(images[threeRandoms[0]]);
label2.setIcon(images[threeRandoms[1]]);
label3.setIcon(images[threeRandoms[2]]);
}
#Override
public void mouseClicked(MouseEvent e) {
System.out.println("mouseClicked");
cards();
}
#Override
public void mouseEntered(MouseEvent e) {
System.out.println("mouseEntered");
}
#Override
public void mouseExited(MouseEvent e) {
System.out.println("mouseExited");
}
#Override
public void mousePressed(MouseEvent e) {
System.out.println("mousePressed");
}
#Override
public void mouseReleased(MouseEvent e) {
System.out.println("mouseReleased");
}
public static void loadImages(){
images = new ImageIcon[4];
ran = new Random();
threeRandoms = new int[3];
for (int i = 1; i <= images.length; i++) {
images[i-1] = new ImageIcon("Drawables//Images//" + i + ".png");
}
}
public static void main(String[] args) {
loadImages();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Cards();
}
});
}
}

Java Applet - For Loop to decrement a stack of components

I've created an Applet that creates a row of buttons, up to 15 buttons, when you push the "add to queue" button. I now want to decrement that row using a for loop. I want it to decrement from left to right. I can only get it to decrement from right to left. I know it has to do with the code in my "Remove" method, but I can't seem to figure out how to fix it. As a newbie I would appreciate any help you can provide.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
public class Main extends javax.swing.JApplet {
private final int width = 60;
private final int height = 24;
private final int maxItems = 15;
private int x = 40 + width;
private int y = 260;
private int count = 1;
private JButton jAdd;
private JButton jRemove;
Vector<JButton> stack = new Vector<JButton>();
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
Main inst = new Main();
frame.getContentPane().add(inst);
((JComponent) frame.getContentPane()).setPreferredSize(inst
.getSize());
frame.pack();
frame.setVisible(true);
}
});
}
public Main() {
super();
initGUI();
}
private void initGUI() {
try {
this.setSize(719, 333);
getContentPane().setLayout(null);
{
jAdd = new JButton();
getContentPane().add(jAdd);
jAdd.setText("Add to Queue");
jAdd.setBounds(43, 300, 150, 24);
jAdd.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jAddActionPerformed(evt);
}
});
}
{
jRemove = new JButton();
getContentPane().add(jRemove);
jRemove.setText("Remove from queue");
jRemove.setBounds(950, 300, 150, 24);
jRemove.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
jRemoveActionPerformed(evt);
}
});
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void jAddActionPerformed(ActionEvent evt) {
if (count > maxItems) {
JOptionPane.showMessageDialog(null, "The queue is full");
return;
}
JButton b = new JButton();
stack.add(0, b);
getContentPane().add(b);
int textCount = count;
b.setText("" +textCount++);
b.setBounds(x, y, width, height);
x = x + width;
count++;
}
private void jRemoveActionPerformed(ActionEvent evt) {
if (stack.isEmpty()) {
JOptionPane.showMessageDialog(null, "The queue is empty");
return;
}
JButton b = stack.remove(0);
this.remove(b);
for(int originalX = 880; originalX < 880; originalX--){
x = 880 - width;
}
repaint();
count--;
}
}
The issue is this:
stack.add(0, b);
You are always adding the new one to the start of the Vector (index 0). Remove that and you will see the behavior you want.
stack.add(b);

JPanel in puzzle game not updating

I have a simple puzzle game. There is an image consisting of 16 tiles (randomly placed). Images are stored in an array and when game is launched they're added to main JPanel.
Game works in this way : Each image has atributes 'place' and 'number'. 'Place' is the current place on grid (either correct or not) and 'number' is the desired place for the image. When a user clicks image their 'place' and 'number' attributes are checked. If they match nothing happens. If not game checks if any image is currently in memory. If there is none, then this image's 'place' and 'number' are stored. If there is some image in memory, then the currently clicked image's 'plac'e is checked with stored image's 'number'. When they match - their places are exchanged. This part works properly. But now, I'm calling addComponent method on my JPanel with updated images and simply nothing happens. Shouldn't the new images be added to JPanel replacing the old ones ?
package Bonus;
import javax.swing.*;
import java.util.Random;
import java.awt.event.*;
import java.awt.*;
class Puzzle extends JPanel implements ActionListener {
private int selected_nr=-1;
private int selected_pl=-1;
private boolean memory=false;
private static Img[] images;
public Puzzle(){
JFrame f = new JFrame("Smile");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.setSize(252,252);
f.setVisible(true);
setLayout(new GridLayout(4, 4));
images = new Img[16];
int[] buttons = new int[16];
for(int i=0; i<16; i++){
buttons[i] = i;
}
int rand;
int temp;
Random random;
random = new Random(System.currentTimeMillis());
for (int i = 0; i < buttons.length; i++) {
rand = (random.nextInt() & 0x7FFFFFFF) % buttons.length;
temp = buttons[i];
buttons[i] = buttons[rand];
buttons[rand] = temp;
}
for (int i = 0; i < 16; i++) {
images[i] = new Img(i, buttons[i]);
}
addComponents(images);
}
public void addComponents(Img[] im){
this.removeAll();
for(int i=0; i<16; i++){
im[i].addActionListener(this);
im[i].setPreferredSize(new Dimension(53,53));
add(im[i]);
}
this.validate();
}
public void actionPerformed(ActionEvent e) {
Img b = (Img)(e.getSource());
int num = b.getNumber();
int pl = b.getPlace();
if(!(b.rightPlace())){
if(memory){
if(pl == selected_nr){
images[pl].setPlace(selected_pl);
images[selected_pl].setPlace(selected_nr);
selected_nr = -1;
selected_pl = -1;
memory = false;
addComponents(images);
}
else{
System.out.println("Try other image");
}
}
else{
memory = true;
selected_nr = num;
selected_pl = pl;
}
}
else{
System.out.println("OK !");
}
}
public static void main(String args[]) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Puzzle();
}
});
}
}
class Img extends JButton {
int number;
int place;
ImageIcon img;
public Img(int p, int n){
number = n;
place = p;
img = new ImageIcon("u"+number+".jpg", BorderLayout.CENTER);
setIcon(img);
}
public boolean rightPlace(){
boolean correct=false;
if(number == place){
correct = true;
}
return correct;
}
public void setPlace(int i){
place = i;
}
public int getNumber(){
return number;
}
public int getPlace(){
return place;
}
}
EDIT: Changed the code to use the answers, but still no luck. addComponents() gets updated images[] but doesn't revalidate them.
Rather than relying on precut image files, here's an example of slicing an existing image and shuffling the resulting pieces. It combines the helpful (+1) suggestions of both #Frederick and #akf.
import java.awt.EventQueue;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
public class ImageLabelPanel extends JPanel implements ActionListener {
private static final int N = 4;
private final List<JLabel> list = new ArrayList<JLabel>();
private final Timer timer = new Timer(1000, this);
ImageLabelPanel() {
this.setLayout(new GridLayout(N, N));
BufferedImage bi = null;
try {
bi = ImageIO.read(new File("image.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
for (int r = 0; r < N; r++) {
for (int c = 0; c < N; c++) {
int w = bi.getWidth() / N;
int h = bi.getHeight() / N;
BufferedImage b = bi.getSubimage(c * w, r * h, w, h);
list.add(new JLabel(new ImageIcon(b)));
}
}
createPane();
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(this);
f.pack();
f.setVisible(true);
timer.start();
}
private void createPane() {
this.removeAll();
for (JLabel label : list) add(label);
this.validate();
}
#Override
public void actionPerformed(ActionEvent e) {
Collections.shuffle(list);
createPane();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ImageLabelPanel();
}
});
}
}
You are adding all of your components again to your JPanel without actually removing any of them. In your addComponents() method, I would first call removeAll(). You might want to rename that method to highlight the side-effects, as it no longer would only be adding components. Perhaps, resetComponents() would be better.
After changing the components, you need to 'refresh' the Swing component by calling invalidate() or revalidate().

Categories