Some background I am developing a game in java, I am using Netbeans to build it I currently have 3 java files
App.java
Board.java
Piece.java
Currently When it runs it shows the user a simple chess board with all the pieces in the right positions etc.
That is all done in Board.java
My Problem is the movement for the pieces is done in Piece.java currently I have the white pawn coded and the mouse events that control it but when i run the program the board appears along with the pieces but none of the pieces move not even the white pawn
and I am stumped to as why, I think maybe I have not linked them probably with the board or something along those lines or maybe there is something u with my mouseevents
Also I am not getting any errors in my code when it run
Here are the java files
App.java
package chessgame;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
public class App {
public static void main(String[] args) {
JFrame frame = new Board();
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE );
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
Board.java
package chessgame;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE;
public class Board extends JFrame {
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
int startX;
int startY;
int initialX;
int initialY;
JPanel panels;
JLabel pieces;
public Board() {
Dimension boardSize = new Dimension(600, 600);
// This is a Layered Pane for this application
layeredPane = new JLayeredPane();
getContentPane().add(layeredPane);
layeredPane.setPreferredSize(boardSize);
//Add a chess board to the Layered Pane
chessBoard = new JPanel();
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
chessBoard.setLayout(new GridLayout(8, 8));
chessBoard.setPreferredSize(boardSize);
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
for (int i = 0; i < 64; i++) {
JPanel square = new JPanel(new BorderLayout());
chessBoard.add(square);
int row = (i / 8) % 2;
if (row == 0) {
square.setBackground(i % 2 == 0 ? Color.white : Color.gray);
} else {
square.setBackground(i % 2 == 0 ? Color.gray : Color.white);
}
}
// Setting up the Initial Chess board.
//White Side
for (int i = 8; i < 16; i++) {
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhitePawn.png")));
panels = (JPanel) chessBoard.getComponent(i);
panels.add(pieces);
}
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteRook.png")));
panels = (JPanel) chessBoard.getComponent(0);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteKnight.png")));
panels = (JPanel) chessBoard.getComponent(1);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteKnight.png")));
panels = (JPanel) chessBoard.getComponent(6);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteBishup.png")));
panels = (JPanel) chessBoard.getComponent(2);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteBishup.png")));
panels = (JPanel) chessBoard.getComponent(5);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteKing.png")));
panels = (JPanel) chessBoard.getComponent(3);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteQueen.png")));
panels = (JPanel) chessBoard.getComponent(4);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteRook.png")));
panels = (JPanel) chessBoard.getComponent(7);
panels.add(pieces);
//Black Side
for (int i = 48; i < 56; i++) {
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackPawn.png")));
panels = (JPanel) chessBoard.getComponent(i);
panels.add(pieces);
}
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackRook.png")));
panels = (JPanel) chessBoard.getComponent(56);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackKnight.png")));
panels = (JPanel) chessBoard.getComponent(57);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackKnight.png")));
panels = (JPanel) chessBoard.getComponent(62);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackBishup.png")));
panels = (JPanel) chessBoard.getComponent(58);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackBishup.png")));
panels = (JPanel) chessBoard.getComponent(61);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackKing.png")));
panels = (JPanel) chessBoard.getComponent(59);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackQueen.png")));
panels = (JPanel) chessBoard.getComponent(60);
panels.add(pieces);
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/BlackRook.png")));
panels = (JPanel) chessBoard.getComponent(63);
panels.add(pieces);
}
}
Piece.java
package chessgame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Piece extends JLabel implements MouseListener, MouseMotionListener {
public Piece(ImageIcon icon) { super(icon); }
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
int startX;
int startY;
int initialX;
int initialY;
JPanel panels;
JLabel pieces;
/*
This method checks if there is a piece present on a particular square.
*/
private Boolean piecePresent(int x, int y) {
Component c = chessBoard.findComponentAt(x, y);
if (c instanceof JPanel) {
return false;
} else {
return true;
}
}
/*
This is a method to check if a piece is a Black piece.
*/
private Boolean checkWhiteOponent(int newX, int newY) {
Boolean oponent;
Component c1 = chessBoard.findComponentAt(newX, newY);
JLabel awaitingPiece = (JLabel) c1;
String tmp1 = awaitingPiece.getIcon().toString();
if (((tmp1.contains("Black")))) {
oponent = true;
} else {
oponent = false;
}
return oponent;
}
/*
This method is called when we press the Mouse. So we need to find out what piece we have
selected. We may also not have selected a piece!
*/
public void mousePressed(MouseEvent e) {
chessPiece = null;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JPanel) {
return;
}
Point parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
chessPiece = (JLabel) c;
initialX = e.getX();
initialY = e.getY();
startX = (e.getX() / 75);
startY = (e.getY() / 75);
chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
chessPiece.setSize(chessPiece.getWidth(), chessPiece.getHeight());
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
}
public void mouseDragged(MouseEvent me) {
if (chessPiece == null) {
return;
}
chessPiece.setLocation(me.getX() + xAdjustment, me.getY() + yAdjustment);
}
/*
This method is used when the Mouse is released...we need to make sure the move was valid before
putting the piece back on the board.
*/
public void mouseReleased(MouseEvent e) {
if (chessPiece == null) {
return;
}
chessPiece.setVisible(false);
Boolean success = false;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
String tmp = chessPiece.getIcon().toString();
String pieceName = tmp.substring(0, (tmp.length() - 4));
Boolean validMove = false;
if (pieceName.equals("WhitePawn")) {
if (startY == 1) {
if ((startX == (e.getX() / 75)) && ((((e.getY() / 75) - startY) == 1) || ((e.getY() / 75) - startY) == 2)) {
if ((((e.getY() / 75) - startY) == 2)) {
if ((!piecePresent(e.getX(), (e.getY()))) && (!piecePresent(e.getX(), (e.getY() + 75)))) {
validMove = true;
} else {
validMove = false;
}
} else {
if ((!piecePresent(e.getX(), (e.getY())))) {
validMove = true;
} else {
validMove = false;
}
}
} else {
validMove = false;
}
} else {
int newY = e.getY() / 75;
int newX = e.getX() / 75;
if ((startX - 1 >= 0) || (startX + 1 <= 7)) {
if ((piecePresent(e.getX(), (e.getY()))) && ((((newX == (startX + 1) && (startX + 1 <= 7))) || ((newX == (startX - 1)) && (startX - 1 >= 0))))) {
if (checkWhiteOponent(e.getX(), e.getY())) {
validMove = true;
if (startY == 6) {
success = true;
}
} else {
validMove = false;
}
} else {
if (!piecePresent(e.getX(), (e.getY()))) {
if ((startX == (e.getX() / 75)) && ((e.getY() / 75) - startY) == 1) {
if (startY == 6) {
success = true;
}
validMove = true;
} else {
validMove = false;
}
} else {
validMove = false;
}
}
} else {
validMove = false;
}
}
}
if (!validMove) {
int location = 0;
if (startY == 0) {
location = startX;
} else {
location = (startY * 8) + startX;
}
String pieceLocation = pieceName + ".png";
pieces = new JLabel(new ImageIcon(pieceLocation));
panels = (JPanel) chessBoard.getComponent(location);
panels.add(pieces);
} else {
if (success) {
int location = 56 + (e.getX() / 75);
if (c instanceof JLabel) {
Container parent = c.getParent();
parent.remove(0);
pieces = new JLabel(new ImageIcon("WhiteQueen.png"));
parent = (JPanel) chessBoard.getComponent(location);
parent.add(pieces);
} else {
Container parent = (Container) c;
pieces = new JLabel(new ImageIcon("WhiteQueen.png"));
parent = (JPanel) chessBoard.getComponent(location);
parent.add(pieces);
}
} else {
if (c instanceof JLabel) {
Container parent = c.getParent();
parent.remove(0);
parent.add(chessPiece);
} else {
Container parent = (Container) c;
parent.add(chessPiece);
}
chessPiece.setVisible(true);
}
}
}
public void mouseClicked(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
Also here is a screenshot of the layout in netbeans
Any help or tips for would welcomed
Here is the Source File in which everything is written in one giant file the pieces can be moved and the white pawn moves right, that is how I know the piece is coded right i just can see to link the events know that they are separate
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
/*
This class can be used as a starting point for creating your Chess game project. The only piece that
has been coded is a white pawn...a lot done, more to do!
*/
public class ChessProject extends JFrame implements MouseListener, MouseMotionListener {
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
int startX;
int startY;
int initialX;
int initialY;
JPanel panels;
JLabel pieces;
public ChessProject(){
Dimension boardSize = new Dimension(600, 600);
// Use a Layered Pane for this application
layeredPane = new JLayeredPane();
getContentPane().add(layeredPane);
layeredPane.setPreferredSize(boardSize);
layeredPane.addMouseListener(this);
layeredPane.addMouseMotionListener(this);
//Add a chess board to the Layered Pane
chessBoard = new JPanel();
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
chessBoard.setLayout( new GridLayout(8, 8) );
chessBoard.setPreferredSize( boardSize );
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
for (int i = 0; i < 64; i++) {
JPanel square = new JPanel( new BorderLayout() );
chessBoard.add( square );
int row = (i / 8) % 2;
if (row == 0)
square.setBackground( i % 2 == 0 ? Color.white : Color.gray );
else
square.setBackground( i % 2 == 0 ? Color.gray : Color.white );
}
// Setting up the Initial Chess board.
for(int i=8;i < 16; i++){
pieces = new JLabel( new ImageIcon("WhitePawn.png") );
panels = (JPanel)chessBoard.getComponent(i);
panels.add(pieces);
}
pieces = new JLabel( new ImageIcon("WhiteRook.png") );
panels = (JPanel)chessBoard.getComponent(0);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteKnight.png") );
panels = (JPanel)chessBoard.getComponent(1);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteKnight.png") );
panels = (JPanel)chessBoard.getComponent(6);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteBishup.png") );
panels = (JPanel)chessBoard.getComponent(2);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteBishup.png") );
panels = (JPanel)chessBoard.getComponent(5);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteKing.png") );
panels = (JPanel)chessBoard.getComponent(3);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteQueen.png") );
panels = (JPanel)chessBoard.getComponent(4);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("WhiteRook.png") );
panels = (JPanel)chessBoard.getComponent(7);
panels.add(pieces);
for(int i=48;i < 56; i++){
pieces = new JLabel( new ImageIcon("BlackPawn.png") );
panels = (JPanel)chessBoard.getComponent(i);
panels.add(pieces);
}
pieces = new JLabel( new ImageIcon("BlackRook.png") );
panels = (JPanel)chessBoard.getComponent(56);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackKnight.png") );
panels = (JPanel)chessBoard.getComponent(57);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackKnight.png") );
panels = (JPanel)chessBoard.getComponent(62);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackBishup.png") );
panels = (JPanel)chessBoard.getComponent(58);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackBishup.png") );
panels = (JPanel)chessBoard.getComponent(61);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackKing.png") );
panels = (JPanel)chessBoard.getComponent(59);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackQueen.png") );
panels = (JPanel)chessBoard.getComponent(60);
panels.add(pieces);
pieces = new JLabel( new ImageIcon("BlackRook.png") );
panels = (JPanel)chessBoard.getComponent(63);
panels.add(pieces);
}
/*
This method checks if there is a piece present on a particular square.
*/
private Boolean piecePresent(int x, int y){
Component c = chessBoard.findComponentAt(x, y);
if(c instanceof JPanel){
return false;
}
else{
return true;
}
}
/*
This is a method to check if a piece is a Black piece.
*/
private Boolean checkWhiteOponent(int newX, int newY){
Boolean oponent;
Component c1 = chessBoard.findComponentAt(newX, newY);
JLabel awaitingPiece = (JLabel)c1;
String tmp1 = awaitingPiece.getIcon().toString();
if(((tmp1.contains("Black")))){
oponent = true;
}
else{
oponent = false;
}
return oponent;
}
/*
This method is called when we press the Mouse. So we need to find out what piece we have
selected. We may also not have selected a piece!
*/
public void mousePressed(MouseEvent e){
chessPiece = null;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JPanel)
return;
Point parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
chessPiece = (JLabel)c;
initialX = e.getX();
initialY = e.getY();
startX = (e.getX()/75);
startY = (e.getY()/75);
chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
chessPiece.setSize(chessPiece.getWidth(), chessPiece.getHeight());
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
}
public void mouseDragged(MouseEvent me) {
if (chessPiece == null) return;
chessPiece.setLocation(me.getX() + xAdjustment, me.getY() + yAdjustment);
}
/*
This method is used when the Mouse is released...we need to make sure the move was valid before
putting the piece back on the board.
*/
public void mouseReleased(MouseEvent e) {
if(chessPiece == null) return;
chessPiece.setVisible(false);
Boolean success =false;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
String tmp = chessPiece.getIcon().toString();
String pieceName = tmp.substring(0, (tmp.length()-4));
Boolean validMove = false;
/*
The only piece that has been enabled to move is a White Pawn...but we should really have this is a separate
method somewhere...how would this work.
So a Pawn is able to move two squares forward one its first go but only one square after that.
The Pawn is the only piece that cannot move backwards in chess...so be careful when committing
a pawn forward. A Pawn is able to take any of the opponent’s pieces but they have to be one
square forward and one square over, i.e. in a diagonal direction from the Pawns original position.
If a Pawn makes it to the top of the other side, the Pawn can turn into any other piece, for
demonstration purposes the Pawn here turns into a Queen.
*/
if(pieceName.equals("WhitePawn")){
if(startY == 1)
{
if((startX == (e.getX()/75))&&((((e.getY()/75)-startY)==1)||((e.getY()/75)-startY)==2))
{
if((((e.getY()/75)-startY)==2)){
if((!piecePresent(e.getX(), (e.getY())))&&(!piecePresent(e.getX(), (e.getY()+75)))){
validMove = true;
}
else{
validMove = false;
}
}
else{
if((!piecePresent(e.getX(), (e.getY()))))
{
validMove = true;
}
else{
validMove = false;
}
}
}
else{
validMove = false;
}
}
else{
int newY = e.getY()/75;
int newX = e.getX()/75;
if((startX-1 >=0)||(startX +1 <=7))
{
if((piecePresent(e.getX(), (e.getY())))&&((((newX == (startX+1)&&(startX+1<=7)))||((newX == (startX-1))&&(startX-1 >=0)))))
{
if(checkWhiteOponent(e.getX(), e.getY())){
validMove = true;
if(startY == 6){
success = true;
}
}
else{
validMove = false;
}
}
else{
if(!piecePresent(e.getX(), (e.getY()))){
if((startX == (e.getX()/75))&&((e.getY()/75)-startY)==1){
if(startY == 6){
success = true;
}
validMove = true;
}
else{
validMove = false;
}
}
else{
validMove = false;
}
}
}
else{
validMove = false;
}
}
}
if(!validMove){
int location=0;
if(startY ==0){
location = startX;
}
else{
location = (startY*8)+startX;
}
String pieceLocation = pieceName+".png";
pieces = new JLabel( new ImageIcon(pieceLocation) );
panels = (JPanel)chessBoard.getComponent(location);
panels.add(pieces);
}
else{
if(success){
int location = 56 + (e.getX()/75);
if (c instanceof JLabel){
Container parent = c.getParent();
parent.remove(0);
pieces = new JLabel( new ImageIcon("WhiteQueen.png") );
parent = (JPanel)chessBoard.getComponent(location);
parent.add(pieces);
}
else{
Container parent = (Container)c;
pieces = new JLabel( new ImageIcon("WhiteQueen.png") );
parent = (JPanel)chessBoard.getComponent(location);
parent.add(pieces);
}
}
else{
if (c instanceof JLabel){
Container parent = c.getParent();
parent.remove(0);
parent.add( chessPiece );
}
else {
Container parent = (Container)c;
parent.add( chessPiece );
}
chessPiece.setVisible(true);
}
}
}
public void mouseClicked(MouseEvent e) {
}
public void mouseMoved(MouseEvent e) {
}
public void mouseEntered(MouseEvent e){
}
public void mouseExited(MouseEvent e) {
}
/*
Main method that gets the ball moving.
*/
public static void main(String[] args) {
JFrame frame = new ChessProject();
frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE );
frame.pack();
frame.setResizable(true);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
You never create an instance of Piece, not even once, so it has no means by which it could ever respond to any events, it's not even on the screen...
I "think" you want to do something more like...
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteRook.png")));
...Note, you'll need to update Piece to support been constructed with a ImageIcon
There's also a bunch of issues with Piece. You have a bunch instance fields...
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
//...
JPanel panels;
JLabel pieces;
Which aren't linked to anything (they are null) which is going to cause you no end of issues.
Instead of focusing all the management within the UI, consider trying to use more of a MVC model. The game logic, rules and state should be maintain within a model, which has NO UI logic at all. It basically allows you to take a piece and make a move, validating that process as it goes. It would then provide notifications back to the UI, via an observer pattern which would notify the UI that some state has changed...
Updated...
Update the constructor of Piece so it can take a reference to an Icon and pass it onto it's parent, this way, you can continue using the code you already have...
public Piece(Icon icon) {
super(icon);
}
Next, when you create a Piece, you need to install a MouseListener to it. In this case, I'd be tempted to make the board responsible for the management of the pieces, it knows the layout and where all the pieces are...
pieces = new Piece(new ImageIcon(getClass().getResource("/chessgame/PieceImages/WhiteRook.png")));
pieces.addMouseListener(this);
Related
I am working on developing a Chess game. I want to have the board Container utilize a GridLayout to display an 8x8 grid of JPanels. (This will make functions such as highlighting selected squares and valid moves much easier.) I would then like to add the pieces over this layer so that they may be dragged and dropped. I initially had the pieces showing by drawing them in the individual square JPanels, but figured that would be a problem when trying to drag-and-drop them later. I have since been trying to use a JLayeredPane as the main container, but have encountered several issues.
One is that once I've specified the GridLayout for the JLayeredPane, regardless of which Integer I use to specify the layer to add the JLabel or other kind of image to, the pieces get added to the grid, making their positions set and and distorting the whole board. I have read that using LayoutManagers can interfere with layer positioning on the JLayeredPane, so this isn't too surprising. (Although the Oracle demo program from the JLayeredPane tutorial seems to do this just fine: http://download.oracle.com/javase/tutorial/uiswing/examples/components/LayeredPaneDemo2Project/src/components/LayeredPaneDemo2.java)
However, I have also tried to put the grid of JPanels into its own JPanel, then add it to a low layer of the JLayeredPane, the idea being that I could add the drag & drop icons to separate, non-opaque JPanel on a higher layer of the JLayeredPane. When I do this however, after I simply have the grid JPanel inside the JLayeredPane (i.e. before the drag-and-drop layer is added), the grid will not display.
I also have tried overriding the paintComponent (and paint) methods of the JLayeredPane to draw the piece images, but they are hidden by the JPanels (I can see that they are indeed there by setting the JPanels to non-opaque) and as far as I can tell there is no option to set the layer of the graphics on the JLayeredPane. I have also tried using the glassPane of the frame to draw the pieces, but got undesired behavior there as well.
Any help explaining some of this behavior, or where I am going wrong, would be much appreciated!
Here is a simple example that shows how you might (randomly) drag and drop a "chess piece" from one square to another:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class ChessBoard extends JFrame implements MouseListener, MouseMotionListener
{
JLayeredPane layeredPane;
JPanel chessBoard;
JLabel chessPiece;
int xAdjustment;
int yAdjustment;
public ChessBoard()
{
Dimension boardSize = new Dimension(600, 600);
// Use a Layered Pane for this this application
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize( boardSize );
layeredPane.addMouseListener( this );
layeredPane.addMouseMotionListener( this );
getContentPane().add(layeredPane);
// Add a chess board to the Layered Pane
chessBoard = new JPanel();
chessBoard.setLayout( new GridLayout(8, 8) );
chessBoard.setPreferredSize( boardSize );
chessBoard.setBounds(0, 0, boardSize.width, boardSize.height);
layeredPane.add(chessBoard, JLayeredPane.DEFAULT_LAYER);
// Build the Chess Board squares
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 8; j++)
{
JPanel square = new JPanel( new BorderLayout() );
square.setBackground( (i + j) % 2 == 0 ? Color.red : Color.white );
chessBoard.add( square );
}
}
// Add a few pieces to the board
ImageIcon duke = new ImageIcon("dukewavered.gif"); // add an image here
JLabel piece = new JLabel( duke );
JPanel panel = (JPanel)chessBoard.getComponent( 0 );
panel.add( piece );
piece = new JLabel( duke );
panel = (JPanel)chessBoard.getComponent( 15 );
panel.add( piece );
}
/*
** Add the selected chess piece to the dragging layer so it can be moved
*/
public void mousePressed(MouseEvent e)
{
chessPiece = null;
Component c = chessBoard.findComponentAt(e.getX(), e.getY());
if (c instanceof JPanel) return;
Point parentLocation = c.getParent().getLocation();
xAdjustment = parentLocation.x - e.getX();
yAdjustment = parentLocation.y - e.getY();
chessPiece = (JLabel)c;
chessPiece.setLocation(e.getX() + xAdjustment, e.getY() + yAdjustment);
layeredPane.add(chessPiece, JLayeredPane.DRAG_LAYER);
layeredPane.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
/*
** Move the chess piece around
*/
public void mouseDragged(MouseEvent me)
{
if (chessPiece == null) return;
// The drag location should be within the bounds of the chess board
int x = me.getX() + xAdjustment;
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
x = Math.min(x, xMax);
x = Math.max(x, 0);
int y = me.getY() + yAdjustment;
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
y = Math.min(y, yMax);
y = Math.max(y, 0);
chessPiece.setLocation(x, y);
}
/*
** Drop the chess piece back onto the chess board
*/
public void mouseReleased(MouseEvent e)
{
layeredPane.setCursor(null);
if (chessPiece == null) return;
// Make sure the chess piece is no longer painted on the layered pane
chessPiece.setVisible(false);
layeredPane.remove(chessPiece);
chessPiece.setVisible(true);
// The drop location should be within the bounds of the chess board
int xMax = layeredPane.getWidth() - chessPiece.getWidth();
int x = Math.min(e.getX(), xMax);
x = Math.max(x, 0);
int yMax = layeredPane.getHeight() - chessPiece.getHeight();
int y = Math.min(e.getY(), yMax);
y = Math.max(y, 0);
Component c = chessBoard.findComponentAt(x, y);
if (c instanceof JLabel)
{
Container parent = c.getParent();
parent.remove(0);
parent.add( chessPiece );
parent.validate();
}
else
{
Container parent = (Container)c;
parent.add( chessPiece );
parent.validate();
}
}
public void mouseClicked(MouseEvent e) {}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public static void main(String[] args)
{
JFrame frame = new ChessBoard();
frame.setDefaultCloseOperation( DISPOSE_ON_CLOSE );
frame.setResizable( false );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I have the weirdest bug ever.
I have this puzzle game that moves puzzle pieces (which really are buttons with images attached to them).
Everything worked fine until I tried to change the text of some label (to indicate how many steps the player has done).
Everytime I call someControl.setText("text");, the puzzle pieces that moved are set back to the their first position. I have no idea why, but they just do.
Here's my window:
It consists of two panels, each uses a GridBagLayout.
The main frame uses a gridBagLayout as well, which consists of the two panels.
I know it's weird as hell, but I can't figure out what may cause this GUI bug. Any idea?
The pieces of code:
increaseSteps which is called everytime I click a puzzle button
void increaseSteps() {
_steps++;
_lblSteps.setText("Steps: " + _steps);
}
Creation of the puzzle panel (the left panel)
private JPanel puzzlePanel() {
JPanel panel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
for (int i = 0; i < _splitImage.getSize(); i++)
for (int j = 0; j < _splitImage.getSize(); j++) {
int valueAtPos = _board.getMatrix()[i][j];
if (valueAtPos == 0)
continue;
int imageRow = _board.getImageRowFromValue(valueAtPos);
int imageCol = _board.getImageColFromValue(valueAtPos);
ImageIcon imageIcon = new ImageIcon(_splitImage.getImages()[imageRow][imageCol]);
JButton btn = new JButton(imageIcon);
_tileButtons[i][j] = new TileButton(btn, i, j);
btn.setPreferredSize(new Dimension(_splitImage.getImages()[i][j].getWidth(null),
_splitImage.getImages()[i][j].getHeight(null)));
// add action listener
btn.addActionListener(this);
btn.addKeyListener(this);
gbc.gridx = j;
gbc.gridy = i;
panel.add(_tileButtons[i][j].getButton(), gbc);
}
return panel;
}
actionPerformed:
#Override
public void actionPerformed(ActionEvent e) {
if (!(e.getSource() instanceof JButton))
return;
JButton btn = (JButton) e.getSource();
TileButton tile = getTileButtonFromBtn(btn);
if (tile == null)
return;
// check if we can move the tile
String moveDir = _board.canMoveTile(tile.getRow(), tile.getCol());
if (moveDir.equals("no"))
return;
increaseSteps();
int dirx = 0;
int diry = 0;
if (moveDir.equals("left")) {
dirx = -1;
_board.move("left", true);
tile.setCol(tile.getCol() - 1);
} else if (moveDir.equals("right")) {
dirx = 1;
_board.move("right", true);
tile.setCol(tile.getCol() + 1);
} else if (moveDir.equals("up")) {
diry = -1;
_board.move("up", true);
tile.setRow(tile.getRow() - 1);
} else { // down
diry = 1;
_board.move("down", true);
tile.setRow(tile.getRow() + 1);
}
moveButton(btn, dirx, diry, MOVE_SPEED);
if (_board.hasWon())
win();
}
moveButton: (moves the button in a seperate thread, calling btn.setLocation())
private void moveButton(JButton btn, int dirx, int diry, int speed) {
Point loc = btn.getLocation();
// get start ticks, calculate distance etc...
StopWatch stopper = new StopWatch();
int distance;
if (dirx != 0)
distance = _splitImage.getImages()[0][0].getWidth(null) * dirx;
else
distance = _splitImage.getImages()[0][0].getHeight(null) * diry;
if (speed > 0) {
// run the animation in a new thread
Thread thread = new Thread() {
public void run() {
int currentTicks;
int elapsed;
do {
int newX = loc.x;
int newY = loc.y;
elapsed = stopper.getElapsed();
int moved = (int) ((double) distance * (double) (elapsed / (double) speed));
if (dirx != 0)
newX += moved;
else
newY += moved;
btn.setLocation(newX, newY);
} while (elapsed <= MOVE_SPEED);
// make sure the last location is exact
btn.setLocation(loc.x + (dirx == 0 ? 0 : distance), loc.y + (diry == 0 ? 0 : distance));
}
};
thread.start();
}
else
btn.setLocation(loc.x + (dirx == 0 ? 0 : distance), loc.y + (diry == 0 ? 0 : distance));
}
You're trying to set the absolute position of a component via setLocation(...) or setBounds(...), one that is held by a container that uses a layout manager. This may work temporarily, but will fail if the container's layout manager is triggered to re-do the layout of its contained components. When that happens, the GridBagConstraints will take over and the components will move to their gridbag constraints assigned location.
The solution is to not do this, and instead to place the location of your components in concert with the layout managers used.
Another problem is that your current code is not Swing thread-safe since you're making Swing state changes from within a background thread. This won't always cause problems, but since it's a threading issue, risks causing intermittent hard to debug problems (ones that usually only occur when your boss or instructor are trying to run your code).
Possible solutions:
For a grid of images, you could use a grid of JLabels (or JButtons if you must) held in a container that uses GridLayout. When you need to reposition components, remove all components held by that JPanel, and then re-add, using the order of addition to help you position the components.
Easiest though would be to use a grid of non-moving JLabels, give them MouseListeners, and instead of moving the JLabels, remove and add Icons to them, including a blank Icon.
If you need to do Swing animation, use a Swing Timer to drive the animation. This will allow your code to make repetitive calls with delay between the calls, and with these calls being made on the Swing event thread, the EDT (event dispatch thread).
Demo proof of concept example code that shows swapping icons, but without animation, and without test of solution yet:
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
#SuppressWarnings("serial")
public class ImageShuffle extends JPanel {
private static final int SIDES = 3;
public static final String IMG_PATH = "https://upload.wikimedia.org/wikipedia/commons/"
+ "thumb/5/5a/Hurricane_Kiko_Sep_3_1983_1915Z.jpg/"
+ "600px-Hurricane_Kiko_Sep_3_1983_1915Z.jpg";
private List<Icon> iconList = new ArrayList<>(); // shuffled icons
private List<Icon> solutionList = new ArrayList<>(); // in order
private List<JLabel> labelList = new ArrayList<>(); // holds JLabel grid
private Icon blankIcon;
public ImageShuffle(BufferedImage img) {
setLayout(new GridLayout(SIDES, SIDES, 1, 1));
fillIconList(img); // fill array list with icons and one blank one
Collections.shuffle(iconList);
MyMouseListener myMouse = new MyMouseListener();
for (Icon icon : iconList) {
JLabel label = new JLabel(icon);
label.addMouseListener(myMouse);
add(label);
labelList.add(label);
}
}
private class MyMouseListener extends MouseAdapter {
#Override
public void mousePressed(MouseEvent e) {
JLabel selectedLabel = (JLabel) e.getSource();
if (selectedLabel.getIcon() == blankIcon) {
return; // don't want to move the blank icon
}
// index variables to hold selected and blank JLabel's index location
int selectedIndex = -1;
int blankIndex = -1;
for (int i = 0; i < labelList.size(); i++) {
if (selectedLabel == labelList.get(i)) {
selectedIndex = i;
} else if (labelList.get(i).getIcon() == blankIcon) {
blankIndex = i;
}
}
// get row and column of selected JLabel
int row = selectedIndex / SIDES;
int col = selectedIndex % SIDES;
// get row and column of blank JLabel
int blankRow = blankIndex / SIDES;
int blankCol = blankIndex % SIDES;
if (isMoveValid(row, col, blankRow, blankCol)) {
Icon selectedIcon = selectedLabel.getIcon();
labelList.get(selectedIndex).setIcon(blankIcon);
labelList.get(blankIndex).setIcon(selectedIcon);
// test for win here by comparing icons held by labelList
// with the solutionList
}
}
private boolean isMoveValid(int row, int col, int blankRow, int blankCol) {
// has to be on either same row or same column
if (row != blankRow && col != blankCol) {
return false;
}
// if same row
if (row == blankRow) {
// then columns must be off by 1 -- they're next to each other
return Math.abs(col - blankCol) == 1;
} else {
// or else rows off by 1 -- above or below each other
return Math.abs(row - blankRow) == 1;
}
}
public void shuffle() {
Collections.shuffle(iconList);
for (int i = 0; i < labelList.size(); i++) {
labelList.get(i).setIcon(iconList.get(i));
}
}
}
private void fillIconList(BufferedImage img) {
// get the width and height of each individual icon
// which is 1/3 the image width and height
int w = img.getWidth() / SIDES;
int h = img.getHeight() / SIDES;
for (int row = 0; row < SIDES; row++) {
int y = (row * img.getWidth()) / SIDES;
for (int col = 0; col < SIDES; col++) {
int x = (col * img.getHeight()) / SIDES;
// create a sub image
BufferedImage subImg = img.getSubimage(x, y, w, h);
// create icon from the image
Icon icon = new ImageIcon(subImg);
// add to both icon lists
iconList.add(icon);
solutionList.add(icon);
}
}
// create a blank image and corresponding icon as well.
BufferedImage blankImg = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
blankIcon = new ImageIcon(blankImg);
iconList.remove(iconList.size() - 1); // remove last icon from list
iconList.add(blankIcon); // and swap in the blank one
solutionList.remove(iconList.size() - 1); // same for the solution list
solutionList.add(blankIcon);
}
private static void createAndShowGui(BufferedImage img) {
JFrame frame = new JFrame("ImageShuffle");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ImageShuffle(img));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
URL imgUrl = null;
BufferedImage img;
try {
imgUrl = new URL(IMG_PATH);
img = ImageIO.read(imgUrl);
SwingUtilities.invokeLater(() -> createAndShowGui(img));
} catch (IOException e) {
e.printStackTrace();
}
}
}
If I wanted animation, again, I'd raise the icon into the JFrame's glasspane, animate it to the new position using a Swing Timer, and then place the icon into the new JLabel. I'd also disable the MouseListener using a boolean field, a "flag", until the animation had completed its move.
I am trying to create a DFS generated maze. I started by making a Cell object that has 4 lines (Top, Right, Bottom and Left). I then drew these lines on to a Maze JPanel. My problem is that most of the cells look fine but the left and top side of the JPanel have thick lines and I can't figure out how to make it just a regular grid.
Here is my Cell where I create the lines:
boolean[] walls = {true, true, true, true};
// Draw the lines of one cell with w width and h height
void drawCell(Graphics g, int w, int h){
// Set the color of the lines to white
g.setColor(Color.WHITE);
// If the top wall exists draw a top line
if (walls[0]) {
g.drawLine(TopLeftX(), TopLeftY(), TopRightX(w), TopRightY());
}
// If a right wall exists draw a right line
if (walls[1]) {
g.drawLine(TopRightX(w), TopRightY(), BotRightX(w), BotRightY(h));
}
// If a bottom wall exists draw a bottom line
if (walls[2]) {
g.drawLine(BotRightX(w), BotRightY(h), BotLeftX(), BotLeftY(h));
}
// If a left wall exists draw a left line
if (walls[3]) {
g.drawLine(BotLeftX(), BotLeftY(h), TopLeftX(), TopLeftY());
}
}
// Set each coordinate for the lines, these will make a square that
// is w wide and h high
private int TopLeftX() { return i; }
private int TopLeftY() { return j; }
private int TopRightX(int w){ return i * w; }
private int TopRightY() { return j; }
private int BotRightX(int w){ return i * w; }
private int BotRightY(int h){ return j * h; }
private int BotLeftX() { return i; }
private int BotLeftY(int h) { return j * h; }
w is the width of a cell and h is the height.
And here is my MazeView JPanel where I draw the lines:
class MazeView extends JPanel{
private Cell grid[][];
private Cell cell;
private int row;
private int col;
private int width = 600;
private int height = 580;
// Create a maze view JPanel that is rows tall and cols wide
MazeView(int rows, int cols){
super.setBackground(Color.BLACK);
super.setLayout(new GridLayout(rows, cols));
newGrid(rows, cols);
}
// Paint all the cells
public void paintComponent(Graphics g){
super.paintComponent(g);
// Get the height and width of each cell
int h = height / getRows();
int w = width / getCols();
// Loop to draw each cell
for (int i = 0; i <= getRows(); i++){
for (int j = 0; j <= getCols(); j++){
grid[i][j].drawCell(g, w, h);
}
}
}
}
I appreciate any help I can get.
When this is run my grid looks like this:
Have a look at g.drawLine(TopLeftX(), TopLeftY(), TopRightX(w), TopRightY()); - resolving the values of those methods you get coordinates i, j, i*w, j. Assuming that i and j are the cell positions you'll draw a line
for cell 0/0 from 0/0 to 0/0
for cell 1/0 from 1/0 to w/0
for cell 0/1 from 0/1 to 0/1
for cell 2/2 from 2/2 to 2*w/2
etc.
Thus you'll want to correct your coordinate calculation for all 4 draw commands.
Assuming i andj are the cell's grid coordinates and w and h are the dimensions of the cell the coordinates for the top left corner would then be i * w and j * h and for the bottom right corner (i + 1) * w and (j + 1) * h.
Example:
0 3 6 9
--------------> x
0 | +---+---+---+
| |0/0|1/0|2/0|
3 | +---+---+---+
| |0/1|1/1|2/1|
6 | +---o---+---+
| |0/2|1/2|2/2|
9 | +---+---O---+
V
y
Let's assume each cell has a width and hight of 3 pixels. Thus the coordinates for the bottom center cell are:
top left (o): x = i * w = 1 * 3 = 3 and y = j * h = 2 * 3 = 6
bottom right (O): x = (i + 1) * w = (1 + 1) * 3 = 6 and y = (j + 1) * h = (2 + 1) * 3 = 9.
Well it isn't a maze yet. Im starting by drawing each cell
Don't fully grasp what you are attempting, but I would think a cell needs to be different colors, not lines. So for example a white cell is a place a player can move to. A black cell is a wall. I'm not sure how drawing individual line will make a maze?
I am trying to create a DFS generated maze.
Don't know what that is, but here is some old code that might give you some ideas.
This is designed to be a maze and you paint icons (instead of colors as I suggested above) for each cell. In this basic implementation you only have two types of icons:
a floor
a wall
A file containing 0/1 is used to identify each cell and therefore the icon of the cell
You then have a playing piece that can move from floor to floor and is blocked when it hits a wall.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class SmallWorld extends JPanel implements KeyListener, ActionListener
{
//WORLD
String[][] worldArray = new String[30][30];
//Block colors
private static Color redBlock = new Color(255,0,0,255);
private static Color whiteBlock = new Color(255,255,255,255);
private static Color blackBlock = new Color(0,0,0,150);
//World images
// JLabel wall = new JLabel( new ImageIcon("wall.gif") );
// JLabel floor = new JLabel( new ImageIcon("floor.gif") );
ImageIcon wallIcon = new ImageIcon("dukewavered.gif");
ImageIcon floorIcon = new ImageIcon("copy16.gif");
//Starting coordinates
int blockPositionX = 1;
int blockPositionY = 1;
//Typing area to capture keyEvent
JTextField typingArea;
//Viewable area
JViewport viewable;
String type = "";
JLayeredPane layeredPane;
JPanel worldBack;
JPanel panel;
JPanel player;
Dimension worldSize = new Dimension(1500, 1500);
public SmallWorld() {
super( );
createWorld();
layeredPane = new JLayeredPane();
add(layeredPane);
layeredPane.setPreferredSize( worldSize );
worldBack = new JPanel();
layeredPane.add(worldBack, JLayeredPane.DEFAULT_LAYER);
worldBack.setLayout( new GridLayout(30, 30) );
worldBack.setPreferredSize( worldSize );
worldBack.setBounds(0, 0, worldSize.width, worldSize.height);
worldBack.setBackground( whiteBlock );
for (int i = 0; i < 30; i++) {
for (int j = 0; j < 30; j++) {
JPanel square = new JPanel( new BorderLayout() );
worldBack.add( square );
type = worldArray[i][j];
if ( type.equals("1") )
{
square.add( new JLabel(wallIcon) );
}
else
{
square.add( new JLabel(floorIcon) );
}
}
}
//Draw the player
player = new JPanel();
player.setBounds(50, 50, 50, 50);
player.setBackground( Color.black );
player.setLocation(50, 50);
layeredPane.add(player, JLayeredPane.DRAG_LAYER);
//set where the player starts
// panel = (JPanel)worldBack.getComponent( 31 );
// panel.add( player );
//Create the typing area with keyListener, add to window
typingArea = new JTextField(20);
typingArea.addKeyListener(this);
typingArea.setEditable( false );
add(typingArea);
}
//Get the world from the DAT file and translate it into
//a 2d array to be used by paintComponent
public void createWorld() {
String getData = null;
int countRow = 0;
try {
//Get file
FileReader fr = new FileReader("world.dat");
BufferedReader br = new BufferedReader(fr);
getData = new String();
//read each line from file, store to 2d array
while ((getData = br.readLine()) != null) {
if(countRow < 30) {
for (int i = 0; i < 30; i++) {
String temp = "" + getData.charAt(i);
worldArray[countRow][i] = temp;
}
countRow++;
}
}
} catch (IOException e) {
System.out.println("Uh oh, got an IOException error!");
e.printStackTrace();
}
}
//Move Block around the world
public void moveBlock() {
Point pt = new Point();
pt.x = blockPositionX * 50;
pt.y = blockPositionY * 50;
int x = Math.max(0, pt.x - 250);
int y = Math.max(0, pt.y - 250);
Rectangle r = new Rectangle(x, y, 550, 550);
scrollRectToVisible( r );
}
//check for collisions with blocks
public boolean checkCollision(int row, int col) {
if ( worldArray[col][row].equals("1") ) {
return true;
}
else {
return false;
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
updateView( e );
e.consume();
}
public void keyReleased(KeyEvent e) {
}
public void actionPerformed(ActionEvent e) {
}
//Update the view of the window based on which button is pressed
protected void updateView( KeyEvent e ) {
//if UP
if ( e.getKeyCode() == 38 ) {
if ( checkCollision( blockPositionX, blockPositionY - 1 ) == false ) {
blockPositionY = blockPositionY - 1;
moveBlock();
player.setLocation(blockPositionX *50, blockPositionY*50);
}
}
//if DOWN
if ( e.getKeyCode() == 40 ) {
if ( checkCollision( blockPositionX, blockPositionY + 1 ) == false ) {
blockPositionY = blockPositionY + 1;
moveBlock();
player.setLocation(blockPositionX *50, blockPositionY*50);
}
}
//if LEFT
if ( e.getKeyCode() == 37 ) {
if ( checkCollision( blockPositionX - 1, blockPositionY ) == false ) {
blockPositionX = blockPositionX - 1;
moveBlock();
player.setLocation(blockPositionX *50, blockPositionY*50);
}
}
//if RIGHT
if ( e.getKeyCode() == 39 ) {
if ( checkCollision( blockPositionX + 1, blockPositionY ) == false ) {
blockPositionX = blockPositionX + 1;
moveBlock();
player.setLocation(blockPositionX *50, blockPositionY*50);
}
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("SmallWorld");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new SmallWorld();
newContentPane.setPreferredSize( new Dimension(1500, 1500) );
JScrollPane scrollPane = new JScrollPane( newContentPane );
scrollPane.setPreferredSize( new Dimension(568, 568) );
frame.getContentPane().add( scrollPane );
frame.pack();
frame.setLocationRelativeTo( null );
frame.setResizable( false );
//frame.setSize(500,520);
frame.setVisible( true );
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
You will need a couple of small icons to represent the floor/wall.
You will also need a file to represent the maze. Here is an example "world.dat" file:
111111111111111111111111111111
100010001010001000101000100011
100010001010001000101000100011
100011101010000000001000000001
100010000010000000001000000001
100110000010000000001000000001
100000000010000000001000000001
111100011110000000001000000001
100000000110001110111000111011
100000000000001110111000111011
100000000000000000000000000001
100010001110000000000000000001
100010001110001110111000111011
100011101100000000000000000011
100010000110001110111000111011
100110000100000000000000000011
100000000110000000001000000001
111100011100000000000000000011
100000000100000000000000000011
100000000010000000000000000001
100000000010000000000000000001
100010000000000000000000000001
100010000000001110111000111011
100011101110000000011000000001
100010000110000000011000000001
100110000110000000001000000001
100000000110001110111000111011
111100011110000000011000000001
100000000110000000011000000001
111111111111111111111111111111
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);
}
}
}
I'm begining a little project to create a simple checkers game. However it's been a long time since I've used the java GUI tools. The goal of the code at this point is to draw the initial board (red pieces at top, black at bottom). However all I get when I run the code is a blank frame. I'm also a little uncertain if my circle drawing code will do what I want (ie create solid red or black circles inside certain squares) Here is the code. Thanks in advance for any help/suggestions
EDIT: I should probably alternate drawing blue and gray squares or else the thing will probably just be a giant blue blob, however I'll settle for a giant blue blob at this point :p
import javax.swing.*;
import java.awt.*;
public class CheckersServer
{
public static class Board
{
private JFrame frame = new JFrame();
private JPanel backBoard = new JPanel();
Board()
{
frame.setSize(905,905);
backBoard.setSize(900,900);
frame.setTitle("Checkers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
backBoard.setVisible(true);
boardSquare bs;
String type = null;
//Filling in Red Side
for (int i = 0; i <=1; i++)
{
for(int j = 0; j < 9; j++)
{
if(j % 2 == 0)
{
type = "Red";
}
else
{
type = "Blank";
}
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
//Filling in empty middle
type = "Blank";
for (int i = 2; i < 7; i++)
{
for(int j = 0; j < 9; j++)
{
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
//Filling in Black side
for (int i = 7; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
if(j % 2 != 0)
{
type = "Black";
}
else
{
type = "Blank";
}
bs = new boardSquare(100*j,100*i,type);
backBoard.add(bs);
}
}
backBoard.repaint();
frame.add(backBoard);
frame.repaint();
}
private class boardSquare extends JComponent
{
private int x; //x position of the rectangle measured from top left corner
private int y; //y position of the rectangle measured from top left corner
private boolean isBlack = false;
private boolean isRed = false;
public boardSquare(int p, int q, String type)
{
x = p;
y = q;
if (type.equals("Black"))
{
isBlack = true;
isRed = false;
}
else if (type.equals("Red"))
{
isRed = true;
isBlack = false;
}
else if (type.equals("Blank"))
{
isBlack = false;
isRed = false;
}
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(x,y,100,100);
g2.draw(box);
g2.setPaint(Color.BLUE);
g2.fill(box);
if(isBlack)
{
g2.fillOval(x, y,100 ,100 );
g2.setColor(Color.black);
g2.drawOval(x, y, 100, 100);
}
else if(isRed)
{
g2.fillOval(x, y,100 ,100 );
g2.setColor(Color.red);
g2.drawOval(x, y, 100, 100);
}
}
}
}
public static void main(String[] args)
{
Board game = new Board();
}
}
You have several issues.
Java UI is layout-based, which means that when you add a component to a parent, the parent's layout determines where the child component will be placed. You don't have any code to set up the layout, and so your application is using the defaults (FlowLayout is the default, and this may work in your case, as long as your JFrame and children are the appropriate size).
The bigger problems are in your boardSquare class. By default, JPanels have a dimension of 10x10. You aren't specifying the size, and so all your squares are 10x10. You need to tell the squares how big they are. You can do this in the boardSquare constructor:
setPreferredSize(new Dimension(100, 100));
Finally, in your drawing code, you are doing an offset of x,y when drawing the squares and circles. This is an offset from the top-left corner of the component. Your components (after setting the size) will be 100x100 pixels. But if your x,y are greater than these values, you will be drawing outside of the bounds of the component. Instead, these values should be set to 0,0 because that is the top-left corner of the component you are drawing in.
By just setting the preferred size of the squares and setting x,y to 0, I was able to get the squares drawing in the frame, though it wasn't pretty. You will need to work on setting the correct layout before it will be laid out correctly.
Here are some hints:
Your BoardSquares have dimension 0x0. Not a good size for something you want to be visible to the user.
To help visualize what's going on, cause each BoardSquare to be 100x100 pixels in size, and give them a border. Now you can see where they are showing up in your GUI. Your GUI code still needs significant changes, but this will at least let you start seeing what you're dealing with.
public BoardSquare(int p, int q, String type)
{
this.setBorder(new LineBorder(Color.CYAN, 2));
this.setPreferredSize(new Dimension(100, 100));
// ... etc ...
BoardSquare seems to be coded to draw its contents based on coordinates from the absolute topmost leftmost point in the window, but they should be coded to draw themselves from the topmost leftmost point of the BoardSquare itself. That is, components should only draw within their own boundaries, and they should use coordinates that assume 0,0 designates the top,left of the component, not of the window.
If you want to use BoardSquares (JComponents) and add them to the frame, you probably should use a different layout manager, like GridLayout. FlowLayout won't give you the kind of precise positioning you want.
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
public class CheckersServer2
{
public static String type_BLANK = "BLANK";
public static String type_RED = "RED";
public static String type_BLACK = "BLACK";
public static int width = 100;
public static int height = 100;
public static class Board
{
private JFrame frame = new JFrame();
private JPanel backBoard = new JPanel();
Board()
{
int numRows = 8;
int numCols = 8;
frame.setSize(905,905);
backBoard.setSize(900,900);
frame.setTitle("Checkers");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
backBoard.setVisible(true);
String type;
for(int r=0; r<numRows; r++){
for(int c=0; c<numCols; c++){
//
type = type_BLANK;
if(c%2==0){
if(r==0 || r==2) {
type = type_RED;
}else if(r==6){
type = type_BLACK;
}
}else{
if(r==1){
type = type_RED;
} else if(r==5 || r==7) {
type = type_BLACK;
}
}
backBoard.add(new BoardSquare(r,c,type));
}
}
backBoard.repaint();
frame.add(backBoard);
frame.repaint();
}
private class BoardSquare extends JComponent
{
/**
*
*/
private static final long serialVersionUID = 1L;
private int x; //x position of the rectangle measured from top left corner
private int y; //y position of the rectangle measured from top left corner
private boolean isBlack = false;
private boolean isRed = false;
public BoardSquare(int p, int q, String type)
{
//this.setBorder(new LineBorder(Color.CYAN, 2));
this.setPreferredSize(new Dimension(width, height));
x = p;
y = q;
if (type.equals(type_BLACK))
{
isBlack = true;
isRed = false;
}
else if (type.equals(type_RED))
{
isRed = true;
isBlack = false;
}
else if (type.equals(type_BLANK))
{
isBlack = false;
isRed = false;
}
}
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
Rectangle box = new Rectangle(x,y,width,height);
g2.draw(box);
g2.setPaint(Color.BLUE);
g2.fill(box);
int ovalWidth = width - 15;
int ovalHeight = ovalWidth;
if(isBlack)
{
g2.setColor(Color.black);
g2.fillOval(x, y, ovalWidth, ovalHeight);
g2.drawOval(x, y, ovalWidth, ovalHeight);
}
else if(isRed)
{
g2.setColor(Color.red);
g2.fillOval(x, y, ovalWidth, ovalHeight);
g2.drawOval(x, y, ovalWidth, ovalHeight);
}
}
}
}
public static void main(String[] args)
{
Board game = new Board();
}
}