so i have this program that asks a user for a number of rows and columns and then makes it into a checker board but my issue is that it only works with odd numbers like if the user was to put in 9 and 9 again it would display a checkered board but if a even number is inputted it just shows columns of white and black
import javax.swing.*;
import java.awt.*;
public class Checkers {
public static void main(String[] args) {
JFrame theGUI = new JFrame();
theGUI.setTitle("Checkers");
String inputStr = JOptionPane.showInputDialog("Number of rows");
if (inputStr == null) return;
int rows = Integer.parseInt(inputStr);
inputStr = JOptionPane.showInputDialog("Number of Columns");
if (inputStr == null) return;
int cols = Integer.parseInt(inputStr);
theGUI.setSize(cols * 50 , rows * 50);
theGUI.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = theGUI.getContentPane();
pane.setLayout(new GridLayout(rows, cols));
for (int i = 1; i <= rows * cols ;i ++) {
if(i % 2 == 0){
ColorPanel panel = new ColorPanel(Color.white);
pane.add(panel);
}else{
ColorPanel panel = new ColorPanel(Color.black);
pane.add(panel);
}
}
theGUI.setVisible(true);
}
}
Your example identifies even numbers in a single loop. Instead, use nested loops to identify alternating tiles:
g.setColor(Color.lightGray);
…
for (int row = 0; row < h; row++) {
for (int col = 0; col < w; col++) {
if ((row + col) % 2 == 0) {
g.fillRect(col * TILE, row * TILE, TILE, TILE);
}
}
}
A complete example is seen here.
Related
I am creating a TicTacToe game with 2 boards, only one is playable to the user. If a user clicks on cell[2][3] on grid 1 a token will be drawn on grid 1 and on cells[2][3] on grid 2. I was thinking of using a HashMap to assign indexes to each cell. Like cell[2][3] and cells[2][3] would each be assigned to index 9. How would I implement this is my code? Would I even use a Hashmap for what I am trying to do? I am unfamiliar with this concept so I might just be overthinking this.
Note: Cell[][] is the cells for grid 1 and Cells[][] are for grid 2. Cells[][] have randomized indexes in it so it can be randomly assigned to the board.
Edit: If I want to link cell(2)(3) and cells(2)(3) I would change integer to Cell when I initialize hashmap. Then I would do HMap. put(cell[2][3], cells[2][3]) right?
Code:
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
import javax.swing.border.LineBorder;
import java.util.Random;
import java.util.HashMap;
public class Bull extends JFrame{
private char currentPlayer = ' ';
// Creates array of cells called Cell[][] cell
private Cell[][] cell = new Cell[3][3];
// Creates array of cells called Sale[][] cells
private Cells[][] cells = new Cells[3][3];
// Creates a boolean array
private boolean t[][] = new boolean[3][3];
// Creates index array
private int z[] = new int[8];
//Initializes Random
Random rand = new Random();
// Initializes variables which will be used to create random ints
int f;
int g;
// Initializes JlblStatus
private JLabel jlblStatus = new JLabel(" ");
private JLabel jlblIndex = new JLabel(" ");
// Method that builds the JFrame and JPanels
public Bull(){
// Do I change Integer to array?
HashMap<Integer, Integer> HMap = new HashMap<Integer, Integer>();
// Title of the JFrame
JFrame frame = new JFrame("Shadow Tic Tac Toe Game");
// Makes the JFrame full screen
frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
// If x button is clicked than the JFrame closes
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// Initializes JPanel1
JPanel panel1 = new JPanel();
// Initializes JPanel2
JPanel panel2 = new JPanel();
// Adds panel1 which will hold the first TicTacToe game.
panel1.setLayout(new GridLayout(3,3,0,0));
for(int d = 0; d < 3; d++){
for(int c = 0; c < 3; c++){
panel1.add(cell[d][c] = new Cell());
// Sets size of the cells in JPanel1
cell[d][c].setPreferredSize(new Dimension(250,250));
}
}
panel2.setLayout(new GridLayout(3,3,0,0));
int n = 0;
while(n < 9){
f=rand.nextInt(3);
g=rand.nextInt(3);
while(t[f][g] == false){
t[f][g] = true;
panel2.add(cells[f][g] = new Cells());
cells[f][g].setPreferredSize(new Dimension(250,250));
System.out.println(f);
System.out.println("\t" + g);
n++;
}
}
// Adds Panel1 to the JFrame
frame.add(panel1, BorderLayout.WEST);
// Adds Panel2 to the JFrame
frame.add(panel2, BorderLayout.EAST);
// Updates the status of the game here (win/lose/draw/whose turn it is
frame.add(jlblStatus, BorderLayout.SOUTH);
// Sets size of the message area at the bottom of the frame
jlblStatus.setPreferredSize(new Dimension(100,100));
// Shows the Instructions of the game
Instructions();
// Calls method Chose() which allows the player to chose which token they will play as
Chose();
frame.pack();
// Sets it so the JFrame is visible to the user
frame.setVisible(true);
}
// Method that creates the Instructions for the game. Will be shown to the user prior to the user picking his token
public void Instructions(){
JOptionPane.showMessageDialog(null,"INSTRUCTIONS" + "\nThis game is called a 'Shadow Tic Tac Toe Game'. In this game there will be two Tic Tac Toe game boards, though only one is playable. \nBut you can win on either board. Lets say you place your token on the center tile at cell(2,3). \nAn X will be drawn on that spot on board 1 and on a randomized spot on the second game board at cell(2,3). \nYou will be able to see the cell indexes before you click on a cell so you can form a strategy");
}
// Method that lets the user chose his/her token
public void Chose(){
int f = 2;
// While f == 2 the loop will run
while(f == 2){
String input = JOptionPane.showInputDialog("CHOSE" + "\nPlease select your token. \nPress 1 for X and 2 for O.");
// Reads in the user input. Input put into a variable called pawn
int pawn = Integer.parseInt(input);
// If user input 1 his/her token will be X. F will equal 3 so the loop does not run again
if(input.equals("1")){
currentPlayer = 'X';
f = 3;
// If user input 2 his/her token will be O. F will equal 3 so the loop does not run again
}else if(input.equals("2")){
currentPlayer = 'O';
f = 3;
// If user does not enter in either a 1 or 2 an error message will appear. f wil equal 2 so the loop runs again and asks the user to chose his/her token again
}else{
JOptionPane.showMessageDialog(null,"ERROR INVALID RESPONSE");
f = 2;
}
}
}
public class Cells extends JPanel{
private char tok = ' ';
public Cells(){
// Sets the border for the cells to the color black
setBorder(new LineBorder(Color.black,1));
}
public void setTok(char d){
tok = d;
repaint();
}
public char getTok(){
return tok;
}
protected void Paint(Graphics g){
super.paint(g);
if(tok == 'X'){
g.drawLine(10,10,getWidth() - 10, getHeight()-10);
g.drawLine(getWidth()-10,10,10,getHeight()-10);
}else if (tok == 'O'){
g.drawOval(10,10,getWidth()-20, getHeight()-20);
}
}
}
public class Cell extends JPanel{
private char token = ' ';
public void setToken(char c){
token = c;
repaint();
}
public char getToken(){
return token;
}
public Cell(){
// Sets the border for the cells to the color black
setBorder(new LineBorder(Color.black, 1));
addMouseListener(new MyMouseListener());
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (token == 'X') {
g.drawLine(10,10, getWidth() - 10, getHeight() - 10);
g.drawLine(getWidth() - 10,10,10, getHeight() - 10);
}
else if (token == 'O') {
g.drawOval(10, 10, getWidth() - 20, getHeight() - 20);
}
}
private class MyMouseListener extends MouseAdapter{
public void mouseClicked(MouseEvent e){
// If cell is empty and game is not over
if (token == ' ' && currentPlayer != ' ') {
setToken(currentPlayer); // Set token in the cell
for(int d = 0; d < 3; d++){
for(int c = 0; c < 3; c++){
if(cell[d][c].getToken() == 'X'){
cells[d][c].setTok('X');
}else if(cell[d][c].getToken() == 'O'){
cells[d][c].setTok('O');
}else if(cell[d][c].getToken() == ' '){
cells[d][c].setTok(' ');
}
}
}
//setTok(currentPlayer);
if(Won(currentPlayer)){
jlblStatus.setText("The game is over! " + currentPlayer + " won the game! Congragulations " + currentPlayer + " !");
currentPlayer = ' ';
}else if(Full()){
jlblStatus.setText("The game is over, it ends in a draw!");
currentPlayer = ' ';
}else{
if(currentPlayer == 'X'){
currentPlayer = 'O';
}else{
currentPlayer = 'X';
}
jlblStatus.setText("It is " + currentPlayer + " 's turn");
}
}
}
}
}
public boolean Full(){
for(int d = 0; d < 3; d++)
for(int c = 0; c < 3; c++)
if(cell[d][c].getToken() == ' ')
return false;
return true;
}
public boolean Won(char token){
for(int d = 0; d < 3; d++){
if(cell[d][0].getToken() == token && cell[d][1].getToken() == token && cell[d][2].getToken() == token){
return true;
}
}
for(int c = 0; c < 3; c++){
if(cell[0][c].getToken() == token && cell[1][c].getToken() == token && cell[2][c].getToken() == token){
return true;
}
}
if(cell[0][0].getToken() == token && cell[1][1].getToken() == token && cell[2][2].getToken() == token){
return true;
}
if(cell[0][2].getToken() == token && cell[1][1].getToken() == token && cell[2][0].getToken() == token){
return true;
}
return false;
}
public static void main(String [] args){
new Bull();
}
}
So essentially you want to map a cell on one grid (that the player can play on) to some cell on another grid (the shadow grid)?
You could do this just using another 2D array that stores what indices a cell maps to in the other grid, but you would need to return a point object containing x and y coordinates. But that method is sorta annoying to keep track of and has its limitations.
If you want to do it with a HashMap<Point, Point> of one Point in one grid to a Point in another grid, then you would have to override hashCode() and equals() of Point and do something like this:
HashMap<Point, Point> mapPointToPoint = new HashMap<>();
// (0,0) maps to shadow grid (1,2)
mapPointToPoint.put(new Point(0,0), new Point(1,2));
mapPointToPoint.put(new Point(0,1), new Point(2,1));
// ... more mappings for all the cells
// to get
Point pointInPlayableGrid = new Point(0,0);
Point pointInShadowGrid = mapPointToPoint.get(pointInPlayableGrid);
// pointInShadowGrid == (1,2) since that's what it was mapped to
However, if you wanted to have multiple shadow grids then you'd need to have a map from points in the playable grid to the points in the shadow grids for each shadow grid.
So instead, since you already have the Cell class, why not just have each Cell store a List<Cell> of all the cells that it maps to. This is also very flexible because you could even have a single playable Cell map to multiple cells in a single shadow grid, and on hover of the playable Cell you could just go through the list of shadow Cells it maps to and highlight them too.
public class Cell extends JPanel{
private Cell shadowCell;
public void setCellThisMapsTo(Cell otherCell){ this.shadowCell = otherCell; }
public Cell getCellThisMapsTo(){ return shadowCell; }
// ... all the other stuff
}
// ... wherever you initialize the playable and shadow grid
// get a list of the shadow Cells, randomized order
Cell[][] shadowGrid; // however you init this
Cell[][] playableGrid; // however you init this
LinkedList<Cell> shadowCells = new LinkedList<>();
for(int x = 0; x < 3; x++){
for(int y = 0; y < 3; y++){
shadowCells.add(shadowGrid[x][y]);
}
}
Collections.shuffle(shadowCells);
for(int x = 0; x < 3; x++){
for(int y = 0; y < 3; y++){
Cell playableCell = playableGrid[x][y];
Cell shadowCell = shadowCells.removeFirst();
playableCell.setCellThisMapsTo(shadowCell );
}
}
// Now all the playable cells map to a random shadow cell
Cell playableCell = playableGrid[0][0];
Cell shadowCell = playableCell.getCellThisMapsTo();
The shadow Cells will not map to any other cells, so shadowCell.getCellThisMapsTo() would return null. But this method would makes it easy to map playable cells to shadow cells and keep track of them, without even using a HashMap nor having to keep track of Points mapping to Points.
Here is my definition for Point. If you want to put something in a hash map based on its values (rather than its object reference), then it is important to override hashCode() and equals():
class Point {
public final int x;
public final int y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
// !!! OVERRIDE hashCode() and equals() so you can use this properly in a HashMap !!!
#Override
public int hashCode() {
int hash = 7;
hash = 71 * hash + this.x;
hash = 71 * hash + this.y;
return hash;
}
#Override
public int equals(Object o) {
if (obj == null)
return false;
if (this == obj)
return true;
if (getClass() != o.getClass())
return false;
Point p = (Point) o;
return this.x == p.x && this.y == p.y;
}
}
Ok. So I'm supposed to build a GUI for my connect 4 program. (Please excuse the chunks of code here and there) I have shortened this program for your reading and I have excluded some code that doesn't have issues. I'm trying to get my JPanel down to the Connect4(). How can I access public TestPane() so I can update the GUI from Connect4().
I am not allowed to use anything Static.
LINE 153 WAS WHERE I WAS GOING TO ATTEMPT TO UPDATE THE GUI
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.Border;
import javax.swing.border.MatteBorder;
import java.awt.event.ActionEvent;
import javax.swing.*;
import java.awt.GridLayout;
public class Connect4 extends JPanel{
public boolean col1 = false;
public int buttonPressed = 10;
public class TestPane extends JPanel{
public TestPane() {
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int row = 0; row < 7; row++) {
for (int col = 0; col < 8; col++) {
//setBackground(Color.BLUE);
gbc.gridx = col;
gbc.gridy = row;
CellPane cellPane = new CellPane();
Border border = null;
if (row < 7) {
if (col < 8) {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
} else {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
}
} else {
if (col < 8) {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
} else {
border = new MatteBorder(1, 1, 1, 1, Color.BLACK);
}
}
cellPane.setBorder(border);
add(cellPane, gbc);
}
//JUST TO TEST THAT THE SQUARES ARE WORKING. THEY ARE BUT NOT WITH MY PROGRAM
gbc.gridx = 3;
gbc.gridy = 2;
CellPane cellPaneP1 = new CellPane();
cellPaneP1.setBackground(Color.BLUE);
add(cellPaneP1,gbc);
gbc.gridx = 5;
gbc.gridy = 4;
CellPane cellPaneP2 = new CellPane();
cellPaneP2.setBackground(Color.RED);
add(cellPaneP2,gbc);
}
}
}
public Connect4(){
JOptionPane.showMessageDialog(null, "Welcome to Connect Four\nThis game will require 2 players\nPlease Enter your names");
Player p1 = new Player();
Player p2 = new Player();
String p1Name = JOptionPane.showInputDialog("Enter your name Player 1");
p1.setName(p1Name);
String p2Name = JOptionPane.showInputDialog("Enter your name Player 2");
p2.setName(p2Name);
JOptionPane.showMessageDialog(null,p1.getName()+ " vs " + p2.getName()+". \nThis is going to be EPIC!!!");
System.out.println(p1.getName()+ " vs " + p2.getName()+". \nThis is going to be EPIC!!!");
int winner =0;
//Create Our board
Board con4Bor= new Board();
//con4Bor.setSize(7,8);]
//Fill our board with '_' to represent empty spaces
con4Bor.fillBoard();
//Randomly Select Player to go first
int i = 0;
int p1p2 = (int)(Math.random()*2+1);
if(p1p2 == 1)
System.out.println(p1.getName() + " was selected at random to go first");
else
System.out.println(p2.getName() + " was selected at random to go first");
JButton column1 = new JButton(new AbstractAction("Column 1"){
#Override
public void actionPerformed(ActionEvent a){
buttonPressed = 1;
}
});
while(winner == 0){
if(p1p2 == 3){
p1p2--;
}
con4Bor.printOutBoard();
//printDiag(c4b);
int playerSelection = 10;
//System.out.println(p1p2);
if(p1p2 == 1){
System.out.println(p1.getName()+": it is now your turn\nplease choose a column");
}
else{
System.out.println(p2.getName()+": it is now your turn\nplease choose a column");
}
System.out.println("Which Column do you want to insert? Column 1, 2, 3, 4, 5, 6, 7 or 8?");
playerSelection = 1;
while(playerSelection != 1 && buttonPressed != 2 && buttonPressed != 3 && buttonPressed != 4 && buttonPressed != 5 && buttonPressed != 6 && buttonPressed != 7 && buttonPressed != 8){
System.out.println(buttonPressed);
playerSelection = 1;//buttonPressed;
}
if(playerSelection == 1){
********************************************************************************
********************************************************************************
***This is where I was poorly attempting to update my GUI if someone selected column 1 ***
********************************************************************************
********************************************************************************
i = 0;
con4Bor.insertCol(i, playerSelection-1, p1p2);
}
//WINNER DETECTION
if(p1p2 == 1){
if(con4Bor.weHaveAHorizontalWinner() == true || con4Bor.weHaveAVeritcalWinner() == true || con4Bor.weHaveADiagonalWinner()==true){
con4Bor.printOutBoard();
System.out.println(p1.getName()+" Wins!!!");
winner++;
}else{
p1p2 =3;
}
}
if(p1p2 == 2){
if(con4Bor.weHaveAHorizontalWinner() == true || con4Bor.weHaveAVeritcalWinner() == true || con4Bor.weHaveADiagonalWinner()==true){
con4Bor.printOutBoard();
System.out.println(p2.getName()+" Wins!!!");
winner++;
}else{
p1p2--;
}
}
}
}
public class CellPane extends JPanel {
private Color defaultBackground;
public CellPane() {
defaultBackground = getBackground();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
}
public static void main (String [] args){
new tester();
}
}
Try repaint() + revalidate() on JPanel after you added/removed/changed any element on it. Also read about MVC and best practices when creating desktop JAVA app.
I have successfully got a checkerboard to be put together using colored panels, but only when the user will input odd numbers for the rows and columns. Otherwise when inputing even numbers it just shows alternating colored columns. I'm struggling to figure out how to write a short segment that checks to see if it's odd or even by using the %2=0, with the result of even changing the color. Below is my code. Thanks, and take it easy on me I'm very new to programming! :-)
Also, I've created a separate ColorPanel class to build the colored panel, and then pull into into my main program. I didn't bother putting that code below.
import javax.swing.*;
import java.awt.*;
public class Checkerboard extends JPanel{
public static void main(String[] args) {
JFrame chBoard = new JFrame();
chBoard.setTitle("Checkerboard");
chBoard.setSize(800,800);
chBoard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String inputStr = JOptionPane.showInputDialog("Number of rows", "5");
if (inputStr == null) return;
int row = Integer.parseInt(inputStr);
inputStr = JOptionPane.showInputDialog("Number of columns", "5");
if (inputStr == null) return;
int col = Integer.parseInt(inputStr);
Container pane = chBoard.getContentPane();
pane.setLayout(new GridLayout(row, col));
Color BoxColor = Color.red;
for ( int counter = 1; counter <= row * col; counter++ )
{
if (BoxColor == Color.red)
BoxColor = Color.black;
else
BoxColor = Color.red;
ColorPanel panel = new ColorPanel(BoxColor);
pane.add(panel);
}
chBoard.setVisible(true);
}
}
Change your loop to:
for ( int x = 0; x < row; x++ ) {
for(int y = 0; y < col; y++) {
if((x + y)%2 == 0) {
BoxColor = Color.red;
} else {
BoxColor = Color.black;
}
...
}
}
Like I said, I'm new to programming but I'm really enjoying the learning experience. I hope this helps other people in their learning experience.
Anyways, I suppose I created more work for myself with the separate ColorPanel class. So instead of creating a separate ColorPanel class to build the colored panel, I just changed it to use the preexisting JPanel class to create the panel inside the main program. So instead of:
ColorPanel panel = new ColorPanel(BoxColor);
+ the ColorPanel class...
I put:
JPanel panel = new JPanel();
panel.setBackground(BoxColor);
within the main program and deleted the additional ColorPanel class.
Sorry for the redundancy, just wanting to explain myself clearly.
Also, thanks to Jason he really helped me figure out the idea of using the two
int x & y
to count the
row & col
and then add them together which enabled me to use the
%2=0
to figure out whether I was on the odd or even panel.
Hope this helps someone! :-)
Final code looks like this:
import javax.swing.*;
import java.awt.*;
public class Checkerboard extends JPanel{
public static void main(String[] args) {
JFrame chBoard = new JFrame();
chBoard.setTitle("Checkerboard");
chBoard.setSize(800,800);
chBoard.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String inputStr = JOptionPane.showInputDialog("Number of rows", "5");
if (inputStr == null) return;
int row = Integer.parseInt(inputStr);
inputStr = JOptionPane.showInputDialog("Number of columns", "5");
if (inputStr == null) return;
int col = Integer.parseInt(inputStr);
Container pane = chBoard.getContentPane();
pane.setLayout(new GridLayout(row, col));
Color BoxColor = Color.red;
for ( int x = 0; x < row; x++ ) {
for(int y = 0; y < col; y++) {
if((x + y)%2 == 0) {
BoxColor = Color.red;}
else{
BoxColor = Color.black;}
JPanel panel = new JPanel();
panel.setBackground(BoxColor);
pane.add(panel);
}
chBoard.setVisible(true);
}
}
}
How would I create a 2d icon array and print it out in a JOptionPane box. so Far I have this, but when I print it out it shows a bunch of BlockEmpty.png
public class iconarray{
public static void main (String [] args)
{
Icon blockempty = new ImageIcon("BlockEmpty.png");
Icon Board [] [] = new Icon [8] [8];
String GameBoard = "";
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
Board[count2][count3] = blockempty;
}
}
for (int count2 = 2; count2 <= 7; count2++)
{
for (int count3 = 1; count3 <= 7; count3++)
{
GameBoard = GameBoard + Board[count2][count3];
}
GameBoard = GameBoard + "\n";
}
JOptionPane.showMessageDialog(null, "", "Connect 4", JOptionPane.PLAIN_MESSAGE, blockempty);
}
}
In order to display a Icon or Image, you first need some way to render it. Icons and Images don't have the means to render them selves (per se), but require another component that can render them.
Something else a lot of people forget, is JOptionPane is capable of display components.
For example:
Icon brick = new ImageIcon(BoardOption.class.getResource("/images.jpg"));
JPanel wall = new JPanel(new GridLayout(8, 8, 0, 0));
JLabel bricks[][] = new JLabel[8][8];
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
bricks[y][x] = new JLabel(brick);
wall.add(bricks[y][x]);
}
}
JOptionPane.showMessageDialog(null, wall, "Another brick in the wall", JOptionPane.PLAIN_MESSAGE, null);
Take a look at How to use icons for more details.
I'm fairly new to GUI programming with swing and am having what I'm sure is a noob problem.
I've created a JFrame with a JPanel inside of it. Then I'm trying to add a JLabel for each element in an array. The problem is that the elements are not appearing on the panel. I've checked to make sure that the array elements are registering using a println statement, so that's not the problem. I'm guessing that I'm missing a statement somewhere... please advise.
Here's my code:
public class MazeFrame extends javax.swing.JFrame {
Maze m;
/**
* Creates new form MazeFrame
*/
public MazeFrame(Maze m) {
this.m = m;
setSize(new Dimension(800, 600));
JPanel pan = new JPanel();
add(pan);
setVisible(true);
// pan.setBackground(Color.yellow);
pan.setLayout(new GridLayout(m.width, m.height));
for (int curr = 0; curr < m.height; curr++){
for (Cell c: m.maze[curr]){
JLabel lab = new JLabel();
switch (c.state){
case border:
lab.setBackground(Color.black);
System.out.println("addedborder");
break;
case wall:
lab.setBackground(Color.DARK_GRAY);
System.out.println("addedwall");
break;
case open:
lab.setBackground(Color.LIGHT_GRAY);
System.out.println("addedopen");
break;
case travelled:
lab.setBackground(Color.RED);
}
lab.setSize(new Dimension(50, 50));
lab.setVisible(true);
pan.add(lab);
// System.out.println("added");
}
}
pan.revalidate();
pan.repaint();
}
}
Here's the maze class:
package robots;
import java.util.Random;
public class Maze {
public Cell[][] maze;
final int width;
final int height;
public Maze(){
width = 20;
height = 20;
maze = new Cell[width][height];
for (int row = 0; row < height; row++){
for (int col = 0; col < width; col++){
maze[row][col] = new Cell(row, col);
}
}
// set borders
for (int curr = 0; curr < height; curr++) {
maze[0][curr].setState("border");
maze[curr][0].setState("border");
maze[height - 1][curr].setState("border");
maze[curr][width - 1].setState("border");
}
// initially mark all cells as walls
for (int row = 1; row < height - 1; row++) {
for (int col = 1; col < width - 1; col++) {
maze[row][col].setState("wall");
}
}
}
private boolean isValidTurn(int row, int col) {
if (row >= 0 && col < width && col > 0 &&
row < 20 && (!this.maze[row][col].getState().matches("open"))) {
return true;
}
return false;
}
public void makeRoute() {
Random r = new Random();
int row = 0;
int col = r.nextInt(width);
maze[row][col].setState("open");
row = row+1;
maze[row][col].setState("open");
// System.out.println(this);
while (row < (this.height - 1)) {
// Assuming the mouse moves in only 3 directions left right or down
// in the maze. 0 indicates left turn 1 indicates right turn and
// 2 indicates down movement in the maze.
int nextDir = r.nextInt(3);
switch (nextDir) {
case 0: // left turn
if (this.isValidTurn(row, (col - 1))) {
--col;
this.maze[row][col].setState("open");
}
break;
case 1: // right turn
if (this.isValidTurn(row, (col + 1))) {
++col;
this.maze[row][col].setState("open");
}
break;
case 2: // down movement
++row;
this.maze[row][col].setState("open");
break;
}
System.out.println("turn : " + nextDir);
// System.out.println(this);
}
System.out.println(this);
}
}
class Cell {
int row;
int col;
int above, below, toLeft, toRight;
enum state {border, wall, open, travelled};
state state;
public Cell(int row, int col){
this.row = row;
this.col = col;
above = row + 1;
below = row -1;
toLeft = col -1;
toRight = col +1;
}
#Override
public String toString(){
String out = new String();
if (state == state.border) {
out = "0";
}
if (state == state.wall) {
out = "#";
}
if (state == state.open) {
out = ".";
}
if (state == state.open) {
out = "-";
}
return out;
}
public void setState(String toSet){
switch (toSet){
case "border":
state = state.border;
break;
case "wall":
state = state.wall;
break;
case "open":
state = state.open;
break;
case "travelled":
state = state.travelled;
break;
}
}
public String getState() {
return state.toString();
}
}
But, as I said, I know that the maze class works fine, because it outputs to the console perfectly when I run it. Also, the println statements in the MazeFrame class show that each cell is registering with its respective state.
See comments in the code:
public class MazeFrame extends javax.swing.JFrame {
Maze m;
/**
* Creates new form MazeFrame
*/
public MazeFrame(Maze m) {
this.m = m;
// Don't manually set the size of a frame. Let the preferred size of you components determine the size.
// This is done by invoking pack() after all components have been added to the frame.
// setSize(new Dimension(800, 600));
JPanel pan = new JPanel();
add(pan);
// setVisible(true); // do after all components added.
// pan.setBackground(Color.yellow);
pan.setLayout(new GridLayout(m.width, m.height));
for (int curr = 0; curr < m.height; curr++){
for (Cell c: m.maze[curr]){
JLabel lab = new JLabel();
lab.setOpaque(true); // as suggested by MadProgrammer
switch (c.state){
case border:
lab.setBackground(Color.black);
System.out.println("addedborder");
break;
case wall:
lab.setBackground(Color.DARK_GRAY);
System.out.println("addedwall");
break;
case open:
lab.setBackground(Color.LIGHT_GRAY);
System.out.println("addedopen");
break;
case travelled:
lab.setBackground(Color.RED);
}
// Set the preferred size so layout managers can do there job
// lab.setSize(new Dimension(50, 50));
lab.setPreferredSize(new Dimension(50, 50));
// Not required. This is the default for all components except top level containers like JFrame, JDialog
// lab.setVisible(true);
pan.add(lab);
// System.out.println("added");
}
}
// No neeed to revalidate or repaint because the frame is not visible yet
// pan.revalidate();
// pan.repaint();
pack(); // let the layout manager determine the size of the frame
setVisible(); // show the frame
}
}
Note: Normally you don't even need to set the preferred size of a component because each component has a preferred size. But in this case you didn't add text or an Icon to the label so it won't have a preferred size.
I was able to get something to work (as to if it's correct is another matter)
Basically all I did (apart from moving setVisible to the end of the constructor) was make the lab opaque...
public TestMaze(Maze m) {
this.m = m;
setSize(new Dimension(800, 600));
JPanel pan = new JPanel();
add(pan);
pan.setLayout(new GridLayout(m.width, m.height));
for (int curr = 0; curr < m.height; curr++) {
for (Cell c : m.maze[curr]) {
JLabel lab = new JLabel();
lab.setOpaque(true); // <-- Add me...
switch (c.state) {
case border:
lab.setBackground(Color.black);
break;
case wall:
lab.setBackground(Color.DARK_GRAY);
break;
case open:
lab.setBackground(Color.LIGHT_GRAY);
break;
case travelled:
lab.setBackground(Color.RED);
}
lab.setSize(new Dimension(50, 50));
lab.setVisible(true);
pan.add(lab);
// System.out.println("added");
}
}
setVisible(true);
}
As i know you should call revalidate/repaint when you add components to any visible container, so you could move your setVisible & adding panel to frame to last statement:
// update panel
pan.revalidate();
pan.repaint();
// adding panel to frame
this.add(pan);
this.pack();
this.setVisible(true);
the other thing you don't need to call JLabel.setVisible(true) because its the default, also to change the background of JLabel you need to add (because its transparent by default):
lab.setOpaque(true);