Newbie: Can't figure out why GUI is freezing

Hello, I am trying to make my very first program with Swing, and I cannot figure out why it freezes and what I need to do to prevent that from happening. This program simulates this game of life. If a button is selected (alive) and 2 or 3 (only) buttons surrounding it are also selected, then the button selected gets to stay selected. Otherwise it dies. Also, if an empty button is surrounded by exactly 3 selected button, it also becomes alive. Here is the code:

package learn;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

publicclass Life{

/**

* @author Michael Keselman

*/

final JLabel label =new JLabel("Empty");

finalstatic String LOOKANDFEEL ="System";

JToggleButton[] b =new JToggleButton[400];

JLabel message =new JLabel();

privateboolean f;

privatefinalint NUMRC = 20;// Number of Rows and Columns

publicstaticvoid main(String[] args){

SwingUtilities.invokeLater(new Runnable(){

publicvoid run(){

createAndShowGUI();

}

});

}

publicstaticvoid createAndShowGUI(){

initLookAndFeel();

JFrame.setDefaultLookAndFeelDecorated(true);

JFrame frame =new JFrame("Swing Application");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Life app =new Life();

Component contents1 = app.createComponents1();

Component contents2 = app.createComponents2();

frame.getContentPane().add(contents1, BorderLayout.CENTER);

frame.getContentPane().add(contents2, BorderLayout.SOUTH);

frame.pack();

frame.setSize(1200, 880);

frame.setLocationRelativeTo(null);

frame.setVisible(true);

}

public Component createComponents1(){

JPanel pane =new JPanel(new GridLayout(NUMRC, NUMRC));

for (int i = 0; i < 400; i++){

b[i] =new JToggleButton("" + i);

b[i].setForeground(Color.black);

pane.add(b[i]);

}

return pane;

}

public Component createComponents2(){

JPanel bpane =new JPanel();

JButton start =new JButton("Start!");

JButton stop =new JButton("Stop!");

stop.setToolTipText("Click here to stop the Game of Life");

start.setToolTipText("Click here to start the Game of Life");

start.addActionListener(new ActionListener(){

publicvoid actionPerformed(ActionEvent e){

SwingUtilities.invokeLater(new Runnable(){

publicvoid run(){

f =true;

while (f =true)

{

for (int i = 0; i < 400; i++){

try{

Thread.sleep(20);

}catch (InterruptedException g){

System.err.println(g);

}

int numSurround = getSurrounded(i);

if (b[i].isSelected())

{

if (numSurround < 2)

{

b[i].setText("L");

b[i].setToolTipText("Too Lonely");

b[i].setSelected(false);

}

elseif (numSurround > 3)

{

b[i].setText("C");

b[i].setToolTipText("Too Crowded");

b[i].setSelected(false);

}

}

else// not selected

{

if (numSurround == 3)

b[i].setSelected(true);

}

// try{Thread.sleep(3000);}

// catch(InterruptedException f){System.out.println(f);}

// System.out.println(i);

// message.setText("Success!");

//System.out.println(i);

//if (i == 399)

//i = -1;

}

}

}

});

}

});

stop.addActionListener(new ActionListener()

{

publicvoid actionPerformed(ActionEvent e)

{

System.out.println("Hello. Success.");

f =false;

}

});

bpane.add(message);

bpane.add(start);

bpane.add(stop);

return bpane;

}

privateint getSurrounded(int i){

int row = i / NUMRC;

int column = i % NUMRC;

int surroundCount = 0;

/*

* Left Neighbor

*/

int leftColumn = column - 1;

if (leftColumn >= 0){

if (b[getIndex(row, leftColumn)].isSelected())

++surroundCount;

}

/*

* Right Neighbor

*/

int rightColumn = column + 1;

if (rightColumn < NUMRC){

if (b[getIndex(row, rightColumn)].isSelected())

++surroundCount;

}

/*

* Top Neighbor

*/

int topRow = row - 1;

if (topRow >= 0){

if (b[getIndex(topRow, column)].isSelected())

++surroundCount;

}

/*

* Bottom Neighbor

*/

int bottomRow = row + 1;

if (bottomRow < NUMRC){

if (b[getIndex(bottomRow, column)].isSelected())

++surroundCount;

}

/*

* Upper-Left Neighbor

*/

if (topRow >= 0 && leftColumn >= 0){

if (b[getIndex(topRow, leftColumn)].isSelected())

++surroundCount;

}

/*

* Upper-Right Neighbor

*/

if (topRow >= 0 && rightColumn < NUMRC){

if (b[getIndex(topRow, rightColumn)].isSelected())

++surroundCount;

}

/*

* Bottom-Left Neighbor

*/

if (bottomRow < NUMRC && leftColumn >= 0){

if (b[getIndex(bottomRow, leftColumn)].isSelected())

++surroundCount;

}

/*

* Bottom-Right Neighbor

*/

if (bottomRow < NUMRC && rightColumn < NUMRC){

if (b[getIndex(bottomRow, rightColumn)].isSelected())

++surroundCount;

}

return surroundCount;

}

protectedint getIndex(int row,int column){

return (NUMRC * row + column);

}

privatestaticvoid initLookAndFeel(){

String lookAndFeel =null;

if (LOOKANDFEEL !=null){

if (LOOKANDFEEL.equals("Metal")){

lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();

}elseif (LOOKANDFEEL.equals("System")){

lookAndFeel = UIManager.getSystemLookAndFeelClassName();

}elseif (LOOKANDFEEL.equals("Motif")){

lookAndFeel ="com.sun.java.swing.plaf.motif.MotifLookAndFeel";

}elseif (LOOKANDFEEL.equals("GTK+")){

lookAndFeel ="com.sun.java.swing.plaf.gtk.GTKLookAndFeel";

}else{

System.err

.println("Unexpected value of LOOKANDFEEL specified: "

+ LOOKANDFEEL);

lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();

}

try{

UIManager.setLookAndFeel(lookAndFeel);

}catch (ClassNotFoundException e){

System.err

.println("Couldn't find class for specified look and feel:"

+ lookAndFeel);

System.err

.println("Did you include the L&F library in the class path?");

System.err.println("Using the default look and feel.");

}catch (UnsupportedLookAndFeelException e){

System.err.println("Can't use the specified look and feel ("

+ lookAndFeel +") on this platform.");

System.err.println("Using the default look and feel.");

}catch (Exception e){

System.err.println("Couldn't get specified look and feel ("

+ lookAndFeel +"), for some reason.");

System.err.println("Using the default look and feel.");

e.printStackTrace();

}

}

}

}

I have a strong feeling that it is because of the semi-infinite for loop in the start button's ActionEvent, but I feel that the program needs to have this because it is supposed to go on until the user presses stop. Please help!

Thank you!!

[14947 byte] By [keseldudea] at [2007-11-26 22:20:44]
# 1

while (f = true)

{

for (int i = 0; i < 400; i++) {

try {

Thread.sleep(20);

Don't really know what you are trying to do but the first thing your code does is sleep for 8 seconds (400 * 20). Then you loop again and sleep another 8 seconds. Since the sleep() method is invoked in the GUI Event Thread the GUI can never repaint itself.

If you want to do animation then use a [url http://java.sun.com/docs/books/tutorial/uiswing/misc/timer.html]Swing Timer[/url].

camickra at 2007-7-10 11:17:59 > top of Java-index,Desktop,Core GUI APIs...
# 2

Thank you! By the way, the for loop is meant to cycle through each index for b[]. However, I didn't want it to go so fast, so I had it sleep for 20 milliseconds :-\. Anyways, thank you for the Sleep Timer suggestion.

How can I use the Timer? I made Timer timer;

as a global variable, and instead of the Thread.sleep(20) business, I wrote

timer = new Timer(600, this);

timer.setInitialDelay(20);

timer.start();

Now it still doesn't work. What else do I need to add?

Message was edited by:

keseldude

Message was edited by:

keseldude

keseldudea at 2007-7-10 11:17:59 > top of Java-index,Desktop,Core GUI APIs...
# 3

OK. I have updated my code to sort of work (it goes to the 8th round at best). How can I optimize it to actually make it continue running? Please help!

package learn;

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

public class Life {

/**

* @author Michael Keselman

*/

final JLabel label = new JLabel("Empty");

final static String LOOKANDFEEL = "System";

JToggleButton[] b = new JToggleButton[400];

JLabel message = new JLabel();

ActionListener a;

private boolean f;

Timer timer;

int c = 0;

private final int NUMRC = 20; // Number of Rows and Columns

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {

public void run() {

createAndShowGUI();

}

});

}

public static void createAndShowGUI() {

initLookAndFeel();

JFrame.setDefaultLookAndFeelDecorated(true);

JFrame frame = new JFrame("Swing Application");

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Life app = new Life();

Component contents1 = app.createComponents1();

Component contents2 = app.createComponents2();

frame.getContentPane().add(contents1, BorderLayout.CENTER);

frame.getContentPane().add(contents2, BorderLayout.SOUTH);

frame.pack();

frame.setSize(1200, 880);

frame.setLocationRelativeTo(null);

frame.setVisible(true);

}

public Component createComponents1() {

JPanel pane = new JPanel(new GridLayout(NUMRC, NUMRC));

for (int i = 0; i < 400; i++) {

b[i] = new JToggleButton("" + i);

b[i].setForeground(Color.black);

pane.add(b[i]);

}

return pane;

}

public Component createComponents2() {

JPanel bpane = new JPanel();

JButton start = new JButton("Start!");

JButton stop = new JButton("Stop!");

JButton clear = new JButton("Clear!");

timer = new Timer(900, a);

timer.start();

clear.setToolTipText("Click here to deselect every button");

stop.setToolTipText("Click here to stop the Game of Life");

start.setToolTipText("Click here to start the Game of Life");

start.addActionListener(a = new ActionListener() {

public void actionPerformed(ActionEvent e) {

f = true;

++c;

//while (f == true)

for (int i = 0; i < 400; i++) {

// try {

// Thread.sleep(20);

// } catch (InterruptedException g) {

// System.err.println(g);

// }

timer = new Timer(600, a);

timer.start();

int numSurround = getSurrounded(i);

if (b[i].isSelected()) {

if (numSurround < 2) {

b[i].setText("L");

b[i].setToolTipText("Too Lonely");

b[i].setSelected(false);

} else if (numSurround > 3) {

b[i].setText("C");

b[i].setToolTipText("Too Crowded");

b[i].setSelected(false);

}

} else // not selected

{

if (numSurround == 3)

b[i].setSelected(true);

}

}

message.setFont(new Font("Comic Sans MS", Font.BOLD, 18));

message.setText("Round " + c);

//}

}

});

stop.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

System.out.println("Hello. Success.");

f = false;

}

});

clear.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) {

for (int i = 0; i < 400; i++)

b[i].setSelected(false);

}

});

bpane.add(message);

bpane.add(start);

bpane.add(stop);

bpane.add(clear);

return bpane;

}

private int getSurrounded(int i) {

int row = i / NUMRC;

int column = i % NUMRC;

int surroundCount = 0;

/*

* Left Neighbor

*/

int leftColumn = column - 1;

if (leftColumn >= 0) {

if (b[getIndex(row, leftColumn)].isSelected())

++surroundCount;

}

/*

* Right Neighbor

*/

int rightColumn = column + 1;

if (rightColumn < NUMRC) {

if (b[getIndex(row, rightColumn)].isSelected())

++surroundCount;

}

/*

* Top Neighbor

*/

int topRow = row - 1;

if (topRow >= 0) {

if (b[getIndex(topRow, column)].isSelected())

++surroundCount;

}

/*

* Bottom Neighbor

*/

int bottomRow = row + 1;

if (bottomRow < NUMRC) {

if (b[getIndex(bottomRow, column)].isSelected())

++surroundCount;

}

/*

* Upper-Left Neighbor

*/

if (topRow >= 0 && leftColumn >= 0) {

if (b[getIndex(topRow, leftColumn)].isSelected())

++surroundCount;

}

/*

* Upper-Right Neighbor

*/

if (topRow >= 0 && rightColumn < NUMRC) {

if (b[getIndex(topRow, rightColumn)].isSelected())

++surroundCount;

}

/*

* Bottom-Left Neighbor

*/

if (bottomRow < NUMRC && leftColumn >= 0) {

if (b[getIndex(bottomRow, leftColumn)].isSelected())

++surroundCount;

}

/*

* Bottom-Right Neighbor

*/

if (bottomRow < NUMRC && rightColumn < NUMRC) {

if (b[getIndex(bottomRow, rightColumn)].isSelected())

++surroundCount;

}

return surroundCount;

}

protected int getIndex(int row, int column) {

return (NUMRC * row + column);

}

private static void initLookAndFeel() {

String lookAndFeel = null;

if (LOOKANDFEEL != null) {

if (LOOKANDFEEL.equals("Metal")) {

lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();

} else if (LOOKANDFEEL.equals("System")) {

lookAndFeel = UIManager.getSystemLookAndFeelClassName();

} else if (LOOKANDFEEL.equals("Motif")) {

lookAndFeel = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";

} else if (LOOKANDFEEL.equals("GTK+")) {

lookAndFeel = "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";

} else {

System.err

.println("Unexpected value of LOOKANDFEEL specified: "

+ LOOKANDFEEL);

lookAndFeel = UIManager.getCrossPlatformLookAndFeelClassName();

}

try {

UIManager.setLookAndFeel(lookAndFeel);

} catch (ClassNotFoundException e) {

System.err

.println("Couldn't find class for specified look and feel:"

+ lookAndFeel);

System.err

.println("Did you include the L&F library in the class path?");

System.err.println("Using the default look and feel.");

} catch (UnsupportedLookAndFeelException e) {

System.err.println("Can't use the specified look and feel ("

+ lookAndFeel + ") on this platform.");

System.err.println("Using the default look and feel.");

} catch (Exception e) {

System.err.println("Couldn't get specified look and feel ("

+ lookAndFeel + "), for some reason.");

System.err.println("Using the default look and feel.");

e.printStackTrace();

}

}

}

}

Thank you!

keseldudea at 2007-7-10 11:17:59 > top of Java-index,Desktop,Core GUI APIs...
# 4

I can't help you with the code. You have one timer. The Timer fires every "x" ms. When the timer fires you change the state of all the pieces of the game. The timer continues until the game is over. When the game is over you stop the timer.

Here is a simple example of using a Timer:

http://forum.java.sun.com/thread.jspa?forumID=57&threadID=605616

camickra at 2007-7-10 11:17:59 > top of Java-index,Desktop,Core GUI APIs...
# 5
Thanks. That piece of code brought me an epiphany. Everything works now.
keseldudea at 2007-7-10 11:17:59 > top of Java-index,Desktop,Core GUI APIs...