How do I update buttons in Java?

I am making a simple tic-tac-toe game in java and for the board I am going to use buttons that the user can click on. I have the buttons and action events and all of that stuff. I created the imageIcon’s and created a new button that should be updated to the screen once the user clicked on the first spot in the upper left corner (only one I have implemented so far). When the user clicks on it though and I create a new button it’s not being updated on my screen. I thought calling the repaint() method would do it, but it doesn’t. Anyone have any ideas?



//required imports for Swing
import java.awt.*;
import javax.swing.*;
import java.awt.event.*; 
import java.text.*;

public class SimpleFrameGridbag extends JFrame
{

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */    
   private JButton oneOne;

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private JButton oneTwo;

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private JButton oneThree;
   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */     
   private JButton twoOne;

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private JButton twoTwo;

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private JButton twoThree;   
   
   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */      
   private JButton threeOne;

  /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private JButton threeTwo;

   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */          
   private JButton threeThree;  
   
   /**
    * Instance variable to represent the tic-tactoe board.<br>
    */         
   private boolean selection; 
   
   ImageIcon middleButtonIcon = createImageIcon("middle.gif");
   /** 
    * Constructor<br> 
    * Preconditions: None. <br>
    * Postconditions: None.<br>
    * Throws: None.<br>
    * @return None.<BR>
    */   
   public SimpleFrameGridbag()
   {
   	//empty constructor
   }
   
   /** 
    * Overloaded constructor for the main window of our program.<br> 
    * Preconditions: A valid width, height, and selection are sent. <br>
    * Postconditions: The main window which allows the playing of tic-tac-toe.<br>
    * Throws: None.<br>
    * @param width The width of the screen.<BR>
    * @param height The height of the screen.<BR>
    * @param selection single player or multiplayer<BR>
    * @param difficultySelection level of difficulty
    * @return None.<BR>
    */ 
   public SimpleFrameGridbag (int width,int height, boolean selection, boolean difficultySelection) //selection is true for singlePlayer and false for multiPlayer
   {
	      //set up the frame
	      super ("Tic-Tac-Toe");   	
          //so we know whether we are using singlePlayer or MultiPlayer 	
   		  this.selection = selection;
	      setSize(width+300,height+300);
	     
          if(selection == true) //for singlePlayer
	      {
				if(difficultySelection == true)
					System.out.println("Single Player and Difficulty 1");
				else
					System.out.println("Single Player and Difficulty 2");
		  }	
		  else if(selection == false) //for multiPlayer
		  {
				if(difficultySelection == true)
					System.out.println("MultiPlayer and Difficulty 1");
				else
					System.out.println("MultiPlayer and Difficulty 2");
		  }	
	  	  		  	
	    //center the window
	    Dimension screenSize=getToolkit().getScreenSize();
	    int screenWidth=screenSize.width;
	    int screenHeight=screenSize.height;
	    setLocation(screenWidth/2-width/2,screenHeight/2-height/2);
	
	    //step 0 (obtain the top level container and set its background color to white)
	    Container cont = getContentPane();
		cont.setBackground(Color.WHITE);
	    //step 1 (instantiate GUI components--  don't declare new components, use the instance variables)
		
		//row first and column second in name
		oneOne = new JButton("1,1");
		oneTwo = new JButton("1,2");
		oneThree = new JButton("1,3");
		twoOne = new JButton("2,1");
		twoTwo = new JButton("2,2");
		twoThree = new JButton("2,3");
		threeOne = new JButton("3,1");
		threeTwo = new JButton("3,2");
		threeThree = new JButton("3,3");
				
		//set the action commands

	    oneOne.setActionCommand("1,1");
	    oneTwo.setActionCommand("1,2");
	    oneThree.setActionCommand("1,3");
	    twoOne.setActionCommand("2,1");
	    twoTwo.setActionCommand("2,2");
	    twoThree.setActionCommand("2,3");
	    threeOne.setActionCommand("3,1");
	    threeTwo.setActionCommand("3,2");
	    threeThree.setActionCommand("3,3");	
	    	
		//add the action listeners for the buttons
	    oneOne.addActionListener(new Listener());
	    oneTwo.addActionListener(new Listener());
	    oneThree.addActionListener(new Listener());
	    twoOne.addActionListener(new Listener());
	    twoTwo.addActionListener(new Listener());
	    twoThree.addActionListener(new Listener());
	    threeOne.addActionListener(new Listener());
	    threeTwo.addActionListener(new Listener());
	    threeThree.addActionListener(new Listener());
	    	    	    
	   	EasyGridBag bag = new EasyGridBag(3,3); 
		cont.setLayout(bag); 
		
		//set up our layout using GridBag and place the components accordingly	
		bag.fillCell(1,1,1,1,1,oneOne,cont);
		bag.fillCell(1,2,1,1,1,oneTwo,cont);
	   	bag.fillCell(1,3,1,1,1,oneThree,cont);
	   	bag.fillCell(2,1,1,1,1,twoOne,cont);
	   	bag.fillCell(2,2,1,1,1,twoTwo,cont);
	   	bag.fillCell(2,3,1,1,1,twoThree,cont);
	   	bag.fillCell(3,1,1,1,1,threeOne,cont);
	   	bag.fillCell(3,2,1,1,1,threeTwo,cont);
	   	bag.fillCell(3,3,1,1,1,threeThree,cont);	   	
   }//end SimpleFrameGridbag overloaded constructor
  
   /** 
    * Class to provide actions for when the user clicks a button.<br> 
    * Preconditions: None. <br>
    * Postconditions: This provides actions for when a user clicks a button.<br>
    * Throws: None.<BR> 
    * Implements ActionListener<br>
    * @return None.<BR>
    */      
   private class Listener implements ActionListener
   {
   	
   /** 
    * Method to provide actions for when the user clicks a button.<br> 
    * Preconditions: An ActionEvent is sent. <br>
    * Postconditions: This provides actions for when a user clicks a button.<br>
    * Throws: None.<BR> <br>
    * @param e An ActionEvent describing what button the user clicked.<br>
    * @return None.<BR>
    */   	
      public void actionPerformed(ActionEvent e) 
      {
      	 
         if (e.getActionCommand().equals("1,1"))
         {
			System.out.println("1,1");
		
			 Container cont = getContentPane();
		cont.setBackground(Color.BLACK);
	    //step 1 (instantiate GUI components--  don't declare new components, use the instance variables)
		
		//row first and column second in name
		oneOne = new JButton("45645", middleButtonIcon);
	    	
		//add the action listeners for the buttons

	    repaint();	 
         } //end ActionCommand
         if (e.getActionCommand().equals("1,2"))
         {
			System.out.println("1,2");
         } //end ActionCommand
         
         if (e.getActionCommand().equals("1,3"))
         {
			System.out.println("1,3");
         } //end ActionCommand         
         if (e.getActionCommand().equals("2,1"))
         {
			System.out.println("2,1");
         } //end ActionCommand
         if (e.getActionCommand().equals("2,2"))
         {
			System.out.println("2,2");
         } //end ActionCommand
         
         if (e.getActionCommand().equals("2,3"))
         {
			System.out.println("2,3");
         } //end ActionCommand                 
         if (e.getActionCommand().equals("3,1"))
         {
			System.out.println("3,1");
         } //end ActionCommand
         if (e.getActionCommand().equals("3,2"))
         {
			System.out.println("3,2");
         } //end ActionCommand
         
         if (e.getActionCommand().equals("3,3"))
         {
			System.out.println("3,3");
         } //end ActionCommand                           
      }//end of the actionperformed method

   } //end of the Listener class
   
   /**This code (createImageIcon method) is from the java tutorial web site. It's full source can be viewed at
    //the URL below
    (http://java.sun.com/docs/books/tutorial/uiswing/components/example-1dot4/ButtonHtmlDemo.java*/
    
    /** Returns an ImageIcon, or null if the path was invalid. */
    protected static ImageIcon createImageIcon(String path) {
        java.net.URL imgURL = SimpleFrameGridbag.class.getResource(path);
        if (imgURL != null) {
            return new ImageIcon(imgURL);
        } else {
            System.err.println("Couldn't find file: " + path);
            return null;
        }
    }  
}//end SimpleGridFrame class

This code isn’t fully functional by itself since there’s no main method.

I’m not real clear on the snippet you posted because it isn’t the way I’d have gone about it, but I’m just a tinkerer in Java so I wouldn’t take my word as dogma. I’d probably subclass JButton to have the info I want, and use something like
MyJSubButton.someMethod()
Then in the code:



myButton11.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleAnyClick(e.getSource()} }

/* ... */

public void handleAnyClick(MyJSubButton b)
{
     // handle information about board
     // figure out icon
     b.setIcon(whateverIconIsNeeded);
}


I think Sun recommends using an action to define a button now when the same action will be called by multiple buttons. Unfortunately, my Java Developers Almanac is at work. But Sun is nice about having their documentation online:
JButton(Action a)
public interface Action

When making a move to menus and such, having this interface was pretty clean as I recall.

THANK YOU! Simply using “myButton.setIcon(myIcon)” worked fine.

Glad I could help.

In addition, the problem may have been because you were declaring a brand new button (rather than using the one already created), and without seeing all of your code, it’s hard to test, but it looked like the repaint() that you called was in the context of the whole JPanel itself. You can invoke repaint() on any component method, specifically (if it’s in scope), like this:

myButton.repaint();

But I’m with erislover – I’d agree that it’s easier (and better) to simply work with the existing button object and use it’s methods to affect changes, rather than replacing with a new button every time one is clicked.

Also, I noticed that you created 9 separately named button objects. You might find the code easier (and briefer) if you did this with an array instead. (An array of JButtons).