Java why does cell keep changing colors - java

Hello sorry I'm very weak in programming.
I'm trying to make my Box each a different shade of green. However, when I implement my code it keeps changing colors even when my box loop is finished.
The finished product is suppose to be a tetris with boxes that have different color of green.
So tetris class creates a lot of boxes in a array .
The method for the tetris is to create each box having its unique position of i and j
import javax.swing.*;
import java.awt.*;
class Main extends JFrame {
class App extends JPanel {
Grid grid;
public App() {
setPreferredSize(new Dimension(900, 720));
grid = new Grid();
}
#Override
public void paint(Graphics g) {
grid.paint(g, getMousePosition());
}
}
public static void main(String[] args) throws Exception {
Main window = new Main();
window.run();
}
private Main() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
App canvas = new App();
this.setContentPane(canvas);
this.pack();
this.setVisible(true);
}
public void run() {
while (true) {
this.repaint();
}
}
}
import java.awt.*;
class Grid {
//fields
Cell[][] cells = new Cell[20][20];
// constructor
public Grid(){
for(int i = 0; i < cells.length; i++){
for(int j = 0; j < cells[i].length; j++){
cells[i][j] = new Cell(10+35*i,10+35*j);
}
}
}
// methods
public void paint(Graphics g, Point mousePos){
for(int i = 0; i < cells.length; i++){
for(int j = 0; j < cells[i].length; j++){
cells[i][j].paint(g, mousePos);
}
}
}
}
import java.awt.*;
import java.util.Random;
class Cell extends Rectangle {
// fields
int random_int;
int minyellow = 50;
int maxyellow = 100;
static int size = 35;
//constructors
public Cell(int x, int y){
super(x,y,size,size);
}
//methods
void paint(Graphics g, Point mousePos){
int random_int = (int)(Math.random() * (maxyellow - minyellow + 1) + minyellow);
this.random_int=random_int;
if(contains(mousePos)){
g.setColor(Color.GRAY);
}
else {
g.setColor(Color.getHSBColor(255, random_int, 60));
}
g.fillRect(x,y,size,size);
g.setColor(Color.BLACK);
g.drawRect(x,y,size,size);
}
public boolean contains(Point p){
if (p != null){
return super.contains(p);
} else {
return false;
}
}
}

A problem in your code is that you pick the random number for your colour inside Cell's paint method, so every time it is painted, it gets a new random colour.
For a cell to have a stable colour, the simplest fix is to set random_int once, in the constructor, and not update it.
public Cell(int x, int y) {
super(x, y, size, size);
random_int = (int) (Math.random() * (maxyellow - minyellow + 1) + minyellow);
}
void paint(Graphics g, Point mousePos) {
if (contains(mousePos)) {
g.setColor(Color.GRAY);
}
else {
g.setColor(Color.getHSBColor(255, random_int, 60));
}
g.fillRect(x,y,size,size);
g.setColor(Color.BLACK);
g.drawRect(x,y,size,size);
}

Related

How to make AWT draw on grid on a rectangle that is clicked?

I am a student in the process of making a Tic Tac Toe game, and currently have most of the UI and grid itself. I know AWT is out of data and Swing is much more informative and useful, but I am being taught and have the most resources on AWT. I currently have 5 classes:
GUI Class:
import java.awt.*;
import javax.swing.JFrame;
public class GUI{
JFrame frame1;
Board board1;
Buttons buttons;
MyMenu menu1;
public GUI() {
frame1 = new JFrame("Tic Tac Toe");
board1 = new Board(3,3 ,200);
buttons = new Buttons(this);
menu1 = new MyMenu(this);
}
public void start () {
frame1.setLayout(new FlowLayout());
board1.setBackground(Color.BLACK);
frame1.setMenuBar(menu1);
frame1.add(board1);
frame1.add(buttons);
frame1.pack();
frame1.setVisible(true);
}
public static void main (String[] args) {
GUI gui = new GUI();
gui.start();
}
public void setBackground (Color c) {
board1.setBackground(c);
}
public void closeGame() {
frame1.dispose();
}
}
Board Class:
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.*;
public class Board extends Canvas {
Cell[][] array;
int rows, cols;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
setSize(cols*size,rows*size);
}
public int getNumRows() {
return rows;
}
public int getNumCols () {
return cols;
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g);
}
}
}
public void paint(Graphics g) {
draw(g);
}
}
Cell Class:
import java.awt.Color;
import java.awt.*;
public class Cell
{
private final int x;
private final int y;
private final int size;
int rows;
int cols;
Cell[][] array = new Cell[rows][cols];
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void fillArray() {
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
public void paint(Graphics g) {
g.setColor(Color.YELLOW);
g.drawRect(x, y, size, size);
}
}
Button Class:
import java.awt.*;
import java.awt.event.*;
public class Buttons extends Panel implements ActionListener {
Button test;
Button giveIn;
GUI gui;
public Buttons(GUI gui) {
this.gui = gui;
giveIn = new Button("GIVE UP!");
this.add(giveIn);
giveIn.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()== giveIn) {
gui.closeGame();
}
}
}
I also have another class, implementing a Menu, but didn't feel it was necessary to include. How hard would and how would I implement it so when I click a rectangle on my grid, something is painted onto that specific rectangle? I understand I would need a mouse listener, and some sort of if statement on my paint method, as well as some methods that return the cell or rectangle clicked. How is something like this implemented?

How to Make Button that Changes Rectangle Graphics Outline Color upon Press?

I am trying to make a button, that upon clicked, changes the grid color of the rectangles I have drawn.
Here is my drawn grid. I would like the menu items I have under grid, when pressed, change the rectangle outline colors of the drawn grid. I have tried a couple methods, but seem to have trouble implementing it.
Here is my Menu Class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
GUI gui;
Cell cell;
public MyMenu(GUI gui) {
this.gui = gui;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource()==c1) {
}
}
}
Here is my Board class
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.*;
public class Board
extends Canvas {
private Cell[][] array;
public Board(int rows, int cols, int size) {
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
setSize(cols*size,rows*size);
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g);
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
draw(g);
}
}
And Finally, here is my Cell Class
import java.awt.Color;
import java.awt.Graphics;
import java.awt.*;
public class Cell
{
private final int x;
private final int y;
private final int size;
int rows;
int cols;
Cell[][] array = new Cell[rows][cols];
public Color currentcolor = Color.BLACK;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void fillArray() {
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.drawRect(x, y, size, size);
}
}
I obviously need to make it, so when the button is pressed, the g.setColor under the Cell class and paint method is changed and then repainted, but I am unsure on how to do this?
First, you might want to understand the difference between Swing and AWT (and why you might want to prefer the latter)
Understanding the Difference Between AWT And Swing In Java
Difference between AWT and Swing in Java
What is the difference between Swing and AWT?
What is the Difference Between AWT and Swing in Java
Difference Between AWT and Swing in Java
Difference between AWT and Swing
AWT and Swing in Java
If you're just starting out, you might also consider using JavaFX instead.
You will also want to investigate things like:
Dependency Injection
Composition over inheritance
Liskov substitution principle
Single Responsibility Principle
As this will all effect the way in which you approach designing your solutions to your problems.
For example, do you really need to extend from MenuBar? What new functionality are you bringing to the class, which couldn't be achieved through a builder or factory pattern?
Each individual menu item could also have it's action handling isolating, so that you're dealing with single response for each action, rather then, what will become, a messy if-else statement in the future (ie Single Responsibility Principle)
Having said all that, your basic problem comes down to, providing some way to notify the Board that it needs to update the gridColor when a menu item is selected.
This can be solved through the use a Observer Pattern. You've already used this, ActionListener is a implementation of the observer pattern.
Now, there is no reason for MyMenu to have full control over GUI (which I'm assuming is some kind Frame), it would be better to make some kind of delegate which is responsible for coordinating messaging between the menu bar and the interested party (this can some times be referred to as a controller, but I'm not going that far).
The first thing we need is to define the functionality we're willing to expose, for example...
public interface BoardConfigurable {
public void setBoardGridColor(Color color);
}
This is a simple contract for telling the interested party that the board grid color should be changed.
(Before some jumps down my throat, we could have a interface called, I don't, MyMenuListener, which then implements BoardConfigurable and possibly a bunch of other interfaces, which further allows for decoupling of the basic code, but this is what I would consider separating the action handling into isolated units of work - but this is going way beyond what is required right now)
We then update MyMenu to accept an instance of this delegate/observer and update the actionPerformed method to call it when ever an appropriate action is triggered.
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
BoardConfigurable boardConfig;
Cell cell;
public MyMenu(BoardConfigurable boardConfig) {
this.boardConfig = boardConfig;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == c1) {
boardConfig.setBoardGridColor(Color.RED);
} else if (e.getSource() == c2) {
boardConfig.setBoardGridColor(Color.GREEN);
} else if (e.getSource() == c3) {
boardConfig.setBoardGridColor(Color.BLUE);
}
}
}
We then need to update the Board (and Cell) to accept this change
public class Board extends Canvas {
private Cell[][] array;
private int rows;
private int cols;
private int size;
private Color gridColor = Color.BLACK;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
this.size = size;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(cols * size, rows * size);
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
repaint();
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g, getGridColor());
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
super.paint(g);
draw(g);
}
}
public class Cell {
private final int x;
private final int y;
private final int size;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void paint(Graphics g, Color gridColor) {
g.setColor(gridColor);
g.drawRect(x, y, size, size);
}
}
note: Cell is making use of dependency injection here, as it really doesn't need to store the color AGAIN. It's also possible that the size could be passed this way, but, it might be useful for determine if a user clicked this cell or not
Then GUI needs to implement BoardConfigurable...
public class GUI extends Container implements BoardConfigurable {
private Board board;
public GUI() {
setLayout(new BorderLayout());
board = new Board(3, 3, 50);
add(board);
}
#Override
public void setBoardGridColor(Color color) {
board.setGridColor(color);
}
}
And we can update build and run the UI...
GUI gui = new GUI();
MyMenu menu = new MyMenu(gui);
Frame frame = new Frame();
frame.add(gui);
frame.setMenuBar(menu);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
An important skill to build is always questioning, "does this really need access to everything I'm passing?", "what will happen if I want to change the underlying implementation? How much will I need to change to achieve it?"
These will help you drive your designs and help build more flexible and decoupled code.
You might also want to become fairmular with the model-view-controller concept
Runnable example...
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
GUI gui = new GUI();
MyMenu menu = new MyMenu(gui);
Frame frame = new Frame();
frame.add(gui);
frame.setMenuBar(menu);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public interface BoardConfigurable {
public void setBoardGridColor(Color color);
}
public class GUI extends Container implements BoardConfigurable {
private Board board;
public GUI() {
setLayout(new BorderLayout());
board = new Board(3, 3, 50);
add(board);
}
#Override
public void setBoardGridColor(Color color) {
board.setGridColor(color);
}
}
public class MyMenu
extends MenuBar
implements ActionListener {
Menu paperMenu;
MenuItem c1, c2, c3;
BoardConfigurable boardConfig;
Cell cell;
public MyMenu(BoardConfigurable boardConfig) {
this.boardConfig = boardConfig;
this.cell = cell;
paperMenu = new Menu("Grid");
c1 = new MenuItem("Red");
c2 = new MenuItem("Green");
c3 = new MenuItem("Random");
paperMenu.add(c1);
paperMenu.add(c2);
paperMenu.add(c3);
this.add(paperMenu);
c1.addActionListener(this);
c2.addActionListener(this);
c3.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
if (e.getSource() == c1) {
boardConfig.setBoardGridColor(Color.RED);
} else if (e.getSource() == c2) {
boardConfig.setBoardGridColor(Color.GREEN);
} else if (e.getSource() == c3) {
boardConfig.setBoardGridColor(Color.BLUE);
}
}
}
public class Board extends Canvas {
private Cell[][] array;
private int rows;
private int cols;
private int size;
private Color gridColor = Color.BLACK;
public Board(int rows, int cols, int size) {
this.rows = rows;
this.cols = cols;
this.size = size;
array = new Cell[rows][cols];
for (int r = 0; r < rows; r++) {
int y = r * size;
for (int c = 0; c < cols; c++) {
int x = c * size;
array[r][c] = new Cell(x, y, size);
}
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(cols * size, rows * size);
}
public Color getGridColor() {
return gridColor;
}
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
repaint();
}
public void draw(Graphics g) {
for (Cell[] row : array) {
for (Cell cell : row) {
cell.paint(g, getGridColor());
}
}
}
public Cell getCell(int r, int c) {
return array[r][c];
}
public void paint(Graphics g) {
super.paint(g);
draw(g);
}
}
public class Cell {
private final int x;
private final int y;
private final int size;
public Cell(int x, int y, int size) {
this.x = x;
this.y = y;
this.size = size;
}
public void paint(Graphics g, Color gridColor) {
g.setColor(gridColor);
g.drawRect(x, y, size, size);
}
}
}

How do I change the rectangles to an image?

I just started learning Java (OOP) and I am trying to develop a simple game (like space invaders). I want to replace the guards (brown rectangles) to an image to make the game more aesthetically pleasing.
I am not sure how to do this as the guards are dependent on a lot of things. I tried using the loadImage() method and others but it did not work.
Relevant codes:
Guard.java
public class Guard {
private List<Square> squares;
public Guard(int x, int y) {
squares=new ArrayList<>();
for(int i=0; i<3; i++) {
for (int j = 0; j < 6; j++) {
squares.add(new Square(x + SQUARE_SIZE * j, y + SQUARE_SIZE * i));
}
}
}
public void collisionWith(MovingObject obj) {
for(Square square : squares) {
if(square.visible && square.intersects(obj.getBoundary())) {
square.setVisible(false);
obj.die();
}
}
}
public void draw(Graphics g) {
for(Square square : squares)
{
if(square.visible) square.draw(g);
}
}
}
Square.java
class Square extends Rectangle {
boolean visible;
Square(int x, int y)
{
super(x, y, SQUARE_SIZE, SQUARE_SIZE);
setVisible(true);
}
void setVisible(boolean visible) {
this.visible = visible;
}
void draw(Graphics g) {
g.setColor(new Color(228, 155, 30));
g.fillRect(x, y, width, height);
}
}
Screenshot for reference: Instead of brown boxes, I want to change it to other things using images
The following mre demonstrates using an image to represent a rectangle. Note that for easier implementation Gurd extends Componenet:
import java.awt.*;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
public class SwingMain {
SwingMain() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.add(new Guard(0,0));
frame.pack();
frame.setVisible(true);
}
class Guard extends Component{
private static final int GAP = 3, W = 6, H = 3;
private int squareSize, totalX, totalY;
private final List<Square> squares;
public Guard(int x, int y) {
squares=new ArrayList<>();
totalY = 0;
Square square = null;
for(int i=0; i< H; i++) {
totalX = 0;
for (int j = 0; j < W; j++) {
square = new Square(x + totalX , y + totalY );
squares.add(square);
totalX += square.getWidth() +GAP;
}
totalY += square.getHeight() +GAP;
}
}
#Override
public void paint(Graphics g) {
super.paint(g);
for(Square square : squares) {
square.draw(g);
}
}
#Override
public Dimension getPreferredSize(){
return new Dimension(totalX, totalY);
}
}
class Square{
private static final String BOX =
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Orange.png";
private Image image = null;
private final int x,y;
Square(int x, int y) {
this.x=x; this.y = y;
try {
image = new ImageIcon(new URL(BOX)).getImage();
} catch (IOException ex) {
ex.printStackTrace();
}
}
void draw(Graphics g) {
g.drawImage(image, x,y, null);
}
int getWidth(){
return image.getWidth(null);
}
int getHeight(){
return image.getHeight(null);
}
}
public static void main(String[] args) {
new SwingMain();
}
}
Square is not efficient because it reads and constructs image over again. To make it more efficient you can introduce a static block to initialize image only once:
static class Square{
private static final String BOX =
"https://cdn3.iconfinder.com/data/icons/softwaredemo/PNG/128x128/Box_Orange.png";
private static Image image = null;
static{
try {
image = new ImageIcon(new URL(BOX)).getImage();
} catch (IOException ex) {
ex.printStackTrace();
}
}
private final int x,y;
Square(int x, int y) {
this.x=x; this.y = y;
}
void draw(Graphics g) {
g.drawImage(image, x,y, null);
}
int getWidth(){
return image.getWidth(null);
}
int getHeight(){
return image.getHeight(null);
}
}

How do I pass an object from another class into the paintComponent method?

My assignment is to create the game "FloodIt." You can play the game here if you need to understand it, but I don't think it's really necessary: http://unixpapa.com/floodit/
I have finished the actual game part of it, but now I need to make a graphical interface for it. I have three classes:
Board.java, which makes the board with random int values and contains several other methods to make the game work:
import java.awt.Color;
import java.util.Random;
/**The board class for the Flood-It game. This class implements a NxN board filled with numColors colors.
* The class implements several methods to allow the playing of the game.
*/
class Board {
//you will probably need to create some field variables
private int size;
private int numColors;
private int[][] board;
private int numOfMoves;
/**Constructs a new sizeXsize board filled where each element on the board is a random number between 0
* and numColors. Also initializes the number of moves to zero.
* #param size -- the size of the board
* #param numColors -- the number of possible entries on the board
*/
public Board(int size,int numColors) {
//TODO finish this constructor
this.size = size;
this.numColors = numColors;
numOfMoves = 0;
board = new int[size][size];
Random rand = new Random();
int randomNum = 0;
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
randomNum = rand.nextInt(this.numColors);
board[count][counter] = randomNum;
}
}
}
/**Updates the board to fill (from the top left corner) with a specified color.
* Filling stops when any other color is hit besides the one in the top left corner.
* Play the game at http://www.lemoda.net/javascript/flood-it/ or http://unixpapa.com/floodit/?sz=14&nc=4
* to get a better understanding of what this method should do.
* You will probably also want to take a look at the algorithm described
* at http://en.wikipedia.org/wiki/Flood_fill which describes what this method should do.
* I recommend the Stack-based recursive implementation. It is a recursive algorithm for
* flooding the board. It is one of the easier ones to implement.
* You are free to have this method call other methods. I would recommend creating a private method that
* this method calls and have that private method be the recursive method.
* A recursive method is one that calls itself.
* #param color -- the new color to flood the board with.
*/
public void move(int replacementColor) {
int targetColor = board[0][0];
recursiveMove(0,0,targetColor,replacementColor);
numOfMoves++;
}
private void recursiveMove(int xCoord, int yCoord, int targetColor, int replacementColor) {
if (targetColor == replacementColor) {
return;
}
if (board[xCoord][yCoord] != targetColor) {
return;
}
board[xCoord][yCoord] = replacementColor;
if (yCoord != size-1) {
recursiveMove(xCoord,yCoord+1,targetColor,replacementColor);
}
if (yCoord != 0) {
recursiveMove(xCoord,yCoord-1,targetColor,replacementColor);
}
if (xCoord != 0) {
recursiveMove(xCoord-1,yCoord,targetColor,replacementColor);
}
if (xCoord != size-1) {
recursiveMove(xCoord+1,yCoord,targetColor,replacementColor);
}
}
/**returns true if the board is not completely filled with a single color.
* Otherwise it returns false.
* #return true if board is all one color
*/
public boolean finished() {
//TODO finish this method
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
if (board[count][counter] != board[0][0]) {
return false;
}
}
}
return true;
}
/**returns how many times the move() method has been called.
* #return the number of times the move() method has been called.
*/
public int numMoves() {
//TODO finish this method
return numOfMoves;
}
/**Returns a string representation of the board. Use tabs between elements of the board.
* And have every row of the board be separated by a newline character.
* Example:
* "1\t0\t3\t\n2\t0\t2\t\n1\t0\t1\t\n"
* #return a String representation of the board
*/
public String toString() {
//TODO finish this method
String boardString = "";
for (int count = 0; count < board.length; count++) {
for (int counter = 0; counter < board.length; counter++) {
boardString += board[count][counter];
boardString += "\t";
}
boardString += "\n";
}
return boardString;
}
}
FloodIt.java, which contains the JFrame lines in order to load the graphical interface, as well as code to actually run the game (it's not entirely finished, as I got stuck):
import java.util.Scanner;
import javax.swing.JFrame;
/**This class is the main method for the Flood-It game as found on many web sites
* ( such as http://www.lemoda.net/javascript/flood-it/ or
http://unixpapa.com/floodit/?sz=14&nc=4 ).
* It prompts the user for the size of the board
* and the number of colors. The user is prompted for the next color until the board is flooded.
* After the game is over it prints how many turns the user took and then asks if they want to play again.
*/
class FloodIt {
private static final int FRAMESIZE = 1000;
public static void main(String args[]) {
JFrame frame = new JFrame();
frame.setSize(FRAMESIZE,FRAMESIZE);
frame.setTitle("Brennan's Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
GraphicalBoard component = new GraphicalBoard();
frame.add(component);
frame.setVisible(true);
String again="";
int size = 20;
int numColors = 7;
do {
Board board=new Board(size,numColors);
while(!board.finished()) {
//I will change the print statements below into graphical input boxes later
System.out.print("****************\n"+board+"\n****************\n");
System.out.print("What color do you choose? ");
int color=Integer.parseInt(scan.nextLine());
board.move(color);
}
System.out.println("Nice job, you finished in "+board.numMoves());
System.out.print("Would you like to play again (Y/N)? ");
again=scan.nextLine();
} while (again.equalsIgnoreCase("Y"));
scan.close();
}
}
And GraphicalBoard.java, which is supposed to take the values of the 2d array from Board.java and display the board in a graphical interface. Each number that could be in the 2d array corresponds with a color in the Colors array:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import javax.swing.JComponent;
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
public void paintComponent(Graphics g, int size, Board board) {
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board[count][counter];
colorOfSquare = colors[colorNum];
g2.setColor(Color.colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
}
Two problems:
In GraphicalBoard.java, on the line "colorNum = board[count][counter];", I am getting the error: "The type of expression must be an array type but it resolved to Board."
I seem to be having a problem bring over the already initialized board from the Board.java class into the GraphicalBoard.java class.
In GraphicalBoard.java, on the line "g2.setColor(Color.colorOfSquare);", I am getting the error: "colorOfSquare cannot be resolved or it not a field."
I know the problem, it is supposed to be something like "g2.setColor(Color.BLACK);", but I am going to have the user input the color, so it kind of needs to be a variable and I was hoping to have something cleaner than just an if statement for every color.
Any suggestions? Thanks!
Your Board class contains a member variable int[][] board, but its scope is private. When you call the following:
colorNum = board[count][counter];
This is wrong because the board variable here is an object of Board class. It itself is not the two day array, but it encapsulates int[][] board inside it. So you need to provide a getter method in Board to expose its board member variable like this:
public int[][] getBoard() {
return board;
}
Then in the paintComponent method you can access it as: board.getBoard()[count][counter].
You already seem to have a user inputted color in the colorOfSquare variable. But Graphics2D's setColor method would only accept a variable of type java.awt.Color. Since you have the String representation of the color, you can get its corresponding java.awt.Color value using reflection as mentioned here. The following should work for you:
Color color;
try {
Field field = Color.class.getField(colorOfSquare);
color = (Color) field.get(null);
} catch (Exception e) {
color = null; // Not defined
}
Two answers:
paintComponent ONLY receives a Graphics object. See this link for a short tutorial. If you need to access other objects in this method, make them variables of GraphicalBoard and pass them om during construction.
1.5 You need to access the Board's board, as this is what you are using. So add a getBoard(int i, int j) in class Board. Something like the following (I also added a getSize() method) :
public int getBoard(int i, int j) {
return board[i][j] ;
}
public int getSize() {
return size;
}
Your color colorOfSquare is already defined as a color. The error arises because the Color class doesn't have such a constant. You should just pass the color directly.
Try this:
public class GraphicalBoard extends JComponent {
private int xSize = 50;
private int ySize = 50;
private Board board;
private int size;
public GraphicalBoard() {
}
public void setBoard(Board board){
this.board = board;
}
public void paintComponent(Graphics g) {
super.paintComponent();
if(board == null) {
throw new RuntimeException("Board not set") ;
}
String colors[] = {"BLUE","GREEN","YELLOW","RED","BLACK","ORANGE","PINK"};
Graphics2D g2 = (Graphics2D) g;
int xCoord = 0;
int yCoord = 0;
int colorNum = 0;
int size = board.getSize() ;
String colorOfSquare = "";
for (int count = 0; count < size; count++) {
for (int counter = 0; counter < size; counter++) {
colorNum = board.getBoard(count, counter) ;
colorOfSquare = colors[colorNum];
g2.setColor(colorOfSquare);
Rectangle square = new Rectangle(xCoord,yCoord,xSize,ySize);
xCoord += 50;
}
yCoord += 50;
}
}
In very general terms,
your view, here the drawing JPanel, should contain a reference to the model object via a has-a or "composition" structure
The view should be notified of changes in the model, often via event listeners such as a PropertyChangeListener
The view then extracts the key information and uses that to help decide what to draw. So, if it has a reference to the current Board object, it can make getter method calls from within the paintComponent method.
Other issues in your code:
Make sure to call the super's paintComponent within your override, else you will not clean up "dirty" pixels
Don't mix linear code -- a Scanner based on System.in with GUI code. Make it all one or the other.
For example, in the code below, I use a model class, the class that holds the int[][] board variable and here called BoardModel, and I give it a SwingPropertyChangeSupport object.
class BoardModel {
// .....
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
This object will accept listeners, and will allow me to notify listeners of changes to the model.
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
Then when the model changes, I notify all listeners by calling the support object's firePropertyChange(...) method:
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board); // ***** here
setWin(checkForWin());
}
}
Then in the control, I can add listeners that notify the view of changes:
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
A working example could look like this:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.SwingPropertyChangeSupport;
public class BoardFun {
private static final int NUM_COLORS = 6;
private static final int SIZE = 20;
#SuppressWarnings("serial")
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
int size = SIZE;
int numColors = NUM_COLORS;
final BoardModel model = new BoardModel(size , numColors );
final BoardPanel view = new BoardPanel();
final ControlPanel controlPanel = new ControlPanel();
view.setModel(model);
view.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent mEvt) {
Point p = mEvt.getPoint();
int row = view.getRow(p);
int col = view.getColumn(p);
model.selectSquare(col, row);
}
});
model.addPropertyChangeListener(BoardModel.BOARD, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent e) {
view.repaint();
String moveCount = "" + model.getNumOfMoves();
controlPanel.setMoveCountFieldText(moveCount);
}
});
model.addPropertyChangeListener(BoardModel.WIN, new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if ((boolean) evt.getNewValue()) {
String message = "Move count: " + model.getNumOfMoves();
String title = "Game Over";
int messageType = JOptionPane.PLAIN_MESSAGE;
JOptionPane.showMessageDialog(view, message, title, messageType);
}
}
});
controlPanel.setResetAction(new AbstractAction("Reset") {
#Override
public void actionPerformed(ActionEvent e) {
model.reset();
}
});
JFrame frame = new JFrame("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(view);
frame.add(controlPanel, BorderLayout.PAGE_START);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
#SuppressWarnings("serial")
class ControlPanel extends JPanel {
private JTextField moveCountField = new JTextField("0", 10);
private JButton resetButton = new JButton();
public ControlPanel() {
add(new JLabel("Move Count:"));
add(moveCountField);
add(resetButton);
}
public void setResetAction(Action action) {
resetButton.setAction(action);
}
public void setMoveCountFieldText(String text) {
moveCountField.setText(text);
}
}
#SuppressWarnings("serial")
class BoardPanel extends JPanel {
private static final int PREF_W = 640;
private static final int PREF_H = PREF_W;
private BoardModel model;
private Color[] colors;
#Override
public Dimension getPreferredSize() {
if (isPreferredSizeSet()) {
return super.getPreferredSize();
} else {
return new Dimension(PREF_W, PREF_H);
}
}
public void setModel(BoardModel model) {
this.model = model;
colors = new Color[model.getNumColors()];
// create colors.length Colors, all of different hue
for (int i = 0; i < colors.length; i++) {
float hue = (float) i / colors.length;
colors[i] = Color.getHSBColor(hue, 1f, 1f);
}
}
// translate point to logical square position
int getRow(Point p) {
return (p.y * model.getBoard().length) / getHeight();
}
int getColumn(Point p) {
return (p.x * model.getBoard()[0].length) / getWidth();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g); // always call the super's method
if (model == null) {
return;
}
int board[][] = model.getBoard();
int height = getHeight() / board.length;
int width = getWidth() / board[0].length;
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
Color color = colors[board[i][j]];
g.setColor(color);
int x = (j * getWidth()) / board[0].length;
int y = (i * getHeight()) / board.length;
g.fillRect(x, y, width, height);
}
}
}
}
class BoardModel {
public static final String BOARD = "board";
public static final String WIN = "win";
private int[][] board;
private int numColors;
private Random random = new Random();
private SwingPropertyChangeSupport support = new SwingPropertyChangeSupport(this);
private int numOfMoves = 0;
private boolean win = false;
public BoardModel(int size, int numColors) {
board = new int[size][size];
this.numColors = numColors;
reset();
}
public void reset() {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[i].length; j++) {
board[i][j] = random.nextInt(numColors);
}
}
numOfMoves = 0;
support.firePropertyChange(BOARD, null, board);
setWin(false);
}
public int[][] getBoard() {
return board;
}
public int getNumOfMoves() {
return numOfMoves;
}
public int getNumColors() {
return numColors;
}
public void setWin(boolean win) {
boolean oldValue = this.win;
boolean newValue = win;
this.win = win;
support.firePropertyChange(WIN, oldValue, newValue);
}
public boolean isWin() {
return win;
}
public void selectSquare(int x, int y) {
int replacementValue = board[y][x];
int targetValue = board[0][0];
if (targetValue == replacementValue) {
return;
} else {
recursiveMove(0, 0, targetValue, replacementValue);
numOfMoves++;
support.firePropertyChange(BOARD, null, board);
setWin(checkForWin());
}
}
public boolean checkForWin() {
int value = board[0][0];
for (int[] row : board) {
for (int cell : row) {
if (cell != value) {
return false;
}
}
}
return true;
}
private void recursiveMove(int i, int j, int targetValue, int replacementValue) {
int currentValue = board[i][j];
if (currentValue != targetValue || currentValue == replacementValue) {
return;
}
board[i][j] = replacementValue;
int rowMin = Math.max(0, i - 1);
int rowMax = Math.min(board.length - 1, i + 1);
int colMin = Math.max(0, j - 1);
int colMax = Math.min(board[i].length - 1, j + 1);
for (int i2 = rowMin; i2 <= rowMax; i2++) {
if (i2 != i) {
recursiveMove(i2, j, targetValue, replacementValue);
}
}
for (int j2 = colMin; j2 <= colMax; j2++) {
if (j2 != j) {
recursiveMove(i, j2, targetValue, replacementValue);
}
}
}
public void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
support.addPropertyChangeListener(propertyName, listener);
}
}

Change color of rectangle in grid

I need help changing the color of a rectangle in a grid. So far, I have the rectangles and the grid (which are lines drawn separating the rectangles), and I want to change the color of a single rectangle when it's clicked.
I added the line "System.out.println("Something")" in the loop where the color is supposed to change, and it always returns "Something." That's why I'm confused. Thanks for any and all help!
Class Grid:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;
import javax.swing.Timer;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Grid extends JPanel{
private int a = 50;
private int b = 50;
private Lifeform[][] Life;
private boolean[][]life = new boolean[a][b];
private Timer t;
Grid(){
//creates grid of rectangles
Life = new Lifeform[a][b];
int ypos = 0;
for(int i = 0; i < Life.length; i++){
int xpos = 0;
for(int j = 0; j < Life[0].length; j++){
Rectangle r = new Lifeform();
r.setBounds(xpos, ypos, 50, 50);
Life[i][j] = (Lifeform) r;
xpos += 50;
}
ypos += 50;
}
t = new Timer(64, new Movement());
this.addMouseListener(new mouse());
}
public void paintComponent(Graphics g){
for(Lifeform[] n : Life){
//makes rectangles white
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
g.setColor(Color.white);
}
for (int i = 0; i <= 25; i++){
g.drawLine(0, 50*i, 1500, 50*i);
g.setColor(Color.black);
}
for (int i = 0; i <= 25; i++){
g.drawLine(50*i, 0, 50*i, 750);
g.setColor(Color.black);
}
}
private JFrame createGrid(){
JFrame frame = new JFrame("Alveolate");
frame.add(this);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(700,700);
frame.setVisible(true);
return frame;
}
public class mouse implements MouseListener{
//colors rectangles (it doesn't work)
public void mouseClicked(MouseEvent e) {
Point p = new Point(e.getX(),e.getY());
for(int i = 0; i < Life.length; i++){
for(int j = 0; j < Life[i].length; j++){
Lifeform spot = Life[i][j];
if (spot.contains(p)){
spot.setColor(Color.red);
System.out.println("Something");
}
}
}
}
public void mousePressed(MouseEvent e) {}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public class Movement implements ActionListener{
public void actionPerformed ( ActionEvent e ){
for (int i = 0; i < Life.length; i++){
for (int j = 0; j < Life[i].length; j++){
if(Life[i][j].getColor().equals(Color.black)){
life[i][j] = true;
}
else{
life[i][j] = false;
}
}
}
repaint();
}
}
public void startTimer(){
t.start();
}
public void stopTimer(){
t.stop();
}
public static void main(String[] args) {
Grid ABC = new Grid();
ABC.createGrid();
ABC.startTimer();
}
}
Class Lifeform:
import java.awt.Color;
import java.awt.Rectangle;
public class Lifeform extends Rectangle {
private Color c;
public Lifeform() {
c = Color.WHITE;
}
public Color getColor() {
return c;
}
public boolean setColor( Color c ) {
boolean rtn = false;
if( c != null ) {
this.c = c;
rtn = true;
}
return rtn;
}
}
try
for(Lifeform[] n : Life){
for(Lifeform lf : n){
g.setColor(lf.getColor());
g.fillRect((int)lf.getX(), (int)lf.getY(), (int)lf.getWidth(), (int)lf.getHeight());
}
}
in your paintComponent method
try this:
for(int i = 0; i < 50; i++){
for(int j = 0; j < 50; j++){
....
}
}
Didn't read all you code but it seems like you definitely set the color of your Lifeform to red. This means that your rendering code never actually uses this fact to display that Lifeform. It seems like the only time you draw your rectangles is in paintComponent. This paint needs to be called each time you want a redraw to happen. You can use repaint on your JFrame or JPanel to get this to happen. Also, the render code you have there seems to only ever display white rectangles
g.fillRect(this.getX(), this.getY(), this.getWidth(), this.getHeight());
g.setColor(Color.white);
This is in a loop through your Lifeform[][]. Instead you should probably have a double for loop to get every Lifeform and use the x and y and color from that to draw. Something like:
g.fillRect(Life[i][j].getX(), Life[i][j].getY(), ..., ..., Life[i][j].getColor())
Also, Life should be named life with a lowercase 'l'. It's way confusing seeing names without conventions.

Categories

Resources