1

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) Board error

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): http://i.imgur.com/ejmCtui.png

4

1 回答 1

3

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 JPanels 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 viaGraphics object and return the correctDimensions (in your case the image dimensions) and than call [pack()][4] onJFrame` 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:

enter image description here

于 2013-01-31T19:58:01.053 回答