Search code examples
javalistenerinteractive

How do I change the color of a square once pressed on?


Right now I have code to be able to randomize colored squares over a 25x25 board. What I'm trying to do is be able to make those colored squares turn white once pressed on and once it turns white, you can't reverse it. I was thinking about using Listeners but I'm not sure how to start.

Here is what I have to create the randomized squares.

import java.awt.*;
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;

public class ColoredBoxes {
   //Selected Colors
   private Color[] availableColors = new Color[] {Color.YELLOW, Color.RED, Color.BLUE, Color.GREEN};
   public static void main(String[] args) {
        new ColoredBoxes();
   }

    public ColoredBoxes() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Collapse");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {
        //Size of the board
        protected static final int ROWS = 25;
        protected static final int COLS = 25;
        protected static final int BOX_SIZE = 25;

        private List<Color> colors;
        
        //RandomColors across the given board size.
        public TestPane() {
            int length = ROWS * COLS;
            colors = new ArrayList<Color>();
            for (int index = 0; index < length; index++) {
                int randomColor = (int) (Math.random() * availableColors.length);
                colors.add(availableColors[randomColor]);
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(COLS * BOX_SIZE, ROWS * BOX_SIZE);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();

            int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
            int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;

            System.out.println("...");
            for (int row = 0; row < ROWS; row++) {
                for (int col = 0; col < COLS; col++) {
                    int index = (row * COLS) + col;
                    g2d.setColor(colors.get(index));
                    g2d.fillRect(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
                }
            }
            g2d.dispose();
        }
    }
}

Any help is much appreciated.


Solution

  • To change color on click, you just need a MouseListener, in the mouseClicked() method you must convert the click coordinates to row and column of the color grid, change that color and then ask the component to repaint.

    Here the implementation, I just replaced your 1-dimensional color list with a 2-dimension color array, since it simplify the representation and the conversion from x,y to row,col.

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.EventQueue;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class ColoredBoxes {
       //Selected Colors
       private Color[] availableColors = new Color[] {Color.YELLOW, Color.RED, Color.BLUE, Color.GREEN};
       
    
       //This is the color that will be set when a cell is clicked
       private static final Color CLICKED_COLOR = Color.white;
       
       public static void main(String[] args) {
            new ColoredBoxes();
       }
    
        public ColoredBoxes() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                        ex.printStackTrace();
                    }
    
                    JFrame frame = new JFrame("Collapse");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.add(new TestPane());
                    frame.pack();
                    frame.setLocationRelativeTo(null);
                    frame.setVisible(true);
                }
            });
        }
    
        public class TestPane extends JPanel {
            //Size of the board
            protected static final int ROWS = 25;
            protected static final int COLS = 25;
            protected static final int BOX_SIZE = 25;
    
            //Since you have a ROWSxCOLS color grid better use a 2-dimension array
            private Color[][] cells;
            
            //RandomColors across the given board size.
            public TestPane() {
                cells=new Color[ROWS][COLS];
                for (int i=0;i<cells.length;i++) {
                    for (int j=0;j<cells[i].length;j++) {
                        int randomColor = (int) (Math.random() * availableColors.length);
                        cells[i][j]=availableColors[randomColor];
                    }
                }
                
                //Here the mouse listener, we only need to manage click events
                //so I use a MouseAdapter to not implement the complete MouseListener interface
                addMouseListener(new MouseAdapter() {
                    @Override
                    public void mouseClicked(MouseEvent e) {
                        onClick(e);
                    }
                });
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(COLS * BOX_SIZE, ROWS * BOX_SIZE);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
    
                int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
                int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
    
                System.out.println("...");
                for (int row = 0; row < ROWS; row++) {
                    for (int col = 0; col < COLS; col++) {
                        g2d.setColor(cells[row][col]);
                        g2d.fillRect(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
                    }
                }
                g2d.dispose();
            }
            
            //Finally the click handler
            protected void onClick(MouseEvent e) {
                //Convert mouse x,y (that are relative to the panel) to row and col
                int xOffset = (getWidth() - (COLS * BOX_SIZE)) / 2;
                int yOffset = (getHeight() - (ROWS * BOX_SIZE)) / 2;
                
                int row=(e.getY()-yOffset)/BOX_SIZE;
                int col=(e.getX()-xOffset)/BOX_SIZE;
    
                //Check that we are in the grid
                if (row>=0&&row<ROWS&&col>=0&&col<COLS) {
                    //Set new color
                    cells[row][col]=Color.white;
                    //Repaint, only the changed region
                    repaint(xOffset + (col * BOX_SIZE), yOffset + (row * BOX_SIZE), BOX_SIZE, BOX_SIZE);
                }
            }
            
        }
    }