1

I am coding a little game in which i have taken a grid of JButtons in a JFrame and i want to refresh the colors of the buttons contained in a JFrame,which is already visible.As explained below

 void foo(){
     mainFrame.setVisible(true);//mainFrame is defined at class level.
     //color update code for the buttons.
     mainFrame.setVisible(true);
 }

Result i am getting is not as expected and my screen gets freeze .Isn't it the right way to achieve what i wanted? EDIT ok i am explaining it in detail what i want to achieve.i have a class,as:-

import javax.swing.*;
import java.awt.*;
import java.util.*;
class Brick extends JButton{
      public void setRandomColors(){
            int random = (int) (Math.random()*50);
            if(random%13==0){
                this.setBackground(Color.MAGENTA);
            }
            else if(random%10==0){
                this.setBackground(Color.red);
            }
            else if(random%9==0){

                this.setBackground(Color.yellow);
            }
            else if(random%7==0){
                this.setBackground(Color.orange);
            }
            else if(random%2==0){
                this.setBackground(Color.cyan);
            }
            else{
                this.setBackground(Color.PINK);
            }
    }
    public void setBlackColor(){
            this.setBackground(Color.black);
    }
}
class Grid {
    JFrame mainGrid = new JFrame();
    ArrayList<Brick> bunchOfBricks = new ArrayList<>();
    int gridLength = 8;//gridlenth is equals to gridweight as i have considered a Square grid.
    int totalBricks = gridLength*gridLength;
    public void formBunchOfBricks(){
            for(int i=0;i<totalBricks;i++){
                      bunchOfBricks.add(new Brick());
            }
    }
    public void formColoredGrid(){
            Brick aBrick;
            mainGrid.setLayout(new GridLayout(8,8));
            for(int i=0;i<totalBricks;++i){
                      aBrick = (bunchOfBricks.get(i));
                      aBrick.setRandomColors();
                      mainGrid.add(aBrick);
            }
            mainGrid.setVisible(true);//its ok upto here iam getting randomly colored Frame of Bricks or so called JButtons.
            delay(15);//Sorry for this one,i warn you not to laugh after looking its defination.

    }
 /*
 I want following function to do following things:-
 1.it should firstly display the Grid whose all buttons are black Colored.
 2.After some time the original colored,first Row of grid formed by formColoredGrid should be                         displayed and all the rest Rows should be black.
 3.Then second row turns colored and all other rows should be black......and so on upto last row of Grid.
 */
   public void movingRows(){
          setGridBlack();
          delay(1);//see in upper method,for this horrible thing.
          for(int i=0;i<gridLength;++i){
                setGridBlack();
                for (int j=0;j<gridLength;++j){
                     Brick aBrick = bunchOfBricks.get((gridLength*i)+j);
                     aBrick.setRandomColors();//Bricks are colored Row by Row.
                }
          delay(5);//already commented this nonsense.
          mainGrid.setVisible(true);//using setVisible again,although this frame is already visible,when i called formColoredGrid.

          setGridBlack();
        }
 //oh! disappointing,i have almost broken my arm slamming it on table that why the function result in a  screen full of black buttons.
    }
   public void setGridBlack(){
          for(int i=0;i<totalBricks;i++){
                   bunchOfBricks.get(i).setBlackColor();
          }
   }
   public void delay(int a){
        for ( int i=0;i<90000000;++i){
            for(int j=0;j<a;++j){

            }
        }
   }
   public static void main(String args[]){
          Grid g1 = new Grid();
          g1.formBunchOfBricks();
          g1.formColoredGrid();
          g1.movingRows();
}

}

Please Help me what is the way out?

OldSchool
  • 2,123
  • 4
  • 23
  • 45
  • There is not need to hide/show the frame. Just change the colors of the buttons. If the screen freezes then you probably have some other code that blocking the Event Dispatch Thread and preventing the GUI from repainting itself. Post your [SSCCE](http://sscce.org/) that demonstrates the problem. – camickr Jul 04 '14 at 16:58
  • http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html – Paul Samsotha Jul 04 '14 at 18:36
  • Yup... learn it thoroughly. Your loop is the problem as @HovercraftFullOfEels noted. Use a timer for a delay – Paul Samsotha Jul 04 '14 at 18:37
  • @peeskillet thanks.But what is the reason of failure in program. – OldSchool Jul 04 '14 at 18:38
  • You have a pointless loop that iterates a gazillion times for no reason. That's your problem – Paul Samsotha Jul 04 '14 at 18:39
  • @peeskillet but only that one!isn't there any other mistake? – OldSchool Jul 04 '14 at 18:40
  • Please make an attempt as learning the timer and implementing it. If it still fails, then edit your question with your attempt – Paul Samsotha Jul 04 '14 at 18:42

1 Answers1

5

Your problem is in code not shown here:

//color update code for the buttons.

You're likely running a loop that never ends on the Swing event thread, possibly a never-ending while loop that polls the state of something(a guess), freezing your GUI. Solution: don't do this; don't use a continuous polling loop. Instead, change the colors based on responses to events as Swing is event-driven.

For better more specific help, please show the offending code and tell us more about your program.


Edit

If you're trying to show colored rows, one by one marching down the board, then my guess is right, you'll want to use a Swing Timer, one that uses an int index to indicate which row is being displayed in color. You'd increment the index inside of the Timer's ActionPerformed class, and then when all rows have been displayed stop the Timer. For example something like so:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

import javax.swing.*;

@SuppressWarnings("serial")
public class MyGrid extends JPanel {
   private static final int GRID_LENGTH = 8;
   private static final Color BTN_BACKGROUND = Color.BLACK;
   private static final Color[] COLORS = { Color.MAGENTA, Color.CYAN,
         Color.RED, Color.YELLOW, Color.ORANGE, Color.PINK, Color.BLUE,
         Color.GREEN };
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final int TIMER_DELAY = 800;
   private JButton[][] buttonGrid = new JButton[GRID_LENGTH][GRID_LENGTH];
   private Map<JButton, Color> btnColorMap = new HashMap<>();
   private Random random = new Random();

   public MyGrid() {
      setLayout(new GridLayout(GRID_LENGTH, GRID_LENGTH));
      for (int row = 0; row < buttonGrid.length; row++) {
         for (int col = 0; col < buttonGrid[row].length; col++) {
            JButton btn = new JButton();
            btn.setBackground(BTN_BACKGROUND);
            // !! add action listener here?

            add(btn);
            buttonGrid[row][col] = btn;
         }
      }

      new Timer(TIMER_DELAY, new TimerListener()).start();
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   public void resetAllBtns() {
      for (JButton[] row : buttonGrid) {
         for (JButton btn : row) {
            btn.setBackground(BTN_BACKGROUND);
         }
      }
   }

   private class TimerListener implements ActionListener {
      private int row = 0;

      @Override
      public void actionPerformed(ActionEvent e) {
         resetAllBtns(); // make all buttons black

         if (row != buttonGrid.length) {
            for (int c = 0; c < buttonGrid[row].length; c++) {
               int colorIndex = random.nextInt(COLORS.length);
               Color randomColor = COLORS[colorIndex];
               buttonGrid[row][c].setBackground(randomColor);

               // !! not sure if you need this
               btnColorMap.put(buttonGrid[row][c], randomColor);
            }

            row++;
         } else {
            // else we've run out of rows -- stop the timer
            ((Timer) e.getSource()).stop();
         }
      }
   }

   private static void createAndShowGui() {
      MyGrid mainPanel = new MyGrid();

      JFrame frame = new JFrame("MyGrid");
      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();
         }
      });
   }
}

Please have a look at the Swing Timer Tutorial as well.


enter image description here


Edit 2
You ask:

but what is the reason of failure of this program,is it the useless delay function?

Your delay method does nothing but busy calculations on the Swing event thread:

public void delay(int a) {
  for (int i = 0; i < 90000000; ++i) {
     for (int j = 0; j < a; ++j) {

     }
  }
}

It's little different from a crude attempt at calling Thread.sleep(...), and is crude because you can't explicitly control how long it will run as you can with thread sleep. Again, the problem is that you're making these calls on the Swing event dispatch thread or EDT, the single thread that is responsible for all Swing drawing and user interactions. Blocking this thread will block your program making it non-running or frozen.

Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373