I need to know how I can set up a action listener for an array of buttons. I am trying to make a tic tac toe game. I am new to programming. I have seen someone on here ask a similar question but I could not grasp what they where doing because my program is set up different.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class tictactoe extends JFrame{
    public static JMenuBar MenuBar = new JMenuBar();
    JMenu File = new JMenu("File");
    JMenu Help = new JMenu("Help");
    JMenu Options = new JMenu("Options");
    JMenuItem NewGame = new JMenuItem("New Game");
    JMenuItem Exit = new JMenuItem("Exit");
    JMenuItem About = new JMenuItem("About");
    JMenuItem Sound = new JMenuItem("Sound");
    JButton[] button = new JButton[9];
    JPanel p1 = new JPanel();
    int user = 1;// sets user count for X and Circle

    public tictactoe(){
        add(p1);
        p1.setVisible(false);
        MenuBar.add(File);
        MenuBar.add(Help);
        MenuBar.add(Options);
        File.add(NewGame);
        File.add(Exit);
        Help.add(About);
        Options.add(Sound);
        Exit.addActionListener(new ExitListener1());
        NewGame.addActionListener(new NewGameListener());
}

    public void Xwin(){
         JOptionPane.showMessageDialog(null,"X wins");}
    public void Ywin(){
         JOptionPane.showMessageDialog(null,"Y wins");}
    
    public void reset(){
        for(int i=1;i<10; i++){//adds 9 buttons
        button[i] = new JButton("");//
        button[i].addActionListener(new Button());//adds Button Listener. Will This work?
        p1.add(button[i]);}
        p1.setLayout(new GridLayout(3,3,0,0));
        user = 1;// Makes sure that user is set back to X
        p1.setVisible(true);}

     public class Button implements ActionListener{
     public void actionPerformed(ActionEvent b){
         if(user == 1){
          //button that user presses will equal x;?????????????
          //(button user presses).setText("X");
             user++;}//sets user to 2 for Circles Choice
          else{
          // button that user presses will read O
             //(button user presses).setText("X");
             user--;}//sets user back to one for X choice}
         }}

       public class NewGameListener implements ActionListener{
       public void actionPerformed(ActionEvent a){
           reset();}}
         
       public class ExitListener1 implements ActionListener {
       public void actionPerformed(ActionEvent e) {
            System.exit(1);}}


    public static void main(String[] args) {
 JFrame Frame = new tictactoe();
 Frame.setSize(500, 500);
 Frame.setVisible(true);
 Frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
 Frame.setJMenuBar(MenuBar);}}

Recommended Answers

All 11 Replies

how I can set up a action listener for an array of buttons

Are you going to create a new listener for each button or use the same listener for all the buttons?

The syntax is: <A reference to a button>.addActionListener(<A ref to the listener>);

The <A reference to a button> could be an element of an array: aryBtns[ix] or
a button reference: aBtn

Please edit your code and wrap it in code tags. Use the [code] icon above the input box.

Also please move ALL of the }s to be on their own line and in alignment with the line of code with the matching {. Your code is VERY hard to read the way you have hidden all of the }s at the end of lines.

Use a for loop to set up the buttons, and then use the index of the button in the array for the separate commands.

button[0]{}
button[1]{}
etc.

Sorry Norm this is the first time I have ever asked for help. Learned most of this on my on. I have no clue how to edit it now. I added the action listener to all the buttons in the [reset()] method. When the user click new game the reset method is called.

@sirlink99 and NormR1
I thought about referencing each button, but I was wondering if I could do it a faster way. I was hoping for a way similar to the [.getSelectedIdex()]when dealing with ComboBox. One listener would make the rest of my code alot easier. I have written this already without methods and arrays, just trying to learn better ways.

This is the reason I wanted to make it just one listener. When I add this code. I get alot of Abstact Button errors. Im trying to make [Button[10] a dummy button so I can set each button equal to it and use a method for all.

public void reset(){
        p1.setLayout(new GridLayout(3,3,0,0));
        for(int i=1;i<10; i++){//adds 9 buttons
        button[i] = new JButton();
        p1.add(button[i]);
        }
        button[1].addActionListener(new Button1());
        button[2].addActionListener(new Button2());
        button[3].addActionListener(new Button3());
        user = 1;// Makes sure that user is set back to X
        p1.setVisible(true);
    }

    public void click(){
        if(user == 1){
           Font x = new Font("X", Font.PLAIN,150);
           button[10].setFont(x);
           button[10].setEnabled(false);
           winCheck[10]= 1;
        }
        else{
            Font y = new Font("Y",Font.PLAIN,150);
            button[10].setFont(y);
            button[10].setEnabled(false);
            winCheck[10]= -1;
        }
    }

    
    // think this is were i am going wrong. // button10 and winCheck10 are dummy objects
     public class Button1 implements ActionListener{
         public void actionPerformed(ActionEvent b){
             button[10]= button[1];//make button10 be button 1 for method
             click();
             winCheck[1]=+winCheck[10];
         }
     }
     public class Button2 implements ActionListener{
         public void actionPerformed(ActionEvent c){
             button[10]= button[2];//make button10 be button 1 for method
             click();
             winCheck[2]=+winCheck[10];
             button[10] = new JButton("");
         }
     }
     public class Button3 implements ActionListener{
         public void actionPerformed(ActionEvent d){
             button[10]= button[3];//make button10 be button 1 for method
             click();
             winCheck[3]=+winCheck[10];
         }
     }
JButton[] button = new Button[9]

should be

JButton[] button = new Button[10]

and everywhere it say

button[10]

should be

button[0]

because I have been doing this way to long today and forgot that arrays start at 0 not one. So 0 would be the dummy number.

Thanks for your help. I think I am just gonna call it a night and tomorrow right a working program with were i am at now so I can get better ideas on how to clean it up.

It is simple, let say you have 9 buttons and you want to put action on button1, all you have to do is:

button[0].addActionListener(  
  new ActionListener() {  
     
   //Handle event
   public void actionPerformed(ActionEvent event) {  
      
      //Your Actions Here.....

   }  
  }  
  );

do the same process on other buttons[0-9].

Member Avatar for hfx642

Maybe THIS will help...

Your JButton would be defined as

JButton myButton [][] = new JButton [3][3];  // This will DEFINE them, but NOT CREATE them
for (int R = 0; R < 3; R++)
   for (int C = 0; C < 3, C++)
      myButton [R][C] = new JButton ();  // This will CREATE them

Then, for your listeners...

for (int R = 0; R < 3; R++)
   for (int C = 0; C < 3, C++)
   {
      final int R_F = R;
      final int C_F = C:
      myButton [R][C}.addActionListener
      (
         new ActionListener ()
         {
            public void actionPerformed (ActionEvent AE)
            {
               // Add YOUR code here!
               // referring to your Rows as R_F (the final int)
               // and your Columns as C_F (the final int)
            }  // End of actionPerformed
         }  // End of ActionListener
      );  // End of addActionListener
   }  // End of for (C/R)

OK. Thank you guys for your help. I am really just trying new things. Like I said I have only been in programming for a semester, so everything that I am doing in this is self learned, or picked up through blogs and played with.

I have found a solution. In this code:

public class listener1 implements ActionListener{
        public void actionPerformed(ActionEvent e){
          for(int i=1; i<buttons.length; i++){
          if(e.getSource() == buttons[i]){
              buttons[i].setText(""+i);
          }
        }
    }
}

I will post my final code so that you guys can see what I was trying to do.

All I set out to do was use one action listener.
Now I think I should call this one messing with loops.

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class tictactoe extends JFrame{

    public static JMenuBar MenuBar = new JMenuBar();
    JMenu File = new JMenu("File");
    JMenu Help = new JMenu("Help");
    JMenu Options = new JMenu("Options");
    JMenuItem NewGame = new JMenuItem("New Game");
    JMenuItem Exit = new JMenuItem("Exit");
    JMenuItem About = new JMenuItem("About");
    JMenuItem Sound = new JMenuItem("Sound");
    JButton[] button = new JButton[9];
    JPanel p1 = new JPanel();
    int[] winCheck = new int[9];//holds value for each button
    int check = 0;//used to hold sum of 3 winCheck value, to determine if anyone has won;
    int player =1;// sets user count for X and Circle
    int load =1;// tells difference between load and reload
    int buttonIndex;//used to index button array
    int TieCheck=0;

    public tictactoe(){
        add(p1);
        MenuBar.add(File);
        MenuBar.add(Help);
        MenuBar.add(Options);
        File.add(NewGame);
        File.add(Exit);
        Help.add(About);
        Options.add(Sound);
        Exit.addActionListener(new ExitListener());
        NewGame.addActionListener(new NewGameListener());}

    
        public class ExitListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
           System.exit(1);
        }
    }


        //Buttons from load must be erased before reload.
        //If not it will just add 9 more buttons to the existing buttons.
        //So I seperated load and reload
        public void firstLoad(){ //first time the user presses New Game
        p1.setLayout(new GridLayout(3,3,0,0));
        for(int i = 0; i<9; i++){
        button[i]= new JButton("");
        p1.add(button[i]);
        button[i].addActionListener(new Play());
        p1.setVisible(true);
        }
    }
    public void reLoad(){
        for(int i=0;i<9;i++){
        winCheck[i] = 0; //sets all the values to check for win back to Zero
        button[i].setEnabled(true);
        p1.remove(button[i]);
        button[i].removeActionListener(new Play());
        }
        player=1;//makes sure X starts first on new game no matter who went last before
        firstLoad();
    }

    public class NewGameListener implements ActionListener{
        public void actionPerformed(ActionEvent e){
        p1.setVisible(false);
        if(load==1){//if its the fist game
        firstLoad();
        load=2;//sets for all reloads
            }
        else{
            reLoad();
        }
        }
    }
    
     public void Xwin(){//just sets what to do when someone wins
         JOptionPane.showMessageDialog(null,"X wins!");
         for(int i=0;i<9;i++){button[i].setEnabled(false);}}
    public void Ywin(){//dido
         JOptionPane.showMessageDialog(null,"Circle wins!");
         for(int i=0;i<9;i++){button[i].setEnabled(false);}}
       
    //IDK but I am pretty sure that this added more demand for computer usage, Creates alot of variables
    //Maybe someone can give me some feed back on that
    //Considering what little time I have been programming and lack of proper training on this,
    //I am proud of it.

    // First for loop loops twice
    //inside  for loop loops 3 times each
    //unless someone wins and then it is kicked out
    //if sum is -3 then Circle wins, If its is Postitve the X wins
    //Inside loop takes the sum of each colum and compares them to 3 or -3
    //If no win on either, inside loop kicks back out.
    //Second time it enters the Inside loop it checks rows

    public void WinCheck(){
            int a=0;//tells inside for loop were to start
            int ai =3;//increments loop start by 3 after ending of loop
            int b=2;//tells inside for loop were to end
            int bi=3;//increments end by 3 after ending of loop
            int c=1;//increment by 3 between start and end of inside loop
            int d=6;//throws while loop if inside loop try to start past 5

            for(int z=1;z<=4;z++){//loops twice unless thrown before
            while(a<=d){// stops for loop at 5 and 2
            for(int i=a;i<=b;i=i+c){
                check=check+winCheck[i];              
            }
                if(check == 3)
                {
                    Xwin();
                    a=9;//kicks inside loop
                    z=9;//kicks outside loop
                    }
                else if(check ==-3){
                    Ywin();
                    a=9;//kicks inside loop
                    z=9;//kicks outside loop
                }
                else{
                check=0;
                a=a+ai;//changes increments after ending of inside loop
                b=b+bi;
                }
                }
            a=0;ai=1;b=6;bi=1;c=3;d=2;// chanes increments for inside loop for the second time through the outside loop
            check = 0;
                }


                
                //check for diagonals
            
            if(winCheck[0]+winCheck[4]+winCheck[8]==3){
                Xwin();
            }
            if(winCheck[0]+winCheck[4]+winCheck[8]==-3){
                Ywin();
            }
            if(winCheck[2]+winCheck[4]+winCheck[6]==3){
                Xwin();
            }
            if(winCheck[2]+winCheck[4]+winCheck[6]==-3){
                Ywin();
            }          
    }
    
    public void click(){
        if(player == 1){
        Font X = new Font("X",Font.PLAIN, 150);
        button[buttonIndex].setFont(X);
        button[buttonIndex].setText("X");
        player = 2;
        winCheck[buttonIndex]= 1;
        }
        else{
        Font O = new Font("O",Font.PLAIN, 150);
        button[buttonIndex].setFont(O);
        button[buttonIndex].setText("O");
        player = 1;
        winCheck[buttonIndex]= -1;
        }

    }
    
    public class Play implements ActionListener{
        public void actionPerformed(ActionEvent e){
                  TieCheck=TieCheck+1;

                  if(TieCheck==9){
                 JOptionPane.showMessageDialog(null,"Tie!");
                }
           for(int i=0; i<button.length; i++){
          if(e.getSource() == button[i]){
               buttonIndex = i;
               button[i].setEnabled(false);
               }
            }
           click();
           WinCheck();
        }
    }

 public static void main(String[] args) {
 JFrame Frame = new tictactoe();
 Frame.setSize(500, 500);
 Frame.setVisible(true);
 Frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
 Frame.setJMenuBar(MenuBar);
    }

}

now it will be Swing's complaint (some required changes)

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class TicTacToe extends JFrame {

    private JMenuBar MenuBar = new JMenuBar();
    private JFrame frame = new JFrame();
    private static final long serialVersionUID = 1L;
    private JMenu File = new JMenu("File");
    private JMenu Help = new JMenu("Help");
    private JMenu Options = new JMenu("Options");
    private JMenuItem NewGame = new JMenuItem("New Game");
    private JMenuItem Exit = new JMenuItem("Exit");
    private JMenuItem About = new JMenuItem("About");
    private JMenuItem Sound = new JMenuItem("Sound");
    private JButton[] button = new JButton[9];
    private JPanel p1 = new JPanel();
    private int[] winCheck = new int[9];//holds value for each button
    private int check = 0;//used to hold sum of 3 winCheck value, to determine if anyone has won;
    private int player = 1;// sets user count for X and Circle
    private int load = 1;// tells difference between load and reload
    private int buttonIndex;//used to index button array
    private int TieCheck = 0;

    public TicTacToe() {
        add(p1);
        File.add(NewGame);
        File.add(Exit);
        MenuBar.add(File);
        Help.add(About);
        MenuBar.add(Help);
        Options.add(Sound);
        MenuBar.add(Options);
        Exit.addActionListener(new ExitListener());
        NewGame.addActionListener(new NewGameListener());
        WindowListener exitListener = new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {
                int confirm = JOptionPane.showOptionDialog(frame, "Are You Sure to Close this Application?",
                        "Exit Confirmation", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
                        null, null, null);
                if (confirm == 0) {
                    System.exit(1);
                }
            }
        };
        frame.addWindowListener(exitListener);
        frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
        frame.setJMenuBar(MenuBar);
        frame.setPreferredSize(new Dimension(500, 500));
        frame.setLocation(100, 100);
        frame.pack();
        frame.setVisible(true);
    }

    public class ExitListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            int confirm = JOptionPane.showOptionDialog(frame, "Are You Sure to Close this Application?",
                    "Exit Confirmation", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE,
                    null, null, null);
            if (confirm == 0) {
                System.exit(1);
            }
        }
    }

    //Buttons from load must be erased before reload.
    //If not it will just add 9 more buttons to the existing buttons.
    //So I seperated load and reload
    public void firstLoad() { //first time the user presses New Game
        p1.setLayout(new GridLayout(3, 3, 0, 0));
        for (int i = 0; i < 9; i++) {
            button[i] = new JButton("");
            p1.add(button[i]);
            button[i].addActionListener(new Play());
            p1.setVisible(true);
        }
    }

    public void reLoad() {
        for (int i = 0; i < 9; i++) {
            winCheck[i] = 0; //sets all the values to check for win back to Zero
            button[i].setEnabled(true);
            p1.remove(button[i]);
            button[i].removeActionListener(new Play());
        }
        player = 1;//makes sure X starts first on new game no matter who went last before
        firstLoad();
    }

    public class NewGameListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            p1.setVisible(false);
            if (load == 1) {//if its the fist game
                firstLoad();
                load = 2;//sets for all reloads
            } else {
                reLoad();
            }
        }
    }

    public void Xwin() {//just sets what to do when someone wins
        JOptionPane.showMessageDialog(null, "X wins!");
        for (int i = 0; i < 9; i++) {
            button[i].setEnabled(false);
        }
    }

    public void Ywin() {//dido
        JOptionPane.showMessageDialog(null, "Circle wins!");
        for (int i = 0; i < 9; i++) {
            button[i].setEnabled(false);
        }
    }

    //IDK but I am pretty sure that this added more demand for computer usage, Creates alot of variables
    //Maybe someone can give me some feed back on that
    //Considering what little time I have been programming and lack of proper training on this,
    //I am proud of it.
    // First for loop loops twice
    //inside  for loop loops 3 times each
    //unless someone wins and then it is kicked out
    //if sum is -3 then Circle wins, If its is Postitve the X wins
    //Inside loop takes the sum of each colum and compares them to 3 or -3
    //If no win on either, inside loop kicks back out.
    //Second time it enters the Inside loop it checks rows
    public void WinCheck() {
        int a = 0;//tells inside for loop were to start
        int ai = 3;//increments loop start by 3 after ending of loop
        int b = 2;//tells inside for loop were to end
        int bi = 3;//increments end by 3 after ending of loop
        int c = 1;//increment by 3 between start and end of inside loop
        int d = 6;//throws while loop if inside loop try to start past 5

        for (int z = 1; z <= 4; z++) {//loops twice unless thrown before
            while (a <= d) {// stops for loop at 5 and 2
                for (int i = a; i <= b; i += c) {
                    check += winCheck[i];
                }
                if (check == 3) {
                    Xwin();
                    a = 9;//kicks inside loop
                    z = 9;//kicks outside loop
                } else if (check == -3) {
                    Ywin();
                    a = 9;//kicks inside loop
                    z = 9;//kicks outside loop
                } else {
                    check = 0;
                    a += ai;//changes increments after ending of inside loop
                    b += bi;
                }
            }
            a = 0;
            ai = 1;
            b = 6;
            bi = 1;
            c = 3;
            d = 2;// chanes increments for inside loop for the second time through the outside loop
            check = 0;
        }
//check for diagonals
        if (winCheck[0] + winCheck[4] + winCheck[8] == 3) {
            Xwin();
        }
        if (winCheck[0] + winCheck[4] + winCheck[8] == -3) {
            Ywin();
        }
        if (winCheck[2] + winCheck[4] + winCheck[6] == 3) {
            Xwin();
        }
        if (winCheck[2] + winCheck[4] + winCheck[6] == -3) {
            Ywin();
        }
    }

    public void click() {
        if (player == 1) {
            Font X = new Font("X", Font.PLAIN, 150);
            button[buttonIndex].setFont(X);
            button[buttonIndex].setText("X");
            player = 2;
            winCheck[buttonIndex] = 1;
        } else {
            Font O = new Font("O", Font.PLAIN, 150);
            button[buttonIndex].setFont(O);
            button[buttonIndex].setText("O");
            player = 1;
            winCheck[buttonIndex] = -1;
        }
    }

    public class Play implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            TieCheck += 1;
            if (TieCheck == 9) {
                JOptionPane.showMessageDialog(null, "Tie!");
            }
            for (int i = 0; i < button.length; i++) {
                if (e.getSource() == button[i]) {
                    buttonIndex = i;
                    button[i].setEnabled(false);
                }
            }
            click();
            WinCheck();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                TicTacToe ticTacToe = new TicTacToe();
            }
        });
    }
}
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.