Reputation: 143
I'm having a weird error with my board game. The board consists of a 2D array with GameTiles, which is a subclass of JPanel. It all works perfectly fine when I have the size (600,500) but whenever I change it I get a weird error in the upper left corner.
Picture of the error (see the upper left corner)
What makes it even weirder is that when I created a new project, just to try it out, it worked perfectly. The code is exactly the same for the painting and I'm not experiencing any error with it. Can it be something else that's causing this problem?
PROBLEM FIXED
Anser: I accidentally overrided the getX and getY methods of JPanel. I changed the name on them and now it works perfectly.
Reversi.java
package org.reversi;
import javax.swing.JFrame;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.reversi.gui.GameFrame;
public class Reversi {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
GameFrame frame = new GameFrame("Reversi");
frame.setSize(600,500);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
}
GameBoard.java
package org.reversi.gui;
import java.awt.Graphics;
import java.awt.GridLayout;
import javax.swing.JPanel;
public class GameBoard extends JPanel{
private GameTile[][] gameBoard = new GameTile[8][8];
public GameBoard() {
initiateLayout();
}
private void initiateLayout() {
setLayout(new GridLayout(8, 8));
for(int row = 0 ; row < 8 ; row++) {
for(int col = 0 ; col < 8 ; col++) {
gameBoard[row][col] = new GameTile(col,row);
add(gameBoard[row][col]);
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(int row = 0 ; row < 8 ; row++)
for(int col = 0 ; col < 8 ; col++)
gameBoard[row][col].repaint();
}
}
GameFrame.java
package org.reversi.gui;
import javax.swing.JFrame;
public class GameFrame extends JFrame {
private GameBoard gameBoard;
/**
* Creates a new frame.
* @param gameTitle the title of the frame
*/
public GameFrame(String gameTitle) {
setTitle(gameTitle);
gameBoard = new GameBoard();
add(gameBoard);
}
}
GameTile.java
package org.reversi.gui;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
public class GameTile extends JPanel {
private BufferedImage image;
private int x;
private int y;
public GameTile(int x, int y) {
this.x = x;
this.y = y;
try {
this.image = ImageIO.read(new File("tile.png"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Link to image (which should be named tile.png): https://i.sstatic.net/8JZmI.png
Upvotes: 1
Views: 315
Reputation: 36423
As per your comment:
This was the problem, thank you so much for pointing that out. I'm using the coordinates when making a move on the board. If there's some way to make this an answer it would be great
In GameTile.java
you have done:
public int getX() {
return x;
}
public int getY() {
return y;
}
With this you are actually overriding JPanel
s getX
and getY
and returning co-ordinates which will affect the Layout
. This can be seen by adding @Override
annotation (NOTE not compiler error is thrown thus we are correctly overriding a method from the extending class):
@Override
public int getX() {
return x;
}
@Override
public int getY() {
return y;
}
As @Xeon said you should not set the co-ordinates the LayoutManager
will do that.
Solution: (plus extras)
Remove those getters or rename them appropriately.
Dont call setSize
on JFrame
rather override getPreferredSize
of JPanel which is drawn to via
Graphics object and return the correct
Dimensions (in your case the image dimensions) and than call [
pack()][4] on
JFrame` before setting it visible but after adding components.
You will need to relocate call to setLocationRelativeTo(...)
to after pack()
.
Better to use JFrame.DISPOSE_ON_CLOSE
so main(String[] args)
method may carry on its execution even after GUI termination.
Also dont extend JFrame
unnecessarily.
Dont repeatedly load the same image in your GameTile
class rather load the image once and add parameter for GameTile
to accept an BufferedImage
( I figured this out while testing using the internet URL it took forever because it read a new image for each GameTile
created)
Here are the classes with necessary changes made:
Reversi.java:
public class Reversi {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
java.awt.EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
new GameFrame("Reversi");
}
});
}
}
GameBoard.java:
public class GameBoard extends JPanel {
private GameTile[][] gameBoard = new GameTile[8][8];
public GameBoard() {
initiateLayout();
}
private void initiateLayout() {
setLayout(new GridLayout(8, 8));
BufferedImage image = null;
try {
image = ImageIO.read(new URL("http://i.imgur.com/ejmCtui.png"));
} catch (IOException e) {
e.printStackTrace();
}
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
gameBoard[row][col] = new GameTile(image, col, row);
add(gameBoard[row][col]);
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; col++) {
gameBoard[row][col].repaint();
}
}
}
}
GameTile.java:
public class GameTile extends JPanel {
private BufferedImage image;
private int x;
private int y;
public GameTile(BufferedImage image, int x, int y) {
this.image = image;
this.x = x;
this.y = y;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(image.getWidth(), image.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
GameFrame.java:
public class GameFrame {
private GameBoard gameBoard;
/**
* Creates a new frame.
*
* @param gameTitle the title of the frame
*/
public GameFrame(String gameTitle) {
JFrame frame = new JFrame(gameTitle);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
gameBoard = new GameBoard();
frame.add(gameBoard);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
which would produce:
Upvotes: 4